Files
triggerssmith/static/blocks/pages/userSlava/popup/script.js
2025-12-17 10:14:13 +02:00

235 lines
7.9 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

const inputPopup = document.getElementById('inputPopup');
const createPopup = document.getElementById('createPopup');
const actionTable = {
'Редактировать': () => console.log('Редактировать'),
'Удалить': () => console.log('Удалить'),
'Копировать': () => console.log('Скопировано')
};
let menuDiv = document.querySelector('.window-menu');
if (!menuDiv) {
menuDiv = document.createElement('div');
menuDiv.className = 'window-menu';
menuDiv.style.position = 'absolute';
menuDiv.style.display = 'none';
document.body.appendChild(menuDiv);
}
function parseJSONSafe(str) {
if (!str) return null;
try { return JSON.parse(str); } catch (e) { return null; }
}
function splitMenuText(text) {
if (!text) return [];
return String(text).split(',').map(s => s.trim()).filter(Boolean);
}
function buildMenu(items) {
menuDiv.innerHTML = '';
items.forEach(label => {
const it = document.createElement('div');
it.className = 'window-item';
it.textContent = label;
it.addEventListener('click', (e) => {
e.stopPropagation();
if (actionTable[label]) actionTable[label]();
hideMenu();
});
menuDiv.appendChild(it);
});
}
function showMenuAt(x, y, items) {
if (!items || !items.length) return;
buildMenu(items);
menuDiv.style.display = 'block';
menuDiv.style.left = x + 'px';
menuDiv.style.top = y + 'px';
const rect = menuDiv.getBoundingClientRect();
if (rect.right > window.innerWidth) menuDiv.style.left = (x - rect.width) + 'px';
if (rect.bottom > window.innerHeight) menuDiv.style.top = (y - rect.height) + 'px';
setTimeout(() => document.addEventListener('click', hideMenu, { once: true }), 0);
}
function hideMenu() {
menuDiv.style.display = 'none';
}
function showOverlayMessage(text) {
if (!text) return;
const overlay = document.createElement('div');
overlay.className = 'overlay';
const popup = document.createElement('div');
popup.className = 'window-popup';
const content = document.createElement('div');
content.textContent = String(text);
const closeBtn = document.createElement('button');
closeBtn.textContent = 'Закрыть';
closeBtn.addEventListener('click', () => overlay.remove());
overlay.addEventListener('click', (e) => { if (e.target === overlay) overlay.remove(); });
popup.appendChild(content);
popup.appendChild(closeBtn);
overlay.appendChild(popup);
document.body.appendChild(overlay);
}
function popupFileFromSections(title, sections, afterClose) {
const popup = document.createElement('div');
popup.className = 'window-panel';
const header = document.createElement('div');
header.className = 'window-header';
header.textContent = 'Свойства: ' + (title || '');
const tabs = document.createElement('div');
tabs.className = 'window-tabs';
const tabButtons = [];
const tabContents = [];
const keys = Object.keys(sections || {});
keys.forEach((name, i) => {
const t = document.createElement('div');
t.className = 'window-tab' + (i === 0 ? ' active' : '');
t.textContent = name;
t.addEventListener('click', () => switchTab(i));
tabButtons.push(t);
tabs.appendChild(t);
const content = document.createElement('div');
content.className = 'window-content' + (i === 0 ? ' active' : '');
const val = sections[name];
if (Array.isArray(val)) {
val.forEach(row => {
const rowEl = document.createElement('div');
rowEl.className = 'window-row';
if (Array.isArray(row) && row.length >= 2) {
const k = document.createElement('span');
k.textContent = row[0];
const v = document.createElement('span');
v.textContent = row[1];
rowEl.append(k, v);
} else {
rowEl.textContent = String(row);
}
content.appendChild(rowEl);
});
} else if (val && typeof val === 'object') {
Object.keys(val).forEach(kname => {
const rowEl = document.createElement('div');
rowEl.className = 'window-row';
const k = document.createElement('span');
k.textContent = kname + ':';
const v = document.createElement('span');
v.textContent = String(val[kname]);
rowEl.append(k, v);
content.appendChild(rowEl);
});
} else {
content.innerHTML = String(val || '');
}
tabContents.push(content);
});
function switchTab(i) {
tabButtons.forEach((t, idx) => t.classList.toggle('active', idx === i));
tabContents.forEach((c, idx) => c.classList.toggle('active', idx === i));
}
const buttons = document.createElement('div');
buttons.className = 'window-buttons';
const okBtn = document.createElement('button');
okBtn.textContent = 'ОК';
const cancelBtn = document.createElement('button');
cancelBtn.textContent = 'Отмена';
okBtn.onclick = close;
cancelBtn.onclick = close;
buttons.append(okBtn, cancelBtn);
let offsetX, offsetY, dragging = false;
header.addEventListener('mousedown', (e) => {
dragging = true;
offsetX = e.clientX - popup.offsetLeft;
offsetY = e.clientY - popup.offsetTop;
header.style.userSelect = 'none';
});
document.addEventListener('mousemove', (e) => {
if (dragging) {
popup.style.left = (e.clientX - offsetX) + 'px';
popup.style.top = (e.clientY - offsetY) + 'px';
}
});
document.addEventListener('mouseup', () => {
dragging = false;
});
function close() {
popup.remove();
if (typeof afterClose === 'function') afterClose();
}
popup.append(header, tabs, ...tabContents, buttons);
document.body.append(popup);
}
function handleCommand(raw, opts) {
if (!raw) return;
const parsed = typeof raw === 'string' ? parseJSONSafe(raw.trim()) : raw;
if (!parsed || !parsed.act) return;
if (parsed.act === 'message' && opts && opts.source === 'button') {
const text = parsed.text || '';
if (!text) return;
showOverlayMessage(text);
return;
}
if (parsed.act === 'menu' && opts && opts.source === 'context') {
const items = Array.isArray(parsed.text)
? parsed.text.map(s => String(s).trim()).filter(Boolean)
: splitMenuText(String(parsed.text || ''));
if (!items.length) return;
const x = opts.coords && typeof opts.coords.x === 'number' ? opts.coords.x : (parsed.x || 0);
const y = opts.coords && typeof opts.coords.y === 'number' ? opts.coords.y : (parsed.y || 0);
showMenuAt(x, y, items);
return;
}
if (parsed.act === 'file' && opts && opts.source === 'button') {
const sections = parsed.text && typeof parsed.text === 'object' ? parsed.text : null;
const title = sections && sections['Общие'] && sections['Общие']['Имя']
? sections['Общие']['Имя']
: parsed.title || '';
if (!sections) return;
popupFileFromSections(title, sections);
return;
}
}
createPopup.addEventListener('click', () => {
const raw = (inputPopup && inputPopup.value) ? inputPopup.value : '';
handleCommand(raw, { source: 'button' });
});
document.addEventListener('contextmenu', (e) => {
const raw = (inputPopup && inputPopup.value) ? inputPopup.value : '';
const parsed = parseJSONSafe(raw);
if (!parsed || parsed.act !== 'menu') return;
e.preventDefault();
handleCommand(raw, { source: 'context', coords: { x: e.pageX, y: e.pageY } });
});
window.addEventListener('keydown', (e) => {
if (e.key === 'Escape') hideMenu();
});