var WEEKDAYS = ["Пн", "Вт", "Ср", "Чт", "Пт", "Сб", "Вс"];
var MONTHS = [
"Январь", "Февраль", "Март", "Апрель", "Май", "Июнь",
"Июль", "Август", "Сентябрь", "Октябрь", "Ноябрь", "Декабрь"
];
var now = new Date();
var view = { year: now.getFullYear(), month: now.getMonth() };
var openDate = null;
var allByDate = {};
var gridEl = document.getElementById("grid");
var monthNameEl = document.getElementById("monthName");
var panelBody = document.getElementById("panelBody");
var panelEmpty = document.getElementById("panelEmpty");
var panelDateEl = document.getElementById("panelDate");
var notesEl = document.getElementById("notes");
var countEl = document.getElementById("count");
function pad(n) { return (n < 10 ? "0" : "") + n; }
function fmt(d) {
return pad(d.getDate()) + "." + pad(d.getMonth() + 1) + "." + d.getFullYear();
}
function iso(date) {
return date.getFullYear() + "-" + pad(date.getMonth() + 1) + "-" + pad(date.getDate());
}
function escapeHtml(s) {
return String(s).replace(/[&<>"']/g, function (c) {
return { "&": "&", "<": "<", ">": ">", '"': """, "'": "'" }[c];
});
}
function renderWeekdays() {
document.getElementById("weekdays").innerHTML =
WEEKDAYS.map(function (w) { return "" + w + ""; }).join("");
}
function render() {
monthNameEl.textContent = MONTHS[view.month] + " " + view.year;
var first = new Date(view.year, view.month, 1);
var startPad = (first.getDay() + 6) % 7;
var daysInMonth = new Date(view.year, view.month + 1, 0).getDate();
var prevDays = new Date(view.year, view.month, 0).getDate();
var html = "";
for (var i = startPad - 1; i >= 0; i--) {
html += '
' + (prevDays - i) + "
";
}
for (var d = 1; d <= daysInMonth; d++) {
var date = new Date(view.year, view.month, d);
var key = iso(date);
var cls = "day";
var isToday =
date.getFullYear() === now.getFullYear() &&
date.getMonth() === now.getMonth() &&
date.getDate() === now.getDate();
if (isToday) cls += " today";
if (openDate === key) cls += " selected";
var has = (allByDate[key] || []).length > 0;
var dot = has ? '' : '';
html += '
' + d + dot + "
";
}
var endPad = 7 - ((startPad + daysInMonth) % 7);
if (endPad < 7) {
for (var j = 1; j <= endPad; j++) {
html += '
' + j + "
";
}
}
gridEl.innerHTML = html;
}
function changeMonth(delta) {
view.month += delta;
if (view.month < 0) { view.month = 11; view.year--; }
if (view.month > 11) { view.month = 0; view.year++; }
render();
}
function goToday() {
now = new Date();
view = { year: now.getFullYear(), month: now.getMonth() };
render();
}
function api(url, opts) {
return fetch(url, opts).then(function (r) {
if (!r.ok) throw new Error("Ошибка сервера " + r.status);
return r.json();
});
}
function loadAll() {
return api("/api/notes").then(function (list) {
allByDate = {};
list.forEach(function (n) {
(allByDate[n.date] = allByDate[n.date] || []).push(n);
});
render();
if (openDate) renderPanel();
});
}
function renderPanel() {
var list = allByDate[openDate] || [];
notesEl.innerHTML = list.map(function (n) {
return (
'
' +
'" +
'' + escapeHtml(n.text) + "" +
'' +
"
"
);
}).join("");
countEl.textContent = list.length ? "Дела: " + list.length : "";
}
function openDay(key) {
openDate = key;
panelEmpty.classList.add("hidden");
panelBody.classList.remove("hidden");
var parts = key.split("-");
var date = new Date(parts[0], +parts[1] - 1, +parts[2]);
panelDateEl.textContent = fmt(date);
render();
renderPanel();
}
function closePanel() {
openDate = null;
panelBody.classList.add("hidden");
panelEmpty.classList.remove("hidden");
render();
}
function addNote(text) {
return api("/api/notes", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ date: openDate, text: text })
}).then(loadAll);
}
function toggleNote(id, done) {
return api("/api/notes", {
method: "PATCH",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ id: id, done: done })
}).then(loadAll);
}
function deleteNote(id) {
return api("/api/notes/" + id, { method: "DELETE" }).then(loadAll);
}
gridEl.addEventListener("click", function (e) {
var day = e.target.closest(".day");
if (!day || day.classList.contains("empty")) return;
openDay(day.dataset.key);
});
notesEl.addEventListener("click", function (e) {
var li = e.target.closest(".note");
if (!li) return;
var id = +li.dataset.id;
var item = (allByDate[openDate] || []).find(function (n) { return n.id === id; });
if (!item) return;
if (e.target.classList.contains("del")) {
if (confirm("Удалить это дело?")) deleteNote(id);
return;
}
if (e.target.classList.contains("chk")) {
toggleNote(id, !item.done);
}
});
document.getElementById("addForm").addEventListener("submit", function (e) {
e.preventDefault();
var input = document.getElementById("noteText");
var text = input.value.trim();
if (!text || !openDate) return;
addNote(text);
input.value = "";
});
document.getElementById("prev").addEventListener("click", function () { changeMonth(-1); });
document.getElementById("next").addEventListener("click", function () { changeMonth(1); });
document.getElementById("today").addEventListener("click", goToday);
document.getElementById("closePanel").addEventListener("click", closePanel);
renderWeekdays();
render();
loadAll();