actualizaciones varias
This commit is contained in:
parent
3367d4ede7
commit
5a83a52e3f
|
|
@ -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();
|
||||
});
|
||||
|
|
@ -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>
|
||||
Loading…
Reference in New Issue