generated from obsidianmd/obsidian-sample-plugin
-
-
Notifications
You must be signed in to change notification settings - Fork 246
/
Copy pathDateInstructions.ts
169 lines (146 loc) · 5.69 KB
/
DateInstructions.ts
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
import type { unitOfTime } from 'moment';
import type { AllTaskDateFields } from '../../DateTime/DateFieldTypes';
import { Task } from '../../Task/Task';
import { postponeMenuItemTitleFromDate, removeDateMenuItemTitleForField } from '../../DateTime/Postponer';
import { TasksDate } from '../../DateTime/TasksDate';
import type { TaskEditingInstruction } from './TaskEditingInstruction';
import { MenuDividerInstruction } from './MenuDividerInstruction';
/**
* An instruction to set a date field to an absolute date.
*
* See also {@link SetRelativeTaskDate} and {@link RemoveTaskDate}.
*/
export class SetTaskDate implements TaskEditingInstruction {
private readonly newDate: Date;
private readonly dateFieldToEdit;
private readonly displayName: string;
constructor(dateFieldToEdit: AllTaskDateFields, date: Date, displayName?: string) {
this.newDate = date;
this.dateFieldToEdit = dateFieldToEdit;
this.displayName = displayName ?? `Set Date: ${this.newDate.toDateString()}`;
}
public apply(task: Task): Task[] {
if (this.isCheckedForTask(task)) {
return [task];
} else {
return [
new Task({
...task,
[this.dateFieldToEdit]: window.moment(this.newDate),
}),
];
}
}
public instructionDisplayName(): string {
return this.displayName;
}
public isCheckedForTask(task: Task): boolean {
return task[this.dateFieldToEdit]?.isSame(window.moment(this.newDate)) || false;
}
}
/**
* An instruction to set a date field to a date relative to the current value, or
* relative to today, if there is no current value.
*
* See also {@link SetTaskDate} and {@link RemoveTaskDate}.
*/
export class SetRelativeTaskDate extends SetTaskDate {
constructor(
dateFieldToEdit: AllTaskDateFields,
taskDueToday: Task,
amount: number,
timeUnit: unitOfTime.DurationConstructor,
) {
const currentDate = taskDueToday[dateFieldToEdit] ?? window.moment();
const title = postponeMenuItemTitleFromDate(dateFieldToEdit, currentDate, amount, timeUnit);
const newDate = new TasksDate(window.moment(currentDate)).postpone(timeUnit, amount).toDate();
super(dateFieldToEdit, newDate, title);
}
}
/**
* An instruction to remove any value from a date field, if there is a current value.
*
* See also {@link SetTaskDate} and {@link SetRelativeTaskDate}.
*/
export class RemoveTaskDate implements TaskEditingInstruction {
private readonly dateFieldToEdit: AllTaskDateFields;
private readonly displayName: string;
constructor(dateFieldToEdit: AllTaskDateFields, task: Task) {
this.dateFieldToEdit = dateFieldToEdit;
this.displayName = removeDateMenuItemTitleForField(dateFieldToEdit, task);
}
apply(task: Task): Task[] {
// There's no point trying to remove an inferred scheduled date, as the next time
// Tasks starts up, it will infer the scheduled date again from the file name,
// which will be very confusing for users.
const fieldIsInferred = this.dateFieldToEdit === 'scheduledDate' && task.scheduledDateIsInferred;
const fieldIsAlreadyNull = task[this.dateFieldToEdit] === null;
if (fieldIsAlreadyNull || fieldIsInferred) {
return [task];
}
return [
new Task({
...task,
[this.dateFieldToEdit]: null,
}),
];
}
instructionDisplayName(): string {
return this.displayName;
}
isCheckedForTask(_task: Task): boolean {
return false;
}
}
/**
* For Starts, Scheduled, Due.
* @param field
* @param task
* @see allLifeCycleDateInstructions
*/
export function allHappensDateInstructions(field: AllTaskDateFields, task: Task) {
return allDateInstructions(task, field, 1);
}
/**
* For Done, Cancelled, Created.
* @param field
* @param task
* @see allHappensDateInstructions
*/
export function allLifeCycleDateInstructions(field: AllTaskDateFields, task: Task) {
return allDateInstructions(task, field, -1);
}
/**
* Add instructions to move a date either forwards or backwards
* @param task
* @param field
* @param factor - +1 means today or future dates; -1 = today or earlier dates.
*/
function allDateInstructions(task: Task, field: AllTaskDateFields, factor: number) {
const today = window.moment().startOf('day');
const todayAsDate = today.toDate();
const todayAsTasksDate = new TasksDate(today.clone());
return [
new SetTaskDate(field, todayAsDate, postponeMenuItemTitleFromDate(field, today, 0, 'days')),
// TODO Fix this confusing mixture of Date, Moment and TasksDate!!!
// Preferably convert everything to use TasksDate.
new SetTaskDate(
field,
todayAsTasksDate.postpone('day', factor).toDate(),
postponeMenuItemTitleFromDate(field, today, factor, 'day'),
),
new MenuDividerInstruction(),
new SetRelativeTaskDate(field, task, factor * 2, 'days'),
new SetRelativeTaskDate(field, task, factor * 3, 'days'),
new SetRelativeTaskDate(field, task, factor * 4, 'days'),
new SetRelativeTaskDate(field, task, factor * 5, 'days'),
new SetRelativeTaskDate(field, task, factor * 6, 'days'),
new MenuDividerInstruction(),
new SetRelativeTaskDate(field, task, factor, 'week'),
new SetRelativeTaskDate(field, task, factor * 2, 'weeks'),
new SetRelativeTaskDate(field, task, factor * 3, 'weeks'),
new SetRelativeTaskDate(field, task, factor, 'month'),
new MenuDividerInstruction(),
new RemoveTaskDate(field, task),
];
}