Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
177 changes: 85 additions & 92 deletions public/script.js
Original file line number Diff line number Diff line change
Expand Up @@ -326,33 +326,15 @@ async function deleteItem(id, level) {
}
}

async function editItem(item, level) {
const li = document.querySelector(`li[data-id="${item.id}"]`);
if (!li) return;

const nameContainer = li.querySelector('div'); // ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€ с ΠΈΠΌΠ΅Π½Π΅ΠΌ ΠΈ Ρ‚ΠΈΠΏΠΎΠΌ
if (!nameContainer) return;

// Найдём ΠΊΠ½ΠΎΠΏΠΊΡƒ рСдактирования/ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€ дСйствий (Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π½Π΅ ΠΏΠΎΡ‚Π΅Ρ€ΡΡ‚ΡŒ)
const buttonContainer = li.querySelector('.item-actions');

// БохраняСм староС состояниС Π½Π° случай ΠΎΡ‚ΠΌΠ΅Π½Ρ‹
const originalName = item.name;
const originalType = item.type || '';

// ΠžΡ‡ΠΈΡΡ‚ΠΈΠΌ ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€ ΠΈ создадим поля для рСдактирования
nameContainer.innerHTML = '';

function createEditFormElements(originalName, originalType, level) {
const nameInput = document.createElement('input');
nameInput.type = 'text';
nameInput.value = originalName;
nameInput.style.minWidth = '140px';
nameInput.className = 'inline-name-input';

nameContainer.appendChild(nameInput);

// ΠŸΠΎΠΊΠ°Π·Ρ‹Π²Π°Π΅ΠΌ сСлСкт Ρ‚ΠΈΠΏΠ° Ρ‚ΠΎΠ»ΡŒΠΊΠΎ для ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠ², Ρƒ ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Ρ… Ρ‚ΠΈΠΏ ΠΌΠΎΠΆΠ½ΠΎ ΠΌΠ΅Π½ΡΡ‚ΡŒ (Π½Π΅ house/room)
let typeSelect = null;
let typeSpan = null;
const editableTypes = ['item', 'container', 'pocket', 'cabinet', 'shelf'];
if (level !== 'house' && level !== 'room') {
typeSelect = document.createElement('select');
Expand All @@ -364,17 +346,13 @@ async function editItem(item, level) {
if (t === originalType) opt.selected = true;
typeSelect.appendChild(opt);
});
nameContainer.appendChild(typeSelect);
} else {
// Ссли Ρ‚ΠΈΠΏ Π½Π΅ Ρ€Π΅Π΄Π°ΠΊΡ‚ΠΈΡ€ΡƒΠ΅ΠΌΡ‹ΠΉ, ΠΏΠΎΠΊΠ°Π·Ρ‹Π²Π°Π΅ΠΌ Ρ‚Π΅ΠΊΡƒΡ‰ΠΈΠΉ Ρ‚ΠΈΠΏ ΠΊΠ°ΠΊ span
const typeSpan = document.createElement('span');
typeSpan = document.createElement('span');
typeSpan.textContent = ` (${originalType || level})`;
typeSpan.style.color = '#888';
typeSpan.style.marginLeft = '6px';
nameContainer.appendChild(typeSpan);
}

// Кнопки ΡΠΎΡ…Ρ€Π°Π½ΠΈΡ‚ΡŒ / ΠΎΡ‚ΠΌΠ΅Π½Π°
const saveBtn = document.createElement('button');
saveBtn.textContent = 'Π‘ΠΎΡ…Ρ€Π°Π½ΠΈΡ‚ΡŒ';
saveBtn.className = 'save-inline-btn';
Expand All @@ -385,54 +363,90 @@ async function editItem(item, level) {
cancelBtn.className = 'cancel-inline-btn';
cancelBtn.style.marginLeft = '4px';

nameContainer.appendChild(saveBtn);
nameContainer.appendChild(cancelBtn);
return { nameInput, typeSelect, typeSpan, saveBtn, cancelBtn };
}

// Ѐокус
nameInput.focus();
nameInput.select();
function restoreItemView(nameContainer, item, nameText, typeText) {
nameContainer.innerHTML = '';
const link = document.createElement('a');
link.textContent = nameText;
link.href = '#';
link.dataset.id = item.id;
link.dataset.type = typeText;
link.style.textDecoration = 'none';
link.style.color = ''; // ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌ ΡΡ‚ΠΈΠ»Π΅Π²ΡƒΡŽ систСму страницы

const itemTypeSpan = document.createElement('span');
itemTypeSpan.textContent = ` (${typeText})`;
itemTypeSpan.style.color = '#888';
itemTypeSpan.style.fontSize = '0.9em';
itemTypeSpan.style.marginLeft = '6px';

nameContainer.appendChild(link);
nameContainer.appendChild(itemTypeSpan);

const containerTypes = ['room','cabinet','container','pocket','shelf','house'];
if (containerTypes.includes(typeText)) {
link.classList.add('clickable-item');
} else {
link.classList.remove('clickable-item');
}
}

const makeNameAndTypeNodes = (nameText, typeText) => {
nameContainer.innerHTML = ''; // очистим ΠΏΠ΅Ρ€Π΅Π΄ восстановлСниСм
const link = document.createElement('a');
link.textContent = nameText;
link.href = '#';
link.dataset.id = item.id;
link.dataset.type = typeText;
link.style.textDecoration = 'none';
link.style.color = ''; // ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌ ΡΡ‚ΠΈΠ»Π΅Π²ΡƒΡŽ систСму страницы
async function updateItemApi(id, level, payload) {
let url;
if (level === 'house') {
url = `/api/houses/${id}`;
} else if (level === 'room') {
url = `/api/rooms/${id}`;
} else {
url = `/api/items/${id}`;
}

const itemTypeSpan = document.createElement('span');
itemTypeSpan.textContent = ` (${typeText})`;
itemTypeSpan.style.color = '#888';
itemTypeSpan.style.fontSize = '0.9em';
itemTypeSpan.style.marginLeft = '6px';
const response = await fetch(url, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload)
});

// ВставляСм Π² ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€
nameContainer.appendChild(link);
nameContainer.appendChild(itemTypeSpan);
if (!response.ok) {
const err = await response.json().catch(()=>({ error: 'Ошибка' }));
throw new Error(err.error || err.message || 'Ошибка ΠΏΡ€ΠΈ сохранСнии.');
}
return response;
}

// Если Ρ‚ΠΈΠΏ β€” ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€/ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚, оставляСм ссылку кликабСльной (handler ΡƒΠΆΠ΅ Π΅ΡΡ‚ΡŒ Π½Π° parent)
// ДобавляСм класс, Ρ‡Ρ‚ΠΎΠ±Ρ‹ CSS ΠΌΠΎΠ³ ΠΏΠΎΠ΄ΡΠ²Π΅Ρ‚ΠΈΡ‚ΡŒ ссылки- ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€Ρ‹
const containerTypes = ['room','cabinet','container','pocket','shelf','house'];
if (containerTypes.includes(typeText)) {
link.classList.add('clickable-item');
} else {
link.classList.remove('clickable-item');
}
};
async function editItem(item, level) {
const li = document.querySelector(`li[data-id="${item.id}"]`);
if (!li) return;

const restoreView = () => {
// Восстановим ΠΎΡ‚ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅ Π² Ρ‚Π΅ΠΊΡƒΡ‰Π΅ΠΌ контСкстС β€” Π½ΠΎ Π±Π΅Π· ΠΏΠ΅Ρ€Π΅Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠΈ Π΄Π°Π½Π½Ρ‹Ρ…, Ссли ΡƒΠΆΠ΅ ΠΎΠ±Π½ΠΎΠ²ΠΈΠ»ΠΈ DOM
const lastStep = currentPath[currentPath.length - 1];
if (!lastStep || lastStep.type === 'root') {
showHouses();
} else if (lastStep.type === 'house') {
showRooms(lastStep.id, lastStep.name);
} else {
showItems(lastStep.id, lastStep.name, lastStep.type);
}
};
const nameContainer = li.querySelector('div'); // ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€ с ΠΈΠΌΠ΅Π½Π΅ΠΌ ΠΈ Ρ‚ΠΈΠΏΠΎΠΌ
if (!nameContainer) return;

// Найдём ΠΊΠ½ΠΎΠΏΠΊΡƒ рСдактирования/ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€ дСйствий (Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π½Π΅ ΠΏΠΎΡ‚Π΅Ρ€ΡΡ‚ΡŒ)
const buttonContainer = li.querySelector('.item-actions');

// БохраняСм староС состояниС Π½Π° случай ΠΎΡ‚ΠΌΠ΅Π½Ρ‹
const originalName = item.name;
const originalType = item.type || '';

// ΠžΡ‡ΠΈΡΡ‚ΠΈΠΌ ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€ ΠΈ создадим поля для рСдактирования
nameContainer.innerHTML = '';

const { nameInput, typeSelect, typeSpan, saveBtn, cancelBtn } = createEditFormElements(originalName, originalType, level);

nameContainer.appendChild(nameInput);
if (typeSelect) {
nameContainer.appendChild(typeSelect);
} else if (typeSpan) {
nameContainer.appendChild(typeSpan);
}
nameContainer.appendChild(saveBtn);
nameContainer.appendChild(cancelBtn);

// Ѐокус
nameInput.focus();
nameInput.select();

const handleSave = async () => {
const newName = nameInput.value.trim();
Expand All @@ -444,34 +458,16 @@ async function editItem(item, level) {
}

try {
let url;
if (level === 'house') {
url = `/api/houses/${item.id}`;
} else if (level === 'room') {
url = `/api/rooms/${item.id}`;
} else {
url = `/api/items/${item.id}`;
}

const payload = { name: newName };
if (typeSelect) payload.type = newType;

const response = await fetch(url, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload)
});

if (!response.ok) {
const err = await response.json().catch(()=>({ error: 'Ошибка' }));
throw new Error(err.error || err.message || 'Ошибка ΠΏΡ€ΠΈ сохранСнии.');
}
await updateItemApi(item.id, level, payload);

// ΠžΠΏΡ‚ΠΈΠΌΠΈΡΡ‚ΠΈΡ‡Π½ΠΎΠ΅ ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½ΠΈΠ΅: ΠΎΠ±Π½ΠΎΠ²ΠΈΠΌ Π»ΠΎΠΊΠ°Π»ΡŒΠ½Ρ‹ΠΉ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ ΠΈ DOM Π±Π΅Π· ΠΏΠΎΠ»Π½ΠΎΠΉ ΠΏΠ΅Ρ€Π΅Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠΈ
item.name = newName;
if (typeSelect) item.type = newType;

makeNameAndTypeNodes(newName, item.type || level);
restoreItemView(nameContainer, item, newName, item.type || level);

// Кнопки ΠΎΡΡ‚Π°ΡŽΡ‚ΡΡ Π² buttonContainer, Π½ΠΈΡ‡Π΅Π³ΠΎ Π½Π΅ Ρ‚Ρ€ΠΎΠ³Π°Π΅ΠΌ
// Π‘Π»Π΅Π³ΠΊΠ° подсвСтим измСнСния
Expand All @@ -480,20 +476,17 @@ async function editItem(item, level) {
buttonContainer.style.background = 'rgba(200,255,200,0.3)';
setTimeout(()=> buttonContainer.style.background = '', 600);
}

// Если Ρ‚ΠΈΠΏ стал ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€ΠΎΠΌ β€” ΠΌΠΎΠΆΠ½ΠΎ сразу ΠΎΡ‚ΠΊΡ€Ρ‹Ρ‚ΡŒ Π΅Π³ΠΎ ΠΏΡ€ΠΈ ΠΊΠ»ΠΈΠΊΠ΅ (click handler Π½Π° parent ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚)
return;
} catch (error) {
console.error(error);
if (errorMessageEl) errorMessageEl.textContent = error.message || 'Ошибка ΠΏΡ€ΠΈ сохранСнии.';
// Π’ случаС ошибки восстановим ΠΏΡ€Π΅ΠΆΠ½ΠΈΠΉ Π²ΠΈΠ΄
makeNameAndTypeNodes(originalName, originalType || level);
restoreItemView(nameContainer, item, originalName, originalType || level);
}
};

const handleCancel = () => {
// Восстановим исходный Π²ΠΈΠ΄
makeNameAndTypeNodes(originalName, originalType || level);
restoreItemView(nameContainer, item, originalName, originalType || level);
};

saveBtn.addEventListener('click', (e) => { e.preventDefault(); handleSave(); });
Expand Down