ae54d93442
Section-based portal access, matrix прав по группам, аккаунтинг-портал, управление группами пользователей, справочники, дашборд и общий каркас навигации/стилей. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
113 lines
3.8 KiB
JavaScript
113 lines
3.8 KiB
JavaScript
/**
|
|
* Drag-and-drop порядка записей системных справочников.
|
|
* Перетаскивание только среди соседей (один parent_id).
|
|
*/
|
|
(function () {
|
|
'use strict';
|
|
|
|
var dragRow = null;
|
|
|
|
function csrfToken() {
|
|
var el = document.querySelector('#dir-items-tbody [name=csrfmiddlewaretoken], input[name=csrfmiddlewaretoken]');
|
|
if (el) return el.value;
|
|
var m = document.cookie.match(/(?:^|; )csrftoken=([^;]+)/);
|
|
return m ? decodeURIComponent(m[1]) : '';
|
|
}
|
|
|
|
function saveOrder(row) {
|
|
var tbody = document.getElementById('dir-items-tbody');
|
|
if (!tbody || !row) return;
|
|
var parentId = row.getAttribute('data-parent-id') || '';
|
|
var typeId = tbody.getAttribute('data-type-id');
|
|
var url = tbody.getAttribute('data-reorder-url');
|
|
if (!typeId || !url) return;
|
|
|
|
var ids = [];
|
|
tbody.querySelectorAll('tr.dir-item-row').forEach(function (tr) {
|
|
if ((tr.getAttribute('data-parent-id') || '') === parentId) {
|
|
ids.push(tr.getAttribute('data-id'));
|
|
}
|
|
});
|
|
if (!ids.length) return;
|
|
|
|
var form = document.createElement('form');
|
|
form.method = 'POST';
|
|
form.action = url;
|
|
form.style.display = 'none';
|
|
|
|
function add(name, value) {
|
|
var input = document.createElement('input');
|
|
input.type = 'hidden';
|
|
input.name = name;
|
|
input.value = value;
|
|
form.appendChild(input);
|
|
}
|
|
add('csrfmiddlewaretoken', csrfToken());
|
|
add('order', ids.join(','));
|
|
add('parent_id', parentId);
|
|
document.body.appendChild(form);
|
|
form.submit();
|
|
}
|
|
|
|
function onDragStart(e) {
|
|
var handle = e.target.closest('.dir-drag-handle');
|
|
if (!handle) {
|
|
e.preventDefault();
|
|
return;
|
|
}
|
|
var row = handle.closest('tr.dir-item-row');
|
|
if (!row) return;
|
|
dragRow = row;
|
|
row.classList.add('dir-dragging');
|
|
try {
|
|
e.dataTransfer.effectAllowed = 'move';
|
|
e.dataTransfer.setData('text/plain', row.getAttribute('data-id') || '');
|
|
} catch (err) { /* IE */ }
|
|
}
|
|
|
|
function onDragOver(e) {
|
|
if (!dragRow) return;
|
|
var target = e.target.closest('tr.dir-item-row');
|
|
if (!target || target === dragRow) return;
|
|
if ((target.getAttribute('data-parent-id') || '') !== (dragRow.getAttribute('data-parent-id') || '')) {
|
|
return;
|
|
}
|
|
e.preventDefault();
|
|
var tbody = target.parentNode;
|
|
var rect = target.getBoundingClientRect();
|
|
var before = (e.clientY - rect.top) < rect.height / 2;
|
|
if (before) {
|
|
tbody.insertBefore(dragRow, target);
|
|
} else {
|
|
tbody.insertBefore(dragRow, target.nextSibling);
|
|
}
|
|
}
|
|
|
|
function onDrop(e) {
|
|
e.preventDefault();
|
|
}
|
|
|
|
function onDragEnd() {
|
|
if (!dragRow) return;
|
|
var row = dragRow;
|
|
dragRow.classList.remove('dir-dragging');
|
|
dragRow = null;
|
|
saveOrder(row);
|
|
}
|
|
|
|
function bind() {
|
|
var tbody = document.getElementById('dir-items-tbody');
|
|
if (!tbody || tbody.getAttribute('data-dnd-bound') === '1') return;
|
|
if (tbody.getAttribute('data-can-edit') !== '1') return;
|
|
tbody.setAttribute('data-dnd-bound', '1');
|
|
tbody.addEventListener('dragstart', onDragStart);
|
|
tbody.addEventListener('dragover', onDragOver);
|
|
tbody.addEventListener('drop', onDrop);
|
|
tbody.addEventListener('dragend', onDragEnd);
|
|
}
|
|
|
|
document.addEventListener('DOMContentLoaded', bind);
|
|
document.addEventListener('htmx:afterSwap', bind);
|
|
document.addEventListener('htmx:afterSettle', bind);
|
|
})();
|