-
Notifications
You must be signed in to change notification settings - Fork 1
/
index.html
1491 lines (1176 loc) · 53.7 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%220.9em%22 font-size=%2290%22>🐠</text></svg>">
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>✔我的待办</title>
<style>
#calendarViewBtn {
width: 100%;
margin-top: 10px;
padding: 10px 15px;
background-color: #FF4351;
border-radius: 2px; /* 圆角效果 */
box-shadow: 0 0 0 2px black; /* 模拟 outline */
color: white;
border: none;
cursor: pointer;
text-align: center;
font-size: 16px;
font-family: sans-serif;
}
#calendarViewBtn:hover {
background-color: #ff7680; /* 和 + 按钮一样的悬停效果 */
}
.status {
font-size: 14px;
text-align: right;
padding-top: 10px;
}
body {
font-family: sans-serif;
max-width: 720px; /* 最大宽度 */
margin: 25px auto; /* 水平居中 */
padding: 0 20px; /* 内边距,防止内容紧贴边缘 */
}
.date-nav {
border-radius: 2px; /* 圆角效果 */
box-shadow: 0 0 0 2px black; /* 模拟 outline */
display: flex;
flex-direction: column; /* 垂直排列年份和日期导航 */
justify-content: space-between;
align-items: center;
padding: 10px;
background-color: #fec04e;
color: #221f1f;
}
.year-line {
font-weight: bold;
font-size: 12px;
align-self: baseline;
}
.date-line {
display: flex;
justify-content: space-between;
align-items: center;
width: 100%; /* 使箭头和日期导航居中分布 */
}
.arrow {
cursor: pointer;
font-size: 20px;
padding: 0 10px;
}
.days {
display: flex;
justify-content: space-between;
flex-grow: 1;
margin: 0 10px;
}
.day {
position: relative;
flex: 1;
text-align: center;
padding: 10px;
cursor: pointer;
transition: background-color 0.3s;
}
.todo-item:hover .todo-buttons, .todo-item.editing .todo-buttons {
display: inline-block;
}
.todo-buttons {
display: none;
}
.day:hover {
background-color: #ffda97;
border-radius: 6px;
color: #221f1f;
}
.active {
background-color: #ffda97;
font-weight: bold;
border-radius: 6px;
color: #221f1f;
}
.today {
font-weight: bold;
}
.badge {
position: absolute;
top: 5px;
right: 10px;
background-color: #FF4351;
color: white;
border-radius: 50%;
padding: 2px 6px;
font-size: 12px;
}
.todo-container {
margin-top: 20px;
padding-right: 20px;
padding-left: 20px;
background-color: #f9f9f9;
border-radius: 2px; /* 圆角效果 */
box-shadow: 0 0 0 2px black; /* 模拟 outline */
}
/* 新增样式以调整日期选择器的位置 */
.date-picker-container {
display: flex;
align-items: center;
margin-left: 10px; /* 调整间距 */
}
#datePicker {
display: none; /* 初始隐藏 */
/* margin-right: 10px; 按钮与日期选择器之间的间距 */
}
.todo-item {
display: flex;
align-items: center;
border-bottom: 1px solid #ccc;
justify-content: space-between;
}
.todo-checkbox {
width: 20px;
height: 20px;
cursor: pointer;
margin-right: 10px;
}
.todo-text {
flex-grow: 1;
color: #131315;
font-family: sans-serif;
font-size: 16px;
padding-top: 8px;
padding-right: 15px;
padding-bottom: 8px;
padding-left: 1px;
margin-right: 10px;
border: none;
outline: none;
background-color: #fff;
}
.todo-text[disabled] {
background-color: #f9f9f9;
}
.completed {
text-decoration: line-through;
color: #888;
}
.todo-buttons .delete-confirm {
background-color: #FF4351 ;
color: white;
border-color: #FF4351;
border: none;
background: #FF4351;
}
.todo-buttons button {
animation-name: glowing-primary;
border-color: #088ef0;
background: linear-gradient(#34a5f8, #088ef0);
color: #FFF;
margin: 2.5px;
border-style: solid;
border-width: 1px;
line-height: 25px;
border-radius: 4px;
text-align: center;
border: none;
}
.calendar-day.today {
background-color: #fffeaa; /* 今日的背景 */
color: black; /* 反色显示 */
font-size: 12px;
white-space: nowrap;
}
.calendar-nav {
display: flex;
justify-content: center; /* 中心对齐 */
align-items: center;
padding: 28px; /* 添加内边距 */
background-color: #fec04e;
border-radius: 2px; /* 圆角效果 */
box-shadow: 0 0 0 2px black; /* 模拟 outline */
color: #221f1f;
font-weight: bold;
}
.calendar-header {
display: grid;
grid-template-columns: repeat(7, 1fr);
text-align: center;
font-weight: bold;
padding-top: 28px;
padding-bottom: 28px;
}
.calendar-body {
display: grid;
grid-template-columns: repeat(7, 1fr); /* 七列 */
grid-template-rows: repeat(autofill, 1fr); /* 行自适应 */
height: auto;
gap: 10px; /* 可选,设置格子之间的间距 */
}
.calendar-day {
border: 1px solid #ddd;
padding: 10px;
position: relative;
font-size: 12px;
white-space: nowrap; /* 禁用换行 */
overflow: hidden; /* 隐藏溢出的内容 */
}
#addTodo {
width: 100%;
margin-top: 10px;
border-radius: 2px; /* 圆角效果 */
box-shadow: 0 0 0 2px black; /* 模拟 outline */
padding: 10px 15px;
background-color: #A5DE37;
color: black;
border: none;
cursor: pointer;
text-align: center;
font-size: 16px;
}
#addTodo:hover {
background-color: #b9e563
}
#config-modal {
display: none;
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
padding: 20px;
border-radius: 2px; /* 圆角效果 */
box-shadow: 0 0 0 2px black; /* 模拟 outline */
background-color: #fff;
/*box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.5);*/
width: 600px;
height: 336px; /* 固定高度为600px */
overflow: hidden; /* 防止内容溢出 */
}
#config-modal label {
display: block;
margin-top: 10px;
}
#config-modal .indented-section {
margin-left: 20px; /* 缩进20px */
}
#save-config {
position: absolute; /* 绝对定位 */
bottom: 6px; /* 距离底部10px */
left: 40%; /* 水平居中 */
transform: translateX(-50%); /* 通过平移来实现居中 */
padding: 10px 20px;
background-color: #A5DE37;
color: rgb(0, 0, 0);
border: none;
border-radius: 5px;
cursor: pointer;
font-size: 16px;
border-radius: 2px; /* 圆角效果 */
box-shadow: 0 0 0 2px black; /* 模拟 outline */
font-family: sans-serif;
}
#save-config:hover {
background-color: #b9e563;
}
#exitconfig {
position: absolute; /* 绝对定位 */
bottom: 6px; /* 距离底部10px */
left: 60%; /* 水平居中 */
transform: translateX(-50%); /* 通过平移来实现居中 */
padding: 10px 20px;
background-color: #FF4351;
color: rgb(0, 0, 0);
border: none;
border-radius: 5px;
cursor: pointer;
font-size: 16px;
border-radius: 2px; /* 圆角效果 */
box-shadow: 0 0 0 2px black; /* 模拟 outline */
font-family: sans-serif;
}
#exitconfig:hover {
background-color: #ff7680;
}
</style>
</head>
<body>
<!-- 设置部分 -->
<div id="config-modal">
<!-- Main options -->
<label>ℹ️ Ctrl + / 显示帮助信息</label>
<label><input type="checkbox" id="md-export"> 启用md文件导出(快捷键 Ctrl + . 下载md文件)</label>
<label><input type="checkbox" id="new-tab-export"> 启用新标签页导出(快捷键 Ctrl + . 打开新标签页)</label>
<label><input type="checkbox" id="gist-sync"> 启用Gist上传下载(手动上传快捷键 Ctrl + . 手动下载快捷键 Ctrl + Shift + . )</label>
<div id="gist-options" style="display: none;">
<div class="indented-section">
在<a href="https://gist.github.com/">这里</a>创建一个Secret Gist,在<a href="https://github.com/settings/tokens/new">这里</a>创建一个令牌(只用给Gist权限)
<label>
Gist_地址:
<input type="text" style="height: auto;width: 290px;"" id="gist-url" placeholder="https://api.github.com/gists/xxxxxxxxxx">
</label>
<label>
Gist_Token:
<input type="text" style="height: auto;width: 280px;" id="gist-token" placeholder="ghp_xxxxxxxxxx">
</label>
<label><input type="checkbox" id="auto-upload"> 启用自动Gist上传(在新设备使用时请先启用Gist上传下载并按下 Ctrl + Shift + . 手动下载Gist内容,避免覆盖线上内容)</label>
<div class="indented-section">
<div id="gist-options2" style="display: none;">
<label>
自动上传间隔(分钟):
<input type="number" style="height: auto;width: 50px;" id="upload-interval" min="600" placeholder=">=5">
</label>
</div>
</div>
</div>
</div>
<!-- Conditional options for gist sync -->
<!-- Save and exit button -->
<button id="save-config">保存并退出</button>
<button id="exitconfig">退出</button>
</div>
<!-- 日期导航部分 -->
<div class="date-nav">
<div id="yearDisplay" class="year-line"></div> <!-- 显示年份的第一行 -->
<div class="date-line">
<span class="arrow" id="prevDay"><</span>
<div class="days" id="daysContainer">
<!-- 日期将会动态生成 -->
</div>
<span class="arrow" id="nextDay">></span>
</div>
</div>
<!-- 待办列表部分 -->
<div class="todo-container" id="todoContainer">
<!-- 待办事项将会在这里生成 -->
</div>
<!-- 日历视图部分 -->
<div id="calendarView" style="display: none;">
<div class="calendar-nav">
<span class="arrow" id="prevMonth"><</span>
<span id="viewLabel">周视图</span>
<span class="arrow" id="nextMonth">></span>
</div>
<div class="calendar-header">
<span>周一</span>
<span>周二</span>
<span>周三</span>
<span>周四</span>
<span>周五</span>
<span>周六</span>
<span>周日</span>
</div>
<div class="calendar-body" id="calendarBody">
<!-- 日历天数将会动态生成 -->
</div>
</div>
<button id="chooseDateBtn" style="display: none;">选择日期</button>
<input type="date" id="datePicker" style="display: none;">
<button id="addTodo">➕</button>
<button id="calendarViewBtn">📅日历视图</button>
<div id="upload-status" class="status"></div>
<script>
//var gistUrl = 'https://api.github.com/gists/xxxxxxxxxx'; // 替换为你的 Gist URL,在这里创建一个secret gist: https://gist.github.com/
//var token = 'ghp_xxxxxxxxxx'; // 替换为你的 GitHub 访问令牌,在这里创建一个令牌,只用给gist权限:https://github.com/settings/tokens/new
//var backuptab = false; // 设置新标签页文本显示开关
//var backupgist = false // 设置gist备份开关
//var backupgistcycle = 120000 // 设置gist自动备份间隔,毫秒单位,小于60秒将不启用自动gist备份
//var backupmd = false; // 设置md文件备份开关
// 获取元素
const chooseDateBtn = document.getElementById('chooseDateBtn');
const datePicker = document.getElementById('datePicker');
let editingTodoId = null; // 用于保存当前正在编辑的待办项的ID
// 日期选择按钮事件,点击后弹出日期选择器
chooseDateBtn.addEventListener('click', () => {
if (editingTodoId !== null) {
const todo = todosByDate[currentSelectedDate].find(todo => todo.id === editingTodoId);
if (todo) {
if (todo) {
// 显示日期选择器并设置默认值为当前待办事项的日期
datePicker.value = currentSelectedDate;
datePicker.style.display = 'inline-block';
//datePicker.focus(); // 使日期选择器自动获得焦点
}
}
}
});
// 监听用户选择日期的事件
datePicker.addEventListener('change', (event) => {
const selectedDate = event.target.value;
if (selectedDate && editingTodoId !== null) {
updateTodoDate(editingTodoId, selectedDate);
}
datePicker.style.display = 'none';
});
let currentDate = new Date(); // 当前显示的开始日期
const daysContainer = document.getElementById("daysContainer");
let todosByDate = {};
const todoContainer = document.getElementById('todoContainer');
const addTodoBtn = document.getElementById('addTodo');
let currentSelectedDate = formatDate(currentDate); // 初始日期
let draggedTodo = null; // 存储被拖动的待办信息
function loadTodos() {
const storedData = localStorage.getItem('todosByDate');
if (storedData) {
todosByDate = JSON.parse(storedData);
}
}
function saveTodos() {
const todosToSave = {};
let hasValidTodos = false; // 用于跟踪是否存在有效的 todos
for (const date in todosByDate) {
// 过滤掉空文本的 todos
const validTodos = todosByDate[date].filter(todo => todo.text.trim() !== '');
if (validTodos.length > 0) {
hasValidTodos = true; // 如果有有效的 todos,则标记为 true
todosToSave[date] = validTodos.map(todo => ({
id: todo.id,
text: todo.text,
completed: todo.completed
// 不再保存 editing 和 deleteConfirmed
}));
}
}
// 只有在有有效 todos 的情况下才保存到 localStorage
if (hasValidTodos) {
localStorage.setItem('todosByDate', JSON.stringify(todosToSave));
} else {
// 如果没有有效的 todos,则清空 localStorage
localStorage.removeItem('todosByDate');
}
}
function formatDate(date) {
const offsetDate = new Date(date.getTime() + (8 * 60 * 60 * 1000)); // Offset for GMT+8
return offsetDate.toISOString().split('T')[0]; // 返回 YYYY-MM-DD 格式
}
// 生成7天的日期显示 (始终以周一为开始)
function updateDays() {
daysContainer.innerHTML = '';
// 设置年份显示
const yearDisplay = document.getElementById("yearDisplay");
yearDisplay.textContent = "🧭"+currentDate.getFullYear(); // 获取当前显示年份并更新
const dayOfWeek = ['周日', '周一', '周二', '周三', '周四', '周五', '周六'];
let tempDate = new Date(currentDate);
const dayOffset = tempDate.getDay() === 0 ? 6 : tempDate.getDay() - 1;
tempDate.setDate(tempDate.getDate() - dayOffset); // 回到周一
for (let i = 0; i < 7; i++) {
const dayDiv = document.createElement('div');
dayDiv.className = 'day';
const formattedDate = formatDate(tempDate);
dayDiv.innerHTML = `${dayOfWeek[tempDate.getDay()]}<br>${tempDate.getMonth() + 1}-${tempDate.getDate()}`;
dayDiv.setAttribute("data-date", formattedDate);
const pendingTodos = (todosByDate[formattedDate] || []).filter(todo => !todo.completed).length;
if (pendingTodos > 0) {
const badge = document.createElement('span');
badge.className = 'badge';
badge.textContent = pendingTodos;
dayDiv.appendChild(badge);
}
dayDiv.addEventListener('dragover', (e) => e.preventDefault());
dayDiv.addEventListener('drop', (e) => handleDrop(e, formattedDate));
dayDiv.addEventListener('click', (e) => {
const selectedDate = e.target.getAttribute("data-date");
Array.from(daysContainer.children).forEach(d => d.classList.remove('active'));
e.target.classList.add('active');
showTodoList(selectedDate);
});
// 重新检查今天日期的标记
if (formattedDate === formatDate(new Date())) {
dayDiv.classList.add('today');
}
// 确保新选择的日期高亮显示
if (formattedDate === currentSelectedDate) {
dayDiv.classList.add('active');
}
daysContainer.appendChild(dayDiv);
tempDate.setDate(tempDate.getDate() + 1);
}
}
function showTodoList(date) {
currentSelectedDate = date;
renderTodoList();
}
function renderTodoList() {
todoContainer.innerHTML = '';
const todos = todosByDate[currentSelectedDate] || [];
const uncompletedTodos = todos.filter(todo => !todo.completed);
const completedTodos = todos.filter(todo => todo.completed);
uncompletedTodos.forEach(todo => createTodoElement(todo));
completedTodos.forEach(todo => createTodoElement(todo));
// 聚焦到最后一个新增的或正在编辑的待办
const editingTodo = todos.find(todo => todo.editing);
if (editingTodo) {
const inputField = Array.from(todoContainer.children).find(item => item.querySelector('.todo-text').value === editingTodo.text);
if (inputField) {
inputField.querySelector('.todo-text').focus();
}
} else {
const lastTodo = Array.from(todoContainer.children).slice(-1)[0];
if (lastTodo) {
lastTodo.querySelector('.todo-text').focus();
}
}
updateDays();
saveTodos();
}
function createTodoElement(todo) {
const todoElement = document.createElement('div');
todoElement.className = 'todo-item';
todoElement.setAttribute('draggable', true);
todoElement.addEventListener('dragstart', () => handleDragStart(todo));
const checkbox = document.createElement('input');
checkbox.type = 'checkbox';
checkbox.className = 'todo-checkbox';
checkbox.checked = todo.completed;
checkbox.addEventListener('click', () => toggleComplete(todo.id));
todoElement.appendChild(checkbox);
const input = document.createElement('input');
input.type = 'text';
input.className = 'todo-text';
input.value = todo.text;
input.disabled = !todo.editing;
if (todo.completed) input.classList.add('completed');
input.addEventListener('dblclick', () => editTodoText(todo.id)); // 双击进入编辑模式
todoElement.appendChild(input);
const buttonContainer = document.createElement('div');
buttonContainer.className = 'todo-buttons';
if (todo.editing) {
todoElement.classList.add('editing');
todoElement.setAttribute('draggable', false);
// 创建选择日期按钮
const chooseDateBtn = document.createElement('button');
chooseDateBtn.textContent = '选择日期';
// 新增日期选择器容器
const datePickerContainer = document.createElement('div');
datePickerContainer.className = 'date-picker-container';
// 选择日期按钮的点击事件
chooseDateBtn.addEventListener('click', () => {
// 显示日期选择器并设置默认值为当前待办事项的日期
datePicker.value = currentSelectedDate; // 使用当前选定的日期
datePicker.style.display = 'inline-block'; // 显示日期选择器
//datePicker.focus(); // 聚焦到日期选择器
chooseDateBtn.style.display = 'none';
// 遍历所有按钮,查找文本为“确定”的按钮
const buttons = document.querySelectorAll('button');
buttons.forEach(button => {
if (button.textContent.trim() === '确定' || button.textContent.trim() === '删除') {
button.style.display = 'none';
}
});
});
// 将日期选择器和按钮添加到容器中
datePickerContainer.appendChild(datePicker);
datePickerContainer.appendChild(chooseDateBtn);
buttonContainer.appendChild(datePickerContainer);
const saveBtn = document.createElement('button');
saveBtn.textContent = '确定';
saveBtn.addEventListener('click', () => saveTodoText(todo.id, input.value));
buttonContainer.appendChild(saveBtn);
input.addEventListener('keydown', (event) => {
if (event.key === 'Enter') {
saveTodoText(todo.id, input.value);
}
});
input.focus(); // 自动聚焦
} else {
const editBtn = document.createElement('button');
editBtn.textContent = '编辑';
editBtn.addEventListener('click', () => {
editTodoText(todo.id);
input.focus(); // 编辑时自动聚焦到输入框
});
datePicker.addEventListener('change', (event) => {
const selectedDate = event.target.value;
if (selectedDate && editingTodoId !== null) {
updateTodoDate(editingTodoId, selectedDate); // 更新待办事项的日期
}
datePicker.style.display = 'none'; // 隐藏日期选择器
});
buttonContainer.appendChild(editBtn);
}
const deleteBtn = document.createElement('button');
deleteBtn.textContent = todo.deleteConfirmed ? '确认删除' : '删除';
datePicker.style.display = 'none';
deleteBtn.classList.toggle('delete-confirm', todo.deleteConfirmed);
deleteBtn.addEventListener('click', () => {
confirmDelete(todo.id);
const buttons = document.querySelectorAll('button');
// 遍历所有按钮,查找文本为“确定”的按钮
buttons.forEach(button => {
if (button.textContent.trim() === '选择日期') {
button.style.display = 'none';
}
});
});
// 添加 mouseenter 和 mouseleave 事件监听器
deleteBtn.addEventListener('mouseenter', () => {
if (todo.deleteConfirmed) {
deleteBtn.textContent = '确认删除'; // 鼠标悬停时保持确认删除
}
});
deleteBtn.addEventListener('mouseleave', () => {
deleteBtn.textContent = '删除'; // 鼠标移开时恢复文本
todo.deleteConfirmed=false;
});
buttonContainer.appendChild(deleteBtn);
todoElement.appendChild(buttonContainer);
todoContainer.appendChild(todoElement);
}
function handleDragStart(todo) {
const currentDateElement = document.querySelector('.calendar-day.active'); // 获取当前选中日期的元素
const currentDate = currentDateElement ? currentDateElement.getAttribute('data-date') : currentSelectedDate; // 获取当前选中日期
draggedTodo = { ...todo, sourceDate: currentDate }; // 将当前日期设置为源日期
}
function handleDrop(event, targetDate) {
event.preventDefault(); // 防止默认行为
if (draggedTodo) {
// 从原日期中删除
todosByDate[draggedTodo.sourceDate] = todosByDate[draggedTodo.sourceDate].filter(todo => todo.id !== draggedTodo.id);
// 添加到目标日期
todosByDate[targetDate] = todosByDate[targetDate] || [];
todosByDate[targetDate].push(draggedTodo);
// 更新当前选中日期的待办列表
if (currentSelectedDate === draggedTodo.sourceDate || currentSelectedDate === targetDate) {
renderTodoList();
}
draggedTodo = null; // 清空被拖动的待办信息
saveTodos();
updateDays();
renderCalendar(); // 重新渲染日历
}
}
function addNewTodo() {
const newTodo = {
id: Date.now(),
text: '',
completed: false,
editing: true,
deleteConfirmed: false
};
// 不将空的新增待办存储
todosByDate[currentSelectedDate] = todosByDate[currentSelectedDate] || [];
todosByDate[currentSelectedDate].push(newTodo);
datePicker.style.display = 'none';
renderTodoList();
const inputFields = document.querySelectorAll('.todo-text');
inputFields[inputFields.length - 1].focus(); // 光标自动聚焦
const buttons = document.querySelectorAll('button');
// 遍历所有按钮,查找文本为“确定”的按钮
buttons.forEach(button => {
if (button.textContent.trim() === '选择日期') {
button.style.display = 'none';
}
});
}
function toggleComplete(id) {
todosByDate[currentSelectedDate] = todosByDate[currentSelectedDate].map(todo => {
if (todo.id === id) {
todo.completed = !todo.completed;
}
return todo;
});
renderTodoList();
}
function saveTodoText(id, newText) {
todosByDate[currentSelectedDate] = todosByDate[currentSelectedDate].map(todo => {
if (todo.id === id) {
if (!newText.trim()) {
return null; // 如果文本为空,则删除待办
}
todo.text = newText;
// 不再保存 editing 状态
todo.editing = false;
}
return todo;
}).filter(todo => todo !== null); // 过滤掉空文本的待办
renderTodoList();
chooseDateBtn.style.display = 'none'; // 隐藏 "选择日期" 按钮
editingTodoId = null; // 清空编辑中的ID
}
function editTodoText(id) {
todosByDate[currentSelectedDate] = todosByDate[currentSelectedDate].map(todo => {
if (todo.id === id) {
todo.editing = true;
editingTodoId = id; // 保存正在编辑的待办ID
}
return todo;
});
chooseDateBtn.style.display = 'none'; // 显示 "选择日期" 按钮
renderTodoList();
}
function updateTodoDate(id, newDate) {
// 从当前日期移除该待办事项
const todo = todosByDate[currentSelectedDate].find(todo => todo.id === id);
if (todo) {
// 从当前日期移除该待办事项
todosByDate[currentSelectedDate] = todosByDate[currentSelectedDate].filter(todo => todo.id !== id);
// 将待办事项添加到新日期
todosByDate[newDate] = todosByDate[newDate] || [];
todosByDate[newDate].push(todo);
currentSelectedDate = newDate; // 更新当前选中的日期
// 检查新日期是否在当前周内
const selectedDateObj = new Date(newDate);
const startOfWeek = new Date(currentDate);
const dayOffset = startOfWeek.getDay() === 0 ? 6 : startOfWeek.getDay() - 1;
startOfWeek.setDate(startOfWeek.getDate() - dayOffset); // 当前周的起始日期
const endOfWeek = new Date(startOfWeek);
endOfWeek.setDate(endOfWeek.getDate() + 6); // 当前周的结束日期
if (selectedDateObj < startOfWeek || selectedDateObj > endOfWeek) {
// 如果新日期不在当前显示的周内,更新currentDate为新日期所在周的起始
currentDate = new Date(selectedDateObj);
currentDate.setDate(currentDate.getDate() - (currentDate.getDay() === 0 ? 6 : currentDate.getDay() - 1));
}
updateDays();
renderTodoList();
const buttons = document.querySelectorAll('button');
// 遍历所有按钮,查找文本为“确定”的按钮
buttons.forEach(button => {
if (button.textContent.trim() === '确定') {
button.click(); // 点击按钮
}
});
}
chooseDateBtn.style.display = 'none'; // 隐藏 "选择日期" 按钮
editingTodoId = null; // 清空编辑中的ID
}
function confirmDelete(id) {
todosByDate[currentSelectedDate] = todosByDate[currentSelectedDate].map(todo => {
if (todo.id === id) {
if (todo.deleteConfirmed) {
return null;
}
todo.deleteConfirmed = true;
}
return todo;
}).filter(todo => todo !== null);
renderTodoList();
}
document.getElementById("prevDay").addEventListener('click', () => {
currentDate.setDate(currentDate.getDate() - 7);
updateDays();
});
document.getElementById("nextDay").addEventListener('click', () => {
currentDate.setDate(currentDate.getDate() + 7);
updateDays();
});
addTodoBtn.addEventListener('click', addNewTodo);
function moveUncompletedTodosToToday() {
const today = formatDate(new Date());
for (let date in todosByDate) {
if (date < today) {
const uncompletedTodos = todosByDate[date].filter(todo => !todo.completed);
if (uncompletedTodos.length > 0) {
todosByDate[today] = (todosByDate[today] || []).concat(uncompletedTodos);
todosByDate[date] = todosByDate[date].filter(todo => todo.completed);
}
}
}
}
loadTodos();
moveUncompletedTodosToToday();
updateDays();
renderTodoList();
let isCalendarView = false; // 跟踪是否在日历视图中
const calendarViewBtn = document.getElementById("calendarViewBtn");
const calendarBody = document.getElementById("calendarBody");
const viewLabel = document.getElementById("viewLabel");
calendarViewBtn.addEventListener('click', toggleCalendarView);
document.getElementById("prevMonth").addEventListener('click', () => changeMonth(-1));
document.getElementById("nextMonth").addEventListener('click', () => changeMonth(1));
function toggleCalendarView() {
isCalendarView = !isCalendarView;
document.getElementById("todoContainer").style.display = isCalendarView ? 'none' : 'block';
document.getElementById("calendarView").style.display = isCalendarView ? 'block' : 'none';
// 控制日期导航的显示与隐藏
document.querySelector('.date-nav').style.display = isCalendarView ? 'none' : 'flex';
calendarViewBtn.textContent = isCalendarView ? '🕔️周视图' : '📅日历视图';
const addTodoButton = document.getElementById("addTodo");
addTodoButton.style.display = isCalendarView ? 'none' : 'block';
if (isCalendarView) {
renderCalendar();
}
if (!isCalendarView) {
//location.reload(); // Reloads the current page
currentSelectedDate = formatDate(currentDate); // 设置当前选中日期为当前日期
updateDays();
renderTodoList()
//renderTodoList(); 渲染待办事项列表
//renderCalendar();
}
}
let currentMonth = new Date(); // 当前显示的月份
function changeMonth(direction) {
currentMonth.setMonth(currentMonth.getMonth() + direction);
renderCalendar();
}
function updateViewLabel(year, month) {
const viewLabel = document.getElementById("viewLabel");
viewLabel.textContent = `${year}年${month}月`;
}