Список списков сохранения проектов JSJavascript

Форум по Javascript
Ответить
Anonymous
 Список списков сохранения проектов JS

Сообщение Anonymous »

Мне нужна помощь с моим файлом JavaScript в моем проекте «To Do Do Do», я думал, что смогу справиться с этим, но есть слишком много, чтобы подумать в этом типе проекта, и я перегружен, если кто -то сможет помочь с логикой сохранения списка, и я пришлю подробности того, что я хотел бы реализовать.
Project Repo: https://github.com/dudek10/to-do-list-advanced-project
Я пытался реализовать логику переименования каждого списка, но он стал слишком сложным, и я не хочу испортить вещи еще больше, я добавлю, отправляю файл JS:
let tasks = [];

// Constants LocalStorage keys
const TASKS_KEY = 'tasks';
const CONTAINER_KEY = 'containerOpenState';
const TASK_INPUT_KEY = 'taskInputDraft';
const SAVED_LISTS_KEY = 'SavedLists';
const SAVE_LIMIT = 5;

// Constants for functions like 'addTask()' etc.
const tasksDiv = document.getElementById("tasks");
const input = document.getElementById("TaskInput");
const addTaskButton = document.getElementById("AddTaskButton");

//main DOM content
document.addEventListener('DOMContentLoaded', () => {

// the list cotainer logic
const OpenListBtn = document.getElementById("OpenList");
const DeleteAllTaskBtn = document.getElementById("TaskDelete");
const NameForm = document.querySelector(".name-form");
const Container = document.querySelector(".container");
const SaveBtn = document.querySelector(".save-button");
const IconClose = document.querySelector(".icon-close");

// Checks whether container is open
const savedState = localStorage.getItem(CONTAINER_KEY);
if (Container && NameForm && SaveBtn) {
if (savedState === 'open') {
Container.classList.add('visible');
NameForm.classList.add('visible');
SaveBtn.classList.add('visible');
} else {
Container.classList.remove('visible');
NameForm.classList.remove('visible');
SaveBtn.classList.remove('visible');
}
}

// Opens the list and sets the state to local storage
if (OpenListBtn && Container && NameForm && SaveBtn) {
OpenListBtn.addEventListener('click', () => {
Container.classList.add('visible');
NameForm.classList.add('visible');
SaveBtn.classList.add('visible');
localStorage.setItem(CONTAINER_KEY, 'open');

});
}
if (IconClose && Container && NameForm && SaveBtn) {
IconClose.addEventListener('click', () => {
Container.classList.remove('visible');
NameForm.classList.remove('visible');
SaveBtn.classList.remove('visible');
localStorage.setItem(CONTAINER_KEY, 'closed');
});
}

// draft input retrieve
const draft = localStorage.getItem(TASK_INPUT_KEY);
if (draft !== null) input.value = draft;

input.addEventListener('input', () => {
localStorage.setItem(TASK_INPUT_KEY, input.value);
});

// Load tasks on startup
loadTasks();

renderSavedListsDropdown();

// Saved list logic
const SavedListBtn = document.getElementById("SavedLists");
const SavedListsDropdown = document.querySelector('.saved-lists-dropdown');
const ListSavingBtn = document.querySelector('.save-button');

// Toggle dropdown visibility when clicking SavedLists button
SavedListBtn.addEventListener('click', (e) => {
e.stopPropagation();
SavedListsDropdown.classList.toggle('show');
});

// Save the current tasks under the typed name
ListSavingBtn.addEventListener('click', () => {
//first we declare the things we want to save

const nameInput = document.getElementById("NameBtn");
const name = (nameInput?.value || '').trim();
if (!name) return; // don’t save if no name
if (tasks.length === 0) return;

//makes a map of all the elements
const map = getSavedListsMap();

//sets a variable for the names and then checks their number
const existingNames = Object.keys(map);
if (!map[name] && existingNames.length >= SAVE_LIMIT) {

return;
}

map[name] = [...tasks]; // store a copy of tasks under given name
localStorage.setItem(SAVED_LISTS_KEY, JSON.stringify(map));

//render the saved lists
renderSavedListsDropdown();
SavedListsDropdown.classList.add('show');
})

// Load a saved list when clicking its button in the dropdown
SavedListsDropdown.addEventListener('click', (e) => {
const btn = e.target.closest('.saved-list-button');
if (!btn) return;
const name = btn.dataset.name;
const map = getSavedListsMap();

// Show the list and fill the name field
document.getElementById('NameBtn').value = name;
tasks = map[name] ? [...map[name]] : [];

Container.classList.add('visible');
NameForm.classList.add('visible');
SaveBtn.classList.add('visible');

renderTasks(); // render loaded tasks
});

// Close dropdown when clicking outside
document.addEventListener('click', (e) => {
if (!SavedListBtn.contains(e.target) && !SavedListsDropdown.contains(e.target)) {
SavedListsDropdown.classList.remove('show');
}
});

// mobile toogle button for nav menu
const toggleBtn = document.querySelector('.ToggleBtn');
const dropdownMenu = document.querySelector('.DropdownMenu');
const toggleBtnIcon = toggleBtn?.querySelector('i');
let isOpen = false;

// on button click change its icon to appropriate one
if (toggleBtn && dropdownMenu && toggleBtnIcon) {
toggleBtn.addEventListener('click', (e) => {
e.stopPropagation();

if (!isOpen) {
dropdownMenu.classList.add('show');
dropdownMenu.classList.remove('hide');
toggleBtnIcon.className = 'fa-solid fa-xmark';
} else {
dropdownMenu.classList.add('hide');
dropdownMenu.classList.remove('show');
toggleBtnIcon.className = 'fa-solid fa-bars';
}
isOpen = !isOpen;
});
}

// Delete all tasks
if (DeleteAllTaskBtn) {
DeleteAllTaskBtn.addEventListener('click', () => {
const items = tasksDiv.querySelectorAll('.task');
if (items.length === 0) return;

let remaining = items.length;

items.forEach((el, i) => {
// set delay for each item
el.style.transitionDelay = `${i * 0.3}s`;

el.classList.add('erasing');
el.addEventListener('transitionend', () => {
remaining--;
if (remaining === 0) {
tasks.length = 0;
renderTasks();
saveTasks();
}
}, { once: true }); // the transition listener will only run once (the css have two transitions so it would double the iteration number)
});
});

}

// Add task event
addTaskButton.addEventListener('click', addTask);

});

//helper for saved lists
function getSavedListsMap() {
try {
return JSON.parse(localStorage.getItem(SAVED_LISTS_KEY)) || {};
} catch {
return {};
}

}

function renderSavedListsDropdown() {
const SavedListsDropdown = document.querySelector('.saved-lists-dropdown');
const map = getSavedListsMap();
SavedListsDropdown.innerHTML = ''; //clears the template buttons
Object.keys(map).forEach(name => {
const btn = document.createElement('button');
btn.className = 'saved-list-button';
btn.textContent = name;
btn.dataset.name = name;
SavedListsDropdown.appendChild(btn);
})
}

//tasks persistence
function loadTasks() {
const oldTasks = localStorage.getItem(TASKS_KEY);
if (oldTasks) {
tasks = JSON.parse(oldTasks);
renderTasks();
}
}

function saveTasks() {
localStorage.setItem(TASKS_KEY, JSON.stringify(tasks));
}

// tasks allingment and style
function renderTasks() {
tasksDiv.innerHTML = "";
tasks.forEach((task, idx) => {
const div = document.createElement('div');
div.classList.add('task');
div.style.marginBottom = '10px';

const text = document.createElement('p');
text.textContent = task;
Object.assign(text.style, {
display: 'inline',
marginRight: '10px',
fontWeight: 'bold',
fontSize: '1.3rem'
});

const button = document.createElement('button');
button.innerHTML = '';
Object.assign(button.style, {
backgroundColor: '#2F1E2E',
color: '#ffffff',
border: 'none',
fontSize: '1.5rem',
cursor: 'pointer',
padding: '6px 8px',
borderRadius: '8px',
display: 'inline-flex',
alignItems: 'center',
justifyContent: 'center',
height: '1.9rem'
});

button.addEventListener('mouseenter', () => button.style.backgroundColor = '#3C2E3B');
button.addEventListener('mouseleave', () => button.style.backgroundColor = '#2F1E2E');

// Trigger CSS animation and remove the task after the transition end
button.onclick = () => {
div.classList.add('erasing');
div.addEventListener('transitionend', () => {
removeTask(idx);
}, { once: true }); // same case as for the delete all tasks button
};

div.appendChild(text);
div.appendChild(button);
tasksDiv.appendChild(div);
});
}

function addTask() {
const value = input.value.trim();
const OriginalPlaceholder = input.placeholder;

// Helper: show placeholder error messages briefly
const ShowPlaceholderWarning = (msg) => {
input.value = "";
input.placeholder = msg;

// clear previous timer
if (input._phTimer) clearTimeout(input._phTimer);

// Restore original placeholder when user is typing
const onType = () => {
input.placeholder = OriginalPlaceholder;
input.removeEventListener('input', onType);
if (input._phTimer) {
clearTimeout(input._phTimer);
input._phTimer = null;
}
};

input.addEventListener('input', onType, { once: true });

//restore after 2s
input._phTimer = setTimeout(() => {
input.placeholder = OriginalPlaceholder;
input.removeEventListener('input', onType);
input._phTimer = null;
}, 2000);
};

// validations
if (!/^[a-zA-Z0-9 ]*$/.test(value)) return ShowPlaceholderWarning("Task contains invalid characters!");
if (!value) return ShowPlaceholderWarning("Please enter a task!");
if (value.length > 45) return ShowPlaceholderWarning("Task exceeds 45 characters!");
if (tasks.includes(value)) return ShowPlaceholderWarning("Task already exists!");
if (tasks.length >= 9) return ShowPlaceholderWarning("Maximum number of tasks reached");

tasks.push(value);
renderTasks();
input.value = "";
localStorage.removeItem(TASK_INPUT_KEY);
saveTasks();
}

function removeTask(idx) {
tasks.splice(idx, 1);
renderTasks();
saveTasks();

}

// input events
input.addEventListener('keyup', (event) => {
if (event.key === 'Enter') addTask();
});



Подробнее здесь: https://stackoverflow.com/questions/797 ... ists-logic
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Javascript»