actualizaciones varias

This commit is contained in:
Tatiana Villa Ema 2026-06-15 19:40:30 +02:00
parent 3367d4ede7
commit 5a83a52e3f
2 changed files with 277 additions and 281 deletions

View File

@ -0,0 +1,275 @@
class PlanningCalendar {
constructor() {
this.currentDate = new Date();
this.tasks = this.loadTasks();
this.draggedTask = null;
this.init();
}
init() {
this.setupEventListeners();
this.render();
}
setupEventListeners() {
document.getElementById('prevMonth').addEventListener('click', () => this.previousMonth());
document.getElementById('nextMonth').addEventListener('click', () => this.nextMonth());
document.getElementById('addTaskForm').addEventListener('submit', (e) => this.addTask(e));
document.getElementById('resetBtn').addEventListener('click', () => this.resetAll());
}
previousMonth() {
this.currentDate.setMonth(this.currentDate.getMonth() - 1);
this.render();
}
nextMonth() {
this.currentDate.setMonth(this.currentDate.getMonth() + 1);
this.render();
}
render() {
this.renderMonthTitle();
this.renderCalendar();
}
renderMonthTitle() {
const options = { month: 'long', year: 'numeric' };
const title = this.currentDate.toLocaleDateString('es-ES', options);
document.getElementById('monthTitle').textContent = title.charAt(0).toUpperCase() + title.slice(1);
}
renderCalendar() {
const grid = document.getElementById('calendarGrid');
grid.innerHTML = '';
// Encabezados de días
const dayNames = ['Lun', 'Mar', 'Mié', 'Jue', 'Vie', 'Sáb', 'Dom'];
dayNames.forEach(day => {
const header = document.createElement('div');
header.className = 'day-header';
header.textContent = day;
grid.appendChild(header);
});
// Obtener primer y último día del mes
const year = this.currentDate.getFullYear();
const month = this.currentDate.getMonth();
const firstDay = new Date(year, month, 1);
const lastDay = new Date(year, month + 1, 0);
// Ajustar para que lunes sea 0
let dayOfWeek = firstDay.getDay() - 1;
if (dayOfWeek === -1) dayOfWeek = 6;
// Días del mes anterior
const prevMonthLastDay = new Date(year, month, 0).getDate();
for (let i = dayOfWeek - 1; i >= 0; i--) {
const cell = this.createDayCell(prevMonthLastDay - i, 'other-month');
grid.appendChild(cell);
}
// Días del mes actual
for (let day = 1; day <= lastDay.getDate(); day++) {
const date = new Date(year, month, day);
const cell = this.createDayCell(day, '', date);
grid.appendChild(cell);
}
// Días del próximo mes
const remainingCells = grid.children.length - 7; // 7 headers
const totalCells = Math.ceil(remainingCells / 7) * 7;
for (let day = 1; day <= totalCells - remainingCells; day++) {
const cell = this.createDayCell(day, 'other-month');
grid.appendChild(cell);
}
}
createDayCell(day, extraClass, date = null) {
const cell = document.createElement('div');
cell.className = `day-cell ${extraClass}`;
if (extraClass === 'other-month') {
cell.classList.add('empty');
} else {
// Es día del mes actual
const isToday = date && this.isToday(date);
const isWeekend = date && (date.getDay() === 0 || date.getDay() === 6);
if (isToday) cell.classList.add('today');
if (isWeekend) cell.classList.add('weekend');
const dayNumber = document.createElement('div');
dayNumber.className = 'day-number' + (isWeekend ? ' weekend' : '');
dayNumber.textContent = day;
cell.appendChild(dayNumber);
const dateKey = this.getDateKey(date);
const dayTasks = this.tasks[dateKey] || [];
const tasksList = document.createElement('div');
tasksList.className = 'tasks-list';
dayTasks.forEach(task => {
const taskEl = this.createTaskElement(task, dateKey);
tasksList.appendChild(taskEl);
});
cell.appendChild(tasksList);
// Agregar zona de drop
const dropZone = document.createElement('div');
dropZone.className = 'drop-zone';
cell.appendChild(dropZone);
// Event listeners para drag & drop
cell.addEventListener('dragover', (e) => this.handleDragOver(e));
cell.addEventListener('drop', (e) => this.handleDrop(e, dateKey));
cell.addEventListener('dragleave', (e) => this.handleDragLeave(e));
}
return cell;
}
createTaskElement(task, dateKey) {
const taskEl = document.createElement('div');
taskEl.className = 'task-item';
taskEl.draggable = true;
taskEl.textContent = task.text;
const deleteBtn = document.createElement('button');
deleteBtn.type = 'button';
deleteBtn.className = 'task-delete-btn';
deleteBtn.textContent = '✕';
deleteBtn.addEventListener('click', (e) => {
e.stopPropagation();
this.deleteTask(task.id, dateKey);
});
taskEl.appendChild(deleteBtn);
taskEl.addEventListener('dragstart', (e) => this.handleDragStart(e, task.id, dateKey));
taskEl.addEventListener('dragend', (e) => this.handleDragEnd(e));
return taskEl;
}
handleDragStart(e, taskId, fromDateKey) {
this.draggedTask = { taskId, fromDateKey };
e.target.classList.add('dragging');
e.dataTransfer.effectAllowed = 'move';
}
handleDragEnd(e) {
e.target.classList.remove('dragging');
}
handleDragOver(e) {
e.preventDefault();
e.dataTransfer.dropEffect = 'move';
e.target.closest('.day-cell').classList.add('drag-over');
}
handleDragLeave(e) {
e.target.closest('.day-cell').classList.remove('drag-over');
}
handleDrop(e, toDateKey) {
e.preventDefault();
e.target.closest('.day-cell').classList.remove('drag-over');
if (!this.draggedTask) return;
const { taskId, fromDateKey } = this.draggedTask;
this.moveTask(taskId, fromDateKey, toDateKey);
this.draggedTask = null;
}
addTask(e) {
e.preventDefault();
const input = document.getElementById('taskInput');
const text = input.value.trim();
if (!text) return;
const today = this.getDateKey(new Date());
const task = {
id: Date.now(),
text: text,
date: today
};
if (!this.tasks[today]) {
this.tasks[today] = [];
}
this.tasks[today].push(task);
this.saveTasks();
input.value = '';
this.render();
}
deleteTask(taskId, dateKey) {
if (this.tasks[dateKey]) {
this.tasks[dateKey] = this.tasks[dateKey].filter(t => t.id !== taskId);
if (this.tasks[dateKey].length === 0) {
delete this.tasks[dateKey];
}
this.saveTasks();
this.render();
}
}
moveTask(taskId, fromDateKey, toDateKey) {
if (!this.tasks[fromDateKey]) return;
const taskIndex = this.tasks[fromDateKey].findIndex(t => t.id === taskId);
if (taskIndex === -1) return;
const task = this.tasks[fromDateKey][taskIndex];
this.tasks[fromDateKey].splice(taskIndex, 1);
if (this.tasks[fromDateKey].length === 0) {
delete this.tasks[fromDateKey];
}
if (!this.tasks[toDateKey]) {
this.tasks[toDateKey] = [];
}
this.tasks[toDateKey].push(task);
this.saveTasks();
this.render();
}
getDateKey(date) {
return date.toISOString().split('T')[0];
}
isToday(date) {
const today = new Date();
return date.toDateString() === today.toDateString();
}
saveTasks() {
localStorage.setItem('planningTasks', JSON.stringify(this.tasks));
}
loadTasks() {
const stored = localStorage.getItem('planningTasks');
return stored ? JSON.parse(stored) : {};
}
resetAll() {
if (confirm('¿Estás seguro de que deseas limpiar todas las tareas?')) {
this.tasks = {};
this.saveTasks();
this.render();
}
}
}
// Inicializar cuando el DOM esté listo
document.addEventListener('DOMContentLoaded', () => {
new PlanningCalendar();
});

View File

@ -5,6 +5,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Planning TAI — Agenda</title>
<link rel="stylesheet" th:href="@{/css/style.css}">
<link rel="stylesheet" th:href="@{/css/planning.css}">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.0/css/all.min.css">
</head>
<body>
@ -60,286 +61,6 @@
<div class="calendar-grid" id="calendarGrid"></div>
</div>
<script>
// ════════════════════════════════════════════════════════════════
// Planning Customizable - Calendario con Drag & Drop
// ════════════════════════════════════════════════════════════════
class PlanningCalendar {
constructor() {
this.currentDate = new Date();
this.tasks = this.loadTasks();
this.draggedTask = null;
this.init();
}
init() {
this.setupEventListeners();
this.render();
}
setupEventListeners() {
document.getElementById('prevMonth').addEventListener('click', () => this.previousMonth());
document.getElementById('nextMonth').addEventListener('click', () => this.nextMonth());
document.getElementById('addTaskForm').addEventListener('submit', (e) => this.addTask(e));
document.getElementById('resetBtn').addEventListener('click', () => this.resetAll());
}
previousMonth() {
this.currentDate.setMonth(this.currentDate.getMonth() - 1);
this.render();
}
nextMonth() {
this.currentDate.setMonth(this.currentDate.getMonth() + 1);
this.render();
}
render() {
this.renderMonthTitle();
this.renderCalendar();
}
renderMonthTitle() {
const options = { month: 'long', year: 'numeric' };
const title = this.currentDate.toLocaleDateString('es-ES', options);
document.getElementById('monthTitle').textContent = title.charAt(0).toUpperCase() + title.slice(1);
}
renderCalendar() {
const grid = document.getElementById('calendarGrid');
grid.innerHTML = '';
// Encabezados de días
const dayNames = ['Lun', 'Mar', 'Mié', 'Jue', 'Vie', 'Sáb', 'Dom'];
dayNames.forEach(day => {
const header = document.createElement('div');
header.className = 'day-header';
header.textContent = day;
grid.appendChild(header);
});
// Obtener primer y último día del mes
const year = this.currentDate.getFullYear();
const month = this.currentDate.getMonth();
const firstDay = new Date(year, month, 1);
const lastDay = new Date(year, month + 1, 0);
// Ajustar para que lunes sea 0
let dayOfWeek = firstDay.getDay() - 1;
if (dayOfWeek === -1) dayOfWeek = 6;
// Días del mes anterior
const prevMonthLastDay = new Date(year, month, 0).getDate();
for (let i = dayOfWeek - 1; i >= 0; i--) {
const cell = this.createDayCell(prevMonthLastDay - i, 'other-month');
grid.appendChild(cell);
}
// Días del mes actual
for (let day = 1; day <= lastDay.getDate(); day++) {
const date = new Date(year, month, day);
const cell = this.createDayCell(day, '', date);
grid.appendChild(cell);
}
// Días del próximo mes
const remainingCells = grid.children.length - 7; // 7 headers
const totalCells = Math.ceil(remainingCells / 7) * 7;
for (let day = 1; day <= totalCells - remainingCells; day++) {
const cell = this.createDayCell(day, 'other-month');
grid.appendChild(cell);
}
}
createDayCell(day, extraClass, date = null) {
const cell = document.createElement('div');
cell.className = `day-cell ${extraClass}`;
if (extraClass === 'other-month') {
cell.classList.add('empty');
} else {
// Es día del mes actual
const isToday = date && this.isToday(date);
const isWeekend = date && (date.getDay() === 0 || date.getDay() === 6);
if (isToday) cell.classList.add('today');
if (isWeekend) cell.classList.add('weekend');
const dayNumber = document.createElement('div');
dayNumber.className = 'day-number' + (isWeekend ? ' weekend' : '');
dayNumber.textContent = day;
cell.appendChild(dayNumber);
const dateKey = this.getDateKey(date);
const dayTasks = this.tasks[dateKey] || [];
const tasksList = document.createElement('div');
tasksList.className = 'tasks-list';
dayTasks.forEach(task => {
const taskEl = this.createTaskElement(task, dateKey);
tasksList.appendChild(taskEl);
});
cell.appendChild(tasksList);
// Agregar zona de drop
const dropZone = document.createElement('div');
dropZone.className = 'drop-zone';
cell.appendChild(dropZone);
// Event listeners para drag & drop
cell.addEventListener('dragover', (e) => this.handleDragOver(e));
cell.addEventListener('drop', (e) => this.handleDrop(e, dateKey));
cell.addEventListener('dragleave', (e) => this.handleDragLeave(e));
}
return cell;
}
createTaskElement(task, dateKey) {
const taskEl = document.createElement('div');
taskEl.className = 'task-item';
taskEl.draggable = true;
taskEl.textContent = task.text;
const deleteBtn = document.createElement('button');
deleteBtn.type = 'button';
deleteBtn.className = 'task-delete-btn';
deleteBtn.textContent = '✕';
deleteBtn.addEventListener('click', (e) => {
e.stopPropagation();
this.deleteTask(task.id, dateKey);
});
taskEl.appendChild(deleteBtn);
taskEl.addEventListener('dragstart', (e) => this.handleDragStart(e, task.id, dateKey));
taskEl.addEventListener('dragend', (e) => this.handleDragEnd(e));
return taskEl;
}
handleDragStart(e, taskId, fromDateKey) {
this.draggedTask = { taskId, fromDateKey };
e.target.classList.add('dragging');
e.dataTransfer.effectAllowed = 'move';
}
handleDragEnd(e) {
e.target.classList.remove('dragging');
}
handleDragOver(e) {
e.preventDefault();
e.dataTransfer.dropEffect = 'move';
e.target.closest('.day-cell').classList.add('drag-over');
}
handleDragLeave(e) {
e.target.closest('.day-cell').classList.remove('drag-over');
}
handleDrop(e, toDateKey) {
e.preventDefault();
e.target.closest('.day-cell').classList.remove('drag-over');
if (!this.draggedTask) return;
const { taskId, fromDateKey } = this.draggedTask;
this.moveTask(taskId, fromDateKey, toDateKey);
this.draggedTask = null;
}
addTask(e) {
e.preventDefault();
const input = document.getElementById('taskInput');
const text = input.value.trim();
if (!text) return;
const today = this.getDateKey(new Date());
const task = {
id: Date.now(),
text: text,
date: today
};
if (!this.tasks[today]) {
this.tasks[today] = [];
}
this.tasks[today].push(task);
this.saveTasks();
input.value = '';
this.render();
}
deleteTask(taskId, dateKey) {
if (this.tasks[dateKey]) {
this.tasks[dateKey] = this.tasks[dateKey].filter(t => t.id !== taskId);
if (this.tasks[dateKey].length === 0) {
delete this.tasks[dateKey];
}
this.saveTasks();
this.render();
}
}
moveTask(taskId, fromDateKey, toDateKey) {
if (!this.tasks[fromDateKey]) return;
const taskIndex = this.tasks[fromDateKey].findIndex(t => t.id === taskId);
if (taskIndex === -1) return;
const task = this.tasks[fromDateKey][taskIndex];
this.tasks[fromDateKey].splice(taskIndex, 1);
if (this.tasks[fromDateKey].length === 0) {
delete this.tasks[fromDateKey];
}
if (!this.tasks[toDateKey]) {
this.tasks[toDateKey] = [];
}
this.tasks[toDateKey].push(task);
this.saveTasks();
this.render();
}
getDateKey(date) {
return date.toISOString().split('T')[0];
}
isToday(date) {
const today = new Date();
return date.toDateString() === today.toDateString();
}
saveTasks() {
localStorage.setItem('planningTasks', JSON.stringify(this.tasks));
}
loadTasks() {
const stored = localStorage.getItem('planningTasks');
return stored ? JSON.parse(stored) : {};
}
resetAll() {
if (confirm('¿Estás seguro de que deseas limpiar todas las tareas?')) {
this.tasks = {};
this.saveTasks();
this.render();
}
}
}
// Inicializar cuando el DOM esté listo
document.addEventListener('DOMContentLoaded', () => {
new PlanningCalendar();
});
</script>
<script th:src="@{/js/planningdinamico.js}"></script>
</body>
</html>