django-fast-treenode 3.0.7__py3-none-any.whl → 3.0.8__py3-none-any.whl
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.
- {django_fast_treenode-3.0.7.dist-info → django_fast_treenode-3.0.8.dist-info}/METADATA +1 -1
- {django_fast_treenode-3.0.7.dist-info → django_fast_treenode-3.0.8.dist-info}/RECORD +18 -18
- treenode/admin/admin.py +104 -126
- treenode/managers/queries.py +1 -1
- treenode/managers/tasks.py +1 -1
- treenode/static/css/treenode_admin.css +21 -0
- treenode/static/js/treenode_admin.js +130 -339
- treenode/templates/treenode/admin/treenode_changelist.html +61 -15
- treenode/templates/treenode/admin/treenode_rows.html +37 -40
- treenode/templatetags/treenode_admin.py +57 -14
- treenode/version.py +2 -2
- treenode/views/autoapi.py +91 -91
- treenode/views/autocomplete.py +52 -52
- treenode/views/children.py +41 -41
- treenode/views/common.py +23 -23
- {django_fast_treenode-3.0.7.dist-info → django_fast_treenode-3.0.8.dist-info}/WHEEL +0 -0
- {django_fast_treenode-3.0.7.dist-info → django_fast_treenode-3.0.8.dist-info}/licenses/LICENSE +0 -0
- {django_fast_treenode-3.0.7.dist-info → django_fast_treenode-3.0.8.dist-info}/top_level.txt +0 -0
@@ -1,40 +1,23 @@
|
|
1
1
|
/**
|
2
2
|
* treenode_admin.js
|
3
3
|
*
|
4
|
-
*
|
5
|
-
*
|
6
|
-
*
|
4
|
+
* Cleaned version 3.1.0 — TreeNode Admin extension for Django Admin.
|
5
|
+
* - No AJAX loading of children
|
6
|
+
* - No persistence in localStorage
|
7
|
+
* - Local-only expand/collapse logic
|
8
|
+
* - Compatible with pre-rendered full tree
|
7
9
|
*
|
8
|
-
*
|
9
|
-
* - Drag-and-drop node movement with Shift for child placement
|
10
|
-
* - Visual animations for feedback (insert flash, drag highlight)
|
11
|
-
* - Inline AJAX expansion and collapse of subtrees
|
12
|
-
* - Server-side re-rendering and recovery after node movement
|
13
|
-
* - Lightweight localStorage persistence using compressed HTML
|
14
|
-
*
|
15
|
-
* Version: 3.0.0
|
10
|
+
* Version: 3.1.0
|
16
11
|
* Author: Timur Kady
|
17
12
|
* Email: timurkady@yandex.com
|
18
13
|
*/
|
19
14
|
|
20
|
-
|
21
15
|
(function($) {
|
22
16
|
|
23
17
|
// ------------------------------- //
|
24
|
-
//
|
18
|
+
// Helpers //
|
25
19
|
// ------------------------------- //
|
26
20
|
|
27
|
-
function debounce(func, wait) {
|
28
|
-
var timeout;
|
29
|
-
return function() {
|
30
|
-
var context = this, args = arguments;
|
31
|
-
clearTimeout(timeout);
|
32
|
-
timeout = setTimeout(function() {
|
33
|
-
func.apply(context, args);
|
34
|
-
}, wait);
|
35
|
-
};
|
36
|
-
}
|
37
|
-
|
38
21
|
function getCookie(name) {
|
39
22
|
let cookieValue = null;
|
40
23
|
if (document.cookie && document.cookie !== '') {
|
@@ -49,120 +32,9 @@
|
|
49
32
|
}
|
50
33
|
return cookieValue;
|
51
34
|
}
|
52
|
-
|
53
|
-
function showAdminMessage(text, level = "info", duration = 6000) {
|
54
|
-
const $ = django.jQuery || window.jQuery;
|
55
|
-
|
56
|
-
// Make sure the block exists
|
57
|
-
let msgList = $(".messagelist");
|
58
|
-
if (!msgList.length) {
|
59
|
-
msgList = $('<ul class="messagelist"></ul>');
|
60
|
-
$("#content").before(msgList);
|
61
|
-
}
|
62
|
-
|
63
|
-
// Create a message
|
64
|
-
const msg = $(`<li class="${level}">${text}</li>`);
|
65
|
-
|
66
|
-
msgList.append(msg);
|
67
|
-
|
68
|
-
// Auto disappear after 6 seconds (default)
|
69
|
-
setTimeout(() => {
|
70
|
-
msg.fadeOut(500, () => msg.remove());
|
71
|
-
}, duration);
|
72
|
-
}
|
73
|
-
|
74
|
-
function hangleAjaxSuccess(data) {
|
75
|
-
const msg = data.message || "The request was successfully completed.";
|
76
|
-
showAdminMessage(msg, "success");
|
77
|
-
ChangeList.saveTree()
|
78
|
-
ChangeList.restoreTree(ChangeList.expandedNodes);
|
79
|
-
}
|
80
|
-
|
81
|
-
function handleAjaxError(xhr, status, error) {
|
82
|
-
ChangeList.restoreTree(ChangeList.expandedNodes);
|
83
|
-
|
84
|
-
const fallbackMessage = "An unknown error occurred while executing the request.";
|
85
|
-
const $ = django.jQuery || window.jQuery;
|
86
|
-
let message = "";
|
87
|
-
|
88
|
-
// Try to extract the JSON error
|
89
|
-
try {
|
90
|
-
const contentType = xhr.getResponseHeader("Content-Type") || "";
|
91
|
-
if (contentType.includes("application/json")) {
|
92
|
-
const data = xhr.responseJSON || JSON.parse(xhr.responseText);
|
93
|
-
if (data?.error) {
|
94
|
-
message = data.error;
|
95
|
-
} else if (typeof data?.detail === "string") {
|
96
|
-
message = data.detail;
|
97
|
-
} else if (typeof data === "string") {
|
98
|
-
message = data;
|
99
|
-
}
|
100
|
-
}
|
101
|
-
} catch (e) {
|
102
|
-
// Not JSON – silently continue
|
103
|
-
}
|
104
|
-
|
105
|
-
// Try to parse plain HTML Django error and extract exception summary
|
106
|
-
if (!message && xhr.responseText) {
|
107
|
-
try {
|
108
|
-
// Try to extract main exception message from Django debug HTML
|
109
|
-
const match = xhr.responseText.match(/<pre class="exception_value">([^<]+)<\/pre>/);
|
110
|
-
if (match && match[1]) {
|
111
|
-
message = match[1].trim();
|
112
|
-
} else {
|
113
|
-
// As fallback, extract first lines of cleaned HTML
|
114
|
-
const plain = xhr.responseText.replace(/<\/?[^>]+(>|$)/g, "").trim();
|
115
|
-
const lines = plain.split("\n").map(line => line.trim()).filter(Boolean);
|
116
|
-
if (lines.length) {
|
117
|
-
message = lines.slice(0, 3).join(" — "); // keep it brief
|
118
|
-
}
|
119
|
-
}
|
120
|
-
} catch (e) {
|
121
|
-
// Parsing failed, do nothing
|
122
|
-
}
|
123
|
-
}
|
124
|
-
|
125
|
-
// If there is still nothing, build a generic fallback
|
126
|
-
if (!message) {
|
127
|
-
if (xhr.status) {
|
128
|
-
message = `${xhr.status}: ${error || status}`;
|
129
|
-
} else {
|
130
|
-
message = fallbackMessage;
|
131
|
-
}
|
132
|
-
}
|
133
|
-
|
134
|
-
showAdminMessage(message, "error");
|
135
|
-
}
|
136
|
-
|
137
|
-
function isDarkTheme() {
|
138
|
-
return document.documentElement.getAttribute("data-theme") === "dark";
|
139
|
-
}
|
140
|
-
|
141
|
-
function applyTheme() {
|
142
|
-
var dark = isDarkTheme();
|
143
|
-
var $container = $(".tree-widget");
|
144
|
-
var $dropdown = $(".tree-widget-dropdown");
|
145
|
-
|
146
|
-
if (dark) {
|
147
|
-
$dropdown.addClass("dark-theme");
|
148
|
-
$container.addClass("dark-theme");
|
149
|
-
} else {
|
150
|
-
$dropdown.removeClass("dark-theme");
|
151
|
-
$container.removeClass("dark-theme");
|
152
|
-
}
|
153
|
-
}
|
154
|
-
|
155
|
-
let ajaxCounter = 0;
|
156
|
-
|
157
|
-
function clearCursor() {
|
158
|
-
ajaxCounter--;
|
159
|
-
if (ajaxCounter === 0) {
|
160
|
-
$('body').css('cursor', 'default');
|
161
|
-
}
|
162
|
-
}
|
163
35
|
|
164
36
|
// ------------------------------- //
|
165
|
-
//
|
37
|
+
// AJAX Setup //
|
166
38
|
// ------------------------------- //
|
167
39
|
|
168
40
|
const csrftoken = getCookie('csrftoken');
|
@@ -172,18 +44,19 @@
|
|
172
44
|
if (!/^https?:.*/.test(settings.url)) {
|
173
45
|
xhr.setRequestHeader("X-CSRFToken", csrftoken);
|
174
46
|
}
|
175
|
-
ajaxCounter++;
|
176
47
|
$('body').css('cursor', 'wait');
|
177
48
|
},
|
49
|
+
complete: function() {
|
50
|
+
$('body').css('cursor', 'default');
|
51
|
+
},
|
178
52
|
cache: false
|
179
53
|
});
|
180
54
|
|
181
55
|
// ------------------------------- //
|
182
|
-
//
|
56
|
+
// Visual feedback //
|
183
57
|
// ------------------------------- //
|
184
58
|
|
185
59
|
const TreeFx = {
|
186
|
-
// Highlight the line where the element was moved
|
187
60
|
flashInsert(nodeId) {
|
188
61
|
const $row = $(`tr[data-node-id="${nodeId}"]`);
|
189
62
|
if (!$row.length) return;
|
@@ -192,235 +65,167 @@
|
|
192
65
|
setTimeout(() => $row.removeClass("flash-insert"), 1000);
|
193
66
|
},
|
194
67
|
|
195
|
-
// Fading in a new tbody (e.g. after reloadTree)
|
196
|
-
fadeInTbody(newHTML, callback) {
|
197
|
-
const $tbody = $('table#result_list tbody');
|
198
|
-
$tbody.stop(true, true).fadeOut(100, () => {
|
199
|
-
$tbody.html(newHTML).fadeIn(150, callback);
|
200
|
-
});
|
201
|
-
},
|
202
|
-
|
203
|
-
// Visual cue when drag starts and ends
|
204
68
|
markDragging($item, enable) {
|
205
69
|
$item.toggleClass('dragging', enable);
|
206
|
-
}
|
70
|
+
}
|
207
71
|
};
|
208
72
|
|
209
|
-
|
210
73
|
// ------------------------------- //
|
211
|
-
//
|
74
|
+
// Tree logic //
|
212
75
|
// ------------------------------- //
|
213
76
|
|
214
|
-
|
215
77
|
var ChangeList = {
|
216
78
|
$tableBody: null,
|
217
79
|
isShiftPressed: false,
|
218
80
|
activeTargetRow: null,
|
219
81
|
isMoving: false,
|
220
|
-
expandedNodes: [],
|
221
|
-
label: '',
|
222
82
|
|
223
83
|
init: function() {
|
224
84
|
this.$tableBody = $('table#result_list tbody');
|
225
85
|
this.bindEvents();
|
226
|
-
this.restoreTree();
|
227
86
|
this.enableDragAndDrop();
|
228
87
|
},
|
229
|
-
|
88
|
+
|
89
|
+
// Save expanded nodes to localStorage
|
230
90
|
saveTree: function() {
|
231
91
|
if (!this.$tableBody) return;
|
232
|
-
|
233
|
-
|
234
|
-
this.$tableBody.find(".treenode-toggle").
|
235
|
-
$btn = $(this)
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
localStorage.removeItem("saved_tbody");
|
92
|
+
|
93
|
+
// Сохраняем ТОЛЬКО те node_id, которые раскрыты
|
94
|
+
this.expandedNodes = this.$tableBody.find(".treenode-toggle").map(function() {
|
95
|
+
const $btn = $(this);
|
96
|
+
return $btn.data("expanded") ? $btn.data("node-id") : null;
|
97
|
+
}).get().filter(Boolean);
|
98
|
+
|
99
|
+
if (this.expandedNodes.length === 0) {
|
100
|
+
localStorage.removeItem("treenode_expanded");
|
242
101
|
} else {
|
243
|
-
localStorage.setItem("
|
102
|
+
localStorage.setItem("treenode_expanded", JSON.stringify(this.expandedNodes));
|
244
103
|
}
|
104
|
+
|
245
105
|
const count = $("#result_list tbody tr").length;
|
246
106
|
if (count > 0) {
|
247
107
|
$("p.paginator").first().text(`${count} ${ChangeList.label}`);
|
248
108
|
localStorage.setItem("label", ChangeList.label);
|
249
109
|
}
|
250
|
-
|
251
110
|
},
|
252
111
|
|
253
|
-
restoreTree: function(expandedList = null) {
|
254
|
-
const expanded = expandedList || JSON.parse(localStorage.getItem("saved_tbody") || "[]");
|
255
|
-
ChangeList.label = localStorage.getItem("label") || "";
|
256
|
-
if (!expanded.length) return;
|
257
112
|
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
dataType: 'json',
|
265
|
-
success: function(data) {
|
266
|
-
ChangeList.$tableBody.html(data.html);
|
267
|
-
ChangeList.expandedNodes = expanded;
|
268
|
-
|
269
|
-
ChangeList.$tableBody.find(".treenode-toggle").each(function () {
|
270
|
-
const $btn = $(this);
|
271
|
-
const nodeId = $btn.data('node-id');
|
272
|
-
if (ChangeList.expandedNodes.includes(nodeId)) {
|
273
|
-
$btn.data("expanded", true);
|
274
|
-
$btn.text("▼");
|
275
|
-
}
|
276
|
-
});
|
277
|
-
|
278
|
-
if (data.label) ChangeList.label = data.label;
|
279
|
-
const count = $("#result_list tbody tr").length;
|
280
|
-
$("p.paginator").first().text(`${count} ${ChangeList.label}`);
|
281
|
-
},
|
282
|
-
error: function(xhr, status, error) {
|
283
|
-
handleAjaxError(xhr, status, error);
|
284
|
-
// console.error("Restore error:", status, error);
|
285
|
-
},
|
286
|
-
complete: function() {
|
287
|
-
clearCursor();
|
288
|
-
}
|
289
|
-
});
|
113
|
+
// Restore expanded nodes from localStorage
|
114
|
+
restoreTreeState: function() {
|
115
|
+
const expanded = JSON.parse(localStorage.getItem("treenode_expanded") || "[]");
|
116
|
+
for (const nodeId of expanded) {
|
117
|
+
ChangeList.expandNode(nodeId);
|
118
|
+
}
|
290
119
|
},
|
291
|
-
|
292
|
-
searchRows: function(searchQuery) {
|
293
|
-
var params = { q: searchQuery };
|
294
120
|
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
ChangeList.$tableBody.html(data.html);
|
302
|
-
},
|
303
|
-
error: function(xhr, status, error) {
|
304
|
-
handleAjaxError(xhr, status, error);
|
305
|
-
// console.error("Search error:", status, error);
|
306
|
-
},
|
307
|
-
complete: function() {
|
308
|
-
clearCursor();
|
309
|
-
}
|
310
|
-
});
|
121
|
+
expandNode: function(nodeId) {
|
122
|
+
const $row = this.$tableBody.find(`tr[data-node-id="${nodeId}"]`);
|
123
|
+
const $btn = $row.find(".treenode-toggle");
|
124
|
+
$btn.text("▼").data("expanded", true);
|
125
|
+
this.showChildren(nodeId);
|
126
|
+
this.saveTree();
|
311
127
|
},
|
312
128
|
|
313
|
-
|
314
|
-
|
315
|
-
|
129
|
+
collapseNode: function(nodeId) {
|
130
|
+
const $row = this.$tableBody.find(`tr[data-node-id="${nodeId}"]`);
|
131
|
+
const $btn = $row.find(".treenode-toggle");
|
132
|
+
$btn.text("►").data("expanded", false); // <-- ВАЖНО!
|
133
|
+
this.hideChildrenRecursive(nodeId);
|
134
|
+
this.saveTree();
|
135
|
+
},
|
316
136
|
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
137
|
+
toggleNode: function($btn) {
|
138
|
+
const nodeId = $btn.data("node-id");
|
139
|
+
const isExpanded = $btn.data("expanded");
|
140
|
+
if (isExpanded) {
|
141
|
+
this.collapseNode(nodeId);
|
142
|
+
} else {
|
143
|
+
this.expandNode(nodeId);
|
144
|
+
}
|
145
|
+
},
|
146
|
+
|
147
|
+
showChildren: function(parentId) {
|
148
|
+
const $children = this.$tableBody.find(`tr[data-parent-id="${parentId}"]`);
|
149
|
+
$children.removeClass("treenode-hidden");
|
150
|
+
|
151
|
+
$children.each((_, child) => {
|
152
|
+
const $child = $(child);
|
153
|
+
const childId = $child.data("node-id");
|
154
|
+
const $toggle = $child.find(".treenode-toggle");
|
155
|
+
if ($toggle.data("expanded")) {
|
156
|
+
this.showChildren(childId);
|
333
157
|
}
|
334
158
|
});
|
335
159
|
},
|
336
160
|
|
337
|
-
|
338
|
-
|
339
|
-
$children.
|
340
|
-
|
341
|
-
|
161
|
+
hideChildrenRecursive: function(parentId) {
|
162
|
+
const $children = this.$tableBody.find(`tr[data-parent-id="${parentId}"]`);
|
163
|
+
$children.addClass("treenode-hidden");
|
164
|
+
|
165
|
+
$children.each((_, child) => {
|
166
|
+
const childId = $(child).data("node-id");
|
167
|
+
this.hideChildrenRecursive(childId);
|
342
168
|
});
|
343
|
-
$children.remove();
|
344
|
-
this.saveTree();
|
345
169
|
},
|
346
170
|
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
171
|
+
expandAll: function() {
|
172
|
+
const self = this;
|
173
|
+
this.$tableBody.find("button.treenode-toggle").each(function() {
|
174
|
+
self.expandNode($(this).data("node-id"));
|
175
|
+
});
|
176
|
+
},
|
351
177
|
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
this.insertRows($parentRow, parentId);
|
358
|
-
}
|
178
|
+
collapseAll: function() {
|
179
|
+
const self = this;
|
180
|
+
this.$tableBody.find("button.treenode-toggle").each(function() {
|
181
|
+
self.collapseNode($(this).data("node-id"));
|
182
|
+
});
|
359
183
|
},
|
360
184
|
|
361
185
|
bindEvents: function() {
|
362
|
-
|
363
|
-
|
364
|
-
// Search listener
|
365
|
-
$('input[name="q"]')
|
366
|
-
.on("focus", function() {
|
367
|
-
self.saveTree();
|
368
|
-
})
|
369
|
-
.on("keyup", debounce(function() {
|
370
|
-
var query = $.trim($(this).val());
|
371
|
-
if (query === '') {
|
372
|
-
self.restoreTree(ChangeList.expandedNodes);
|
373
|
-
} else {
|
374
|
-
self.searchRows(query);
|
375
|
-
}
|
376
|
-
}, 300));
|
186
|
+
const self = this;
|
377
187
|
|
378
|
-
// Toggle buttons listener
|
379
188
|
$(document).on("click", "button.treenode-toggle", function(e) {
|
380
189
|
e.preventDefault();
|
381
|
-
|
382
|
-
|
190
|
+
self.toggleNode($(this));
|
191
|
+
});
|
192
|
+
|
193
|
+
$(document).on("click", ".treenode-expand-all", function() {
|
194
|
+
self.expandAll();
|
383
195
|
});
|
384
|
-
|
385
|
-
|
196
|
+
|
197
|
+
$(document).on("click", ".treenode-collapse-all", function() {
|
198
|
+
self.collapseAll();
|
199
|
+
});
|
200
|
+
|
386
201
|
$(document).on("keydown", function(e) {
|
387
202
|
if (e.key === "Shift") {
|
388
|
-
|
389
|
-
|
203
|
+
self.isShiftPressed = true;
|
204
|
+
self.updateDndHighlight();
|
390
205
|
}
|
391
|
-
})
|
392
|
-
.on("keyup", function(e) {
|
206
|
+
}).on("keyup", function(e) {
|
393
207
|
if (e.key === "Shift") {
|
394
|
-
|
395
|
-
|
208
|
+
self.isShiftPressed = false;
|
209
|
+
self.updateDndHighlight();
|
396
210
|
}
|
397
211
|
});
|
398
|
-
|
399
|
-
// Listener for admin panel theme change button
|
400
|
-
$(document).on("click", "button.theme-toggle", function() {
|
401
|
-
applyTheme();
|
402
|
-
});
|
403
|
-
|
404
|
-
// Fix action selets
|
212
|
+
|
405
213
|
$('#result_list').on('change', '#action-toggle', function() {
|
406
214
|
$('input.action-select').prop('checked', this.checked);
|
407
215
|
});
|
408
216
|
},
|
409
|
-
|
217
|
+
|
410
218
|
enableDragAndDrop: function() {
|
411
219
|
const self = this;
|
412
|
-
|
220
|
+
|
413
221
|
this.$tableBody.sortable({
|
414
222
|
items: "tr",
|
415
223
|
handle: ".treenode-drag-handle",
|
416
224
|
placeholder: "treenode-placeholder",
|
417
|
-
activeTargetRow: null,
|
418
225
|
helper: function(e, tr) {
|
419
226
|
const $originals = tr.children();
|
420
227
|
const $helper = tr.clone();
|
421
|
-
$helper.find('[id]').
|
422
|
-
$(this).removeAttr('id');
|
423
|
-
});
|
228
|
+
$helper.find('[id]').removeAttr('id');
|
424
229
|
$helper.children().each(function(index) {
|
425
230
|
$(this).width($originals.eq(index).width());
|
426
231
|
});
|
@@ -428,45 +233,38 @@
|
|
428
233
|
},
|
429
234
|
start: function(e, ui) {
|
430
235
|
TreeFx.markDragging(ui.item, true);
|
431
|
-
// ChangeList.updateDndHighlight();
|
432
|
-
// console.log("Drag started:", ui.item.data("node-id"));
|
433
236
|
},
|
434
237
|
over: function(e, ui) {
|
435
|
-
|
436
|
-
// console.log("over")
|
238
|
+
self.updateDndHighlight();
|
437
239
|
},
|
438
240
|
stop: function(e, ui) {
|
439
241
|
TreeFx.markDragging(ui.item, false);
|
440
|
-
|
441
242
|
const $item = ui.item;
|
442
243
|
const nodeId = $item.data("node-id");
|
443
244
|
const prevId = $item.prev().data("node-id") || null;
|
444
|
-
const
|
445
|
-
const isChild = ChangeList.isShiftPressed;
|
245
|
+
const mode = self.isShiftPressed ? 'child' : 'after';
|
446
246
|
|
447
|
-
if (
|
448
|
-
|
449
|
-
|
247
|
+
if (self.activeTargetRow) {
|
248
|
+
self.activeTargetRow.removeClass("target-as-child");
|
249
|
+
self.activeTargetRow = null;
|
450
250
|
}
|
451
251
|
|
452
|
-
|
453
|
-
ChangeList.applyMove(nodeId, prevId, mode)
|
454
|
-
|
252
|
+
self.applyMove(nodeId, prevId, mode);
|
455
253
|
TreeFx.flashInsert(nodeId);
|
456
254
|
},
|
457
255
|
});
|
458
256
|
},
|
459
|
-
|
257
|
+
|
460
258
|
updateDndHighlight: function() {
|
461
259
|
const $placeholder = this.$tableBody.find("tr.treenode-placeholder");
|
462
260
|
const $target = $placeholder.prev();
|
463
|
-
|
464
|
-
if (
|
261
|
+
|
262
|
+
if (!$target.length || !$target.data("node-id")) {
|
465
263
|
this.$tableBody.find("tr.target-as-child").removeClass("target-as-child");
|
466
264
|
this.activeTargetRow = null;
|
467
265
|
return;
|
468
266
|
}
|
469
|
-
|
267
|
+
|
470
268
|
if (this.isShiftPressed) {
|
471
269
|
if (!this.activeTargetRow || !this.activeTargetRow.is($target)) {
|
472
270
|
this.$tableBody.find("tr.target-as-child").removeClass("target-as-child");
|
@@ -480,52 +278,45 @@
|
|
480
278
|
}
|
481
279
|
}
|
482
280
|
},
|
483
|
-
|
281
|
+
|
484
282
|
applyMove: function(nodeId, targetId, mode) {
|
485
283
|
if (this.isMoving) return;
|
486
|
-
|
284
|
+
|
487
285
|
this.isMoving = true;
|
488
286
|
this.activeTargetRow = null;
|
489
|
-
|
287
|
+
|
490
288
|
const params = {
|
491
289
|
node_id: nodeId,
|
492
290
|
target_id: targetId,
|
493
|
-
mode: mode
|
494
|
-
expanded: JSON.stringify(this.expandedNodes)
|
291
|
+
mode: mode
|
495
292
|
};
|
496
|
-
|
497
|
-
// console.log(params);
|
498
|
-
|
293
|
+
|
499
294
|
$.ajax({
|
500
295
|
url: 'move/',
|
501
296
|
method: 'POST',
|
502
297
|
data: params,
|
503
298
|
dataType: 'json',
|
504
299
|
success: function(data) {
|
505
|
-
|
300
|
+
const msg = data.message || "Node moved successfully.";
|
301
|
+
$("<li class='success'>" + msg + "</li>").appendTo(".messagelist");
|
506
302
|
},
|
507
303
|
error: function(xhr, status, error) {
|
508
|
-
|
304
|
+
const fallback = "Error moving node.";
|
305
|
+
$("<li class='error'>" + (xhr.responseText || fallback) + "</li>").appendTo(".messagelist");
|
509
306
|
},
|
510
307
|
complete: function() {
|
511
308
|
ChangeList.isMoving = false;
|
512
|
-
|
309
|
+
location.reload();
|
513
310
|
}
|
514
311
|
});
|
515
312
|
}
|
516
|
-
}
|
517
|
-
|
518
|
-
// ------------------------------- //
|
519
|
-
// Init //
|
520
|
-
// ------------------------------- //
|
313
|
+
};
|
521
314
|
|
522
315
|
$(document).ready(function () {
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
}
|
316
|
+
if ($("table#result_list").length) {
|
317
|
+
ChangeList.init();
|
318
|
+
ChangeList.restoreTreeState();
|
319
|
+
}
|
528
320
|
});
|
529
321
|
|
530
|
-
})(django.jQuery || window.jQuery);
|
531
|
-
|
322
|
+
})(django.jQuery || window.jQuery);
|