0424e0273e
Co-authored-by: Cursor <cursoragent@cursor.com>
245 lines
9.8 KiB
JavaScript
245 lines
9.8 KiB
JavaScript
(function () {
|
|
document.documentElement.classList.remove('oo-open');
|
|
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 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 zone = browserDropRoot(e.target) || dropRoot(e.target);
|
|
if (!zone) return;
|
|
e.preventDefault();
|
|
e.dataTransfer.dropEffect = 'copy';
|
|
zone.classList.add('is-drag');
|
|
});
|
|
|
|
document.addEventListener('dragleave', function (e) {
|
|
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);
|
|
var zone = browser || drop;
|
|
if (!zone) return;
|
|
e.preventDefault();
|
|
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');
|
|
});
|
|
|
|
// ── Модальный предпросмотр PDF / изображений ───────────────────────────
|
|
|
|
function ensurePreviewModal() {
|
|
var existing = document.getElementById('doc-preview-modal');
|
|
if (existing) return existing;
|
|
|
|
var overlay = document.createElement('div');
|
|
overlay.id = 'doc-preview-overlay';
|
|
overlay.className = 'doc-preview-overlay';
|
|
overlay.style.display = 'none';
|
|
overlay.addEventListener('click', docPreviewClose);
|
|
|
|
var modal = document.createElement('div');
|
|
modal.id = 'doc-preview-modal';
|
|
modal.className = 'doc-preview-modal';
|
|
modal.setAttribute('role', 'dialog');
|
|
modal.setAttribute('aria-modal', 'true');
|
|
modal.style.display = 'none';
|
|
modal.addEventListener('click', docPreviewClose);
|
|
modal.innerHTML =
|
|
'<div class="doc-preview-dialog" onclick="event.stopPropagation()">' +
|
|
' <div class="doc-preview-dialog-bar">' +
|
|
' <div class="doc-preview-dialog-title" id="doc-preview-title"></div>' +
|
|
' <div class="doc-preview-dialog-actions">' +
|
|
' <a id="doc-preview-download" class="btn btn-ghost" style="font-size:0.8125rem;" download>Скачать</a>' +
|
|
' <a id="doc-preview-full" class="btn btn-ghost" style="font-size:0.8125rem;" target="_blank" rel="noopener">На всю страницу</a>' +
|
|
' <button type="button" class="btn btn-ghost btn-icon" id="doc-preview-close" aria-label="Закрыть">✕</button>' +
|
|
' </div>' +
|
|
' </div>' +
|
|
' <div class="doc-preview-dialog-body" id="doc-preview-body"></div>' +
|
|
'</div>';
|
|
|
|
document.body.appendChild(overlay);
|
|
document.body.appendChild(modal);
|
|
document.getElementById('doc-preview-close').addEventListener('click', docPreviewClose);
|
|
return modal;
|
|
}
|
|
|
|
function downloadUrlFromInline(url) {
|
|
try {
|
|
var u = new URL(url, window.location.origin);
|
|
u.searchParams.delete('inline');
|
|
return u.pathname + u.search;
|
|
} catch (err) {
|
|
return String(url || '').replace(/([?&])inline=1(&|$)/, function (_, a, b) {
|
|
return a === '?' && b === '&' ? '?' : (b === '&' ? a : '');
|
|
});
|
|
}
|
|
}
|
|
|
|
window.docPreviewOpen = function (elOrUrl, title, kind) {
|
|
var url, name, previewKind;
|
|
if (typeof elOrUrl === 'string') {
|
|
url = elOrUrl;
|
|
name = title || '';
|
|
previewKind = kind || 'image';
|
|
} else if (elOrUrl && elOrUrl.getAttribute) {
|
|
url = elOrUrl.getAttribute('href') || '';
|
|
name = elOrUrl.getAttribute('data-doc-title') || elOrUrl.textContent || '';
|
|
previewKind = elOrUrl.getAttribute('data-doc-kind') || 'image';
|
|
} else {
|
|
return false;
|
|
}
|
|
if (!url) return false;
|
|
|
|
ensurePreviewModal();
|
|
var overlay = document.getElementById('doc-preview-overlay');
|
|
var modal = document.getElementById('doc-preview-modal');
|
|
var body = document.getElementById('doc-preview-body');
|
|
var titleEl = document.getElementById('doc-preview-title');
|
|
var dl = document.getElementById('doc-preview-download');
|
|
var full = document.getElementById('doc-preview-full');
|
|
|
|
if (titleEl) {
|
|
titleEl.textContent = name;
|
|
titleEl.title = name;
|
|
}
|
|
if (dl) {
|
|
dl.href = downloadUrlFromInline(url);
|
|
dl.setAttribute('download', name || '');
|
|
}
|
|
if (full) {
|
|
var fullHref = (elOrUrl && elOrUrl.getAttribute && elOrUrl.getAttribute('data-doc-full')) || url;
|
|
full.href = fullHref;
|
|
}
|
|
|
|
body.innerHTML = '';
|
|
if (previewKind === 'pdf') {
|
|
var frame = document.createElement('iframe');
|
|
frame.className = 'doc-preview-dialog-frame';
|
|
frame.title = name || 'PDF';
|
|
frame.src = url;
|
|
body.appendChild(frame);
|
|
} else {
|
|
var wrap = document.createElement('div');
|
|
wrap.className = 'doc-preview-dialog-image-wrap';
|
|
var img = document.createElement('img');
|
|
img.className = 'doc-preview-dialog-image';
|
|
img.alt = name || '';
|
|
img.src = url;
|
|
wrap.appendChild(img);
|
|
body.appendChild(wrap);
|
|
}
|
|
|
|
overlay.style.display = 'block';
|
|
modal.style.display = 'flex';
|
|
document.body.style.overflow = 'hidden';
|
|
return false;
|
|
};
|
|
|
|
window.docPreviewClose = function () {
|
|
var overlay = document.getElementById('doc-preview-overlay');
|
|
var modal = document.getElementById('doc-preview-modal');
|
|
var body = document.getElementById('doc-preview-body');
|
|
if (overlay) overlay.style.display = 'none';
|
|
if (modal) modal.style.display = 'none';
|
|
if (body) body.innerHTML = '';
|
|
document.body.style.overflow = '';
|
|
};
|
|
|
|
document.addEventListener('keydown', function (ev) {
|
|
if (ev.key !== 'Escape') return;
|
|
var modal = document.getElementById('doc-preview-modal');
|
|
if (modal && modal.style.display === 'flex') docPreviewClose();
|
|
});
|
|
})();
|