documents: вкладка «Мой отдел» и drag-and-drop загрузка в список.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1332,6 +1332,16 @@
|
||||
border-color: var(--color-primary);
|
||||
background: color-mix(in srgb, var(--color-primary) 8%, var(--color-muted));
|
||||
}
|
||||
.nc-browser-drop {
|
||||
position: relative;
|
||||
min-height: 4rem;
|
||||
border-radius: 0.5rem;
|
||||
transition: background 120ms, box-shadow 120ms;
|
||||
}
|
||||
.nc-browser-drop.is-drag {
|
||||
background: color-mix(in srgb, var(--color-primary) 6%, transparent);
|
||||
box-shadow: inset 0 0 0 2px color-mix(in srgb, var(--color-primary) 45%, transparent);
|
||||
}
|
||||
.nc-drop-label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
@@ -1968,6 +1968,16 @@
|
||||
border-color: var(--color-primary);
|
||||
background: color-mix(in srgb, var(--color-primary) 8%, var(--color-muted));
|
||||
}
|
||||
.nc-browser-drop {
|
||||
position: relative;
|
||||
min-height: 4rem;
|
||||
border-radius: 0.5rem;
|
||||
transition: background 120ms, box-shadow 120ms;
|
||||
}
|
||||
.nc-browser-drop.is-drag {
|
||||
background: color-mix(in srgb, var(--color-primary) 6%, transparent);
|
||||
box-shadow: inset 0 0 0 2px color-mix(in srgb, var(--color-primary) 45%, transparent);
|
||||
}
|
||||
.nc-drop-label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
@@ -1,45 +1,116 @@
|
||||
(function () {
|
||||
document.documentElement.classList.remove('oo-open');
|
||||
var emptyLabel = 'или перетащите сюда';
|
||||
var emptyLabel = 'или перетащите сюда / в список';
|
||||
|
||||
function dropRoot(el) {
|
||||
return el && el.closest ? el.closest('.nc-drop') : null;
|
||||
}
|
||||
|
||||
function browserDropRoot(el) {
|
||||
return el && el.closest ? el.closest('.nc-browser-drop[data-nc-upload="1"]') : null;
|
||||
}
|
||||
|
||||
function findUploadForm(fromEl) {
|
||||
var browser = browserDropRoot(fromEl);
|
||||
if (browser) {
|
||||
var f = browser.querySelector('form.nc-drop');
|
||||
if (f) return f;
|
||||
}
|
||||
return dropRoot(fromEl);
|
||||
}
|
||||
|
||||
function uploadFilesViaForm(form, fileList) {
|
||||
if (!form || !fileList || !fileList.length) return;
|
||||
var files = Array.prototype.slice.call(fileList);
|
||||
var url = form.getAttribute('hx-post') || form.getAttribute('action');
|
||||
var targetSel = form.getAttribute('hx-target') || '#documents-browser';
|
||||
var swap = form.getAttribute('hx-swap') || 'innerHTML';
|
||||
|
||||
function next() {
|
||||
if (!files.length) return;
|
||||
var file = files.shift();
|
||||
var fd = new FormData(form);
|
||||
fd.set('file', file, file.name);
|
||||
fetch(url, {
|
||||
method: 'POST',
|
||||
body: fd,
|
||||
credentials: 'same-origin',
|
||||
headers: { 'HX-Request': 'true' },
|
||||
}).then(function (r) {
|
||||
return r.text().then(function (html) {
|
||||
var target = document.querySelector(targetSel);
|
||||
if (target) {
|
||||
if (typeof htmx !== 'undefined' && htmx.swap) {
|
||||
htmx.swap(target, html, { swapStyle: swap });
|
||||
} else {
|
||||
target.innerHTML = html;
|
||||
}
|
||||
// после swap форма пересоздана — продолжаем очередь
|
||||
form = target.querySelector('form.nc-drop') || form;
|
||||
}
|
||||
if (files.length) next();
|
||||
});
|
||||
}).catch(function () { /* ignore */ });
|
||||
}
|
||||
next();
|
||||
}
|
||||
|
||||
document.addEventListener('change', function (e) {
|
||||
if (!e.target || !e.target.classList.contains('nc-drop-input')) return;
|
||||
var drop = dropRoot(e.target);
|
||||
var nameEl = drop && drop.querySelector('.nc-drop-name');
|
||||
if (!nameEl) return;
|
||||
var file = e.target.files && e.target.files[0];
|
||||
nameEl.textContent = file ? file.name : emptyLabel;
|
||||
var files = e.target.files;
|
||||
if (!files || !files.length) {
|
||||
nameEl.textContent = emptyLabel;
|
||||
return;
|
||||
}
|
||||
nameEl.textContent = files.length === 1
|
||||
? files[0].name
|
||||
: (files.length + ' файлов');
|
||||
});
|
||||
|
||||
document.addEventListener('dragover', function (e) {
|
||||
var drop = dropRoot(e.target);
|
||||
if (!drop) return;
|
||||
var zone = browserDropRoot(e.target) || dropRoot(e.target);
|
||||
if (!zone) return;
|
||||
e.preventDefault();
|
||||
drop.classList.add('is-drag');
|
||||
e.dataTransfer.dropEffect = 'copy';
|
||||
zone.classList.add('is-drag');
|
||||
});
|
||||
|
||||
document.addEventListener('dragleave', function (e) {
|
||||
var drop = dropRoot(e.target);
|
||||
if (!drop) return;
|
||||
if (e.relatedTarget && drop.contains(e.relatedTarget)) return;
|
||||
drop.classList.remove('is-drag');
|
||||
var zone = browserDropRoot(e.target) || dropRoot(e.target);
|
||||
if (!zone) return;
|
||||
if (e.relatedTarget && zone.contains(e.relatedTarget)) return;
|
||||
zone.classList.remove('is-drag');
|
||||
});
|
||||
|
||||
document.addEventListener('drop', function (e) {
|
||||
var browser = browserDropRoot(e.target);
|
||||
var drop = dropRoot(e.target);
|
||||
if (!drop) return;
|
||||
var zone = browser || drop;
|
||||
if (!zone) return;
|
||||
e.preventDefault();
|
||||
drop.classList.remove('is-drag');
|
||||
var input = drop.querySelector('.nc-drop-input');
|
||||
if (!input || !e.dataTransfer || !e.dataTransfer.files.length) return;
|
||||
input.files = e.dataTransfer.files;
|
||||
input.dispatchEvent(new Event('change', { bubbles: true }));
|
||||
zone.classList.remove('is-drag');
|
||||
if (!e.dataTransfer || !e.dataTransfer.files.length) return;
|
||||
|
||||
var form = findUploadForm(e.target);
|
||||
if (!form) return;
|
||||
|
||||
// автозагрузка сразу (без кнопки «Загрузить»)
|
||||
uploadFilesViaForm(form, e.dataTransfer.files);
|
||||
});
|
||||
|
||||
// Несколько файлов через кнопку «Загрузить» — по одному, как при DnD
|
||||
document.addEventListener('submit', function (e) {
|
||||
var form = e.target;
|
||||
if (!form || !form.classList || !form.classList.contains('nc-drop')) return;
|
||||
var input = form.querySelector('.nc-drop-input');
|
||||
if (!input || !input.files || input.files.length <= 1) return;
|
||||
e.preventDefault();
|
||||
uploadFilesViaForm(form, input.files);
|
||||
}, true);
|
||||
|
||||
document.addEventListener('htmx:afterSwap', function (e) {
|
||||
if (!e.detail || !e.detail.target || e.detail.target.id !== 'main-content') return;
|
||||
document.documentElement.classList.remove('oo-open');
|
||||
@@ -127,7 +198,6 @@
|
||||
dl.setAttribute('download', name || '');
|
||||
}
|
||||
if (full) {
|
||||
// полная страница — тот же inline URL (или отдельный preview route, если передан)
|
||||
var fullHref = (elOrUrl && elOrUrl.getAttribute && elOrUrl.getAttribute('data-doc-full')) || url;
|
||||
full.href = fullHref;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user