Repository navigation
Expand file tree
/
Copy pathplugin.js
More file actions
348 lines (287 loc) · 11.8 KB
/
Copy pathplugin.js
File metadata and controls
348 lines (287 loc) · 11.8 KB
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
const plugin = {
replaceText: {
"Tag tasks in batch": async function (app, text) {
try {
const tasks = await this._transformTextIntoTaskArray(app, text);
await this._batchTagTasks(app, tasks);
} catch (err) {
console.log(err)
app.alert(err);
}
},
"Move tasks in batch": async function (app, text) {
try {
const tasks = await this._transformTextIntoTaskArray(app, text);
await this._batchMoveTasks(app, tasks);
} catch (error) {
console.log(error);
app.alert(error);
}
},
"Delete tags in batch": async function (app, text) {
try {
const tasks = await this._transformTextIntoTaskArray(app, text);
await this._batchDeleteTags(app, tasks);
} catch (error) {
console.log(error)
app.alert(error)
}
},
"Edit task details in batch": async function (app, text) {
try {
const tasks = await this._transformTextIntoTaskArray(app, text);
await this._batchEditTaskDetails(app, tasks);
} catch (error) {
console.log(error);
app.alert(error);
}
}
},
noteOption: {
"Tag tasks in batch": async function (app, noteUUID) {
try {
const tasks = await this._getTasksFromNote(app, noteUUID);
await this._batchTagTasks(app, tasks);
} catch (err) {
console.log(err);
app.alert(err);
}
},
"Move tasks in batch": async function (app, noteUUID) {
try {
const tasks = await this._getTasksFromNote(app, noteUUID);
await this._batchMoveTasks(app, tasks);
} catch (error) {
console.log(error)
app.alert(error)
}
},
"Delete tags in batch": async function (app, noteUUID) {
try {
const tasks = await this._getTasksFromNote(app, noteUUID);
await this._batchDeleteTags(app, tasks);
} catch (error) {
console.log(error)
app.alert(error)
}
},
"Edit task details in batch": async function (app, noteUUID) {
try {
const tasks = await this._getTasksFromNote(app, noteUUID);
await this._batchEditTaskDetails(app, tasks);
} catch (error) {
console.log(error);
app.alert(error);
}
}
},
/**
* Adds inline tags to the selected tasks
* @param {*} app
* @param {string} text With the tasks separated by linebreaks
* @returns {void}
*/
async _batchTagTasks(app, tasks) {
const systemNotes = await app.filterNotes();
const inlineTag = await app.prompt("Choose an inline tag", {
inputs: [
{ label: 'Inline tag selection', type: 'note', options: systemNotes }
]
});
if (!inlineTag) throw new Error("Inline tag field cannot be empty");
console.log('Inline tag to add:\n');
console.log(inlineTag)
// Add the tag to the task name
await Promise.all(tasks.map(async task => {
const newtaskName = ` ${task.content}\n[${inlineTag.name}](https://www.amplenote.com/notes/${inlineTag.uuid})`;
await app.updateTask(task.uuid, { content: newtaskName });
}));
console.log('Tasks tagged successfully!');
},
/**
* Moves the selected tasks to another note
* @param {*} app
* @param {string} text With tasks separated by linebreaks
* @returns {void}
*/
async _batchMoveTasks(app, tasks) {
const systemNotes = await app.filterNotes();
const targetNote = await app.prompt("Choose a note", {
inputs: [
{ label: 'Target note', type: 'note', options: systemNotes }
]
});
if (!targetNote) throw new Error("Target note cannot be empty");
console.log("Note to move tasks to: ")
console.log(targetNote);
// Move tasks to target note
await Promise.all(tasks.map(async task => {
const noteUUID = targetNote.uuid;
await app.updateTask(task.uuid, { noteUUID: noteUUID })
console.log(task);
}));
},
/**
* Deletes the inline tags of the selected tasks.
* @param {*} app
* @param {string} text With the selected tasks separated by linebreaks
* @returns {void}
*/
async _batchDeleteTags(app, tasks) {
let noteUUIDs = [];
//Get all possible inline tags from the selected tasks
tasks.map(task => {
//Replaces the whole task name with only the noteUUID
const noteLink = task.content.match(/\((.*?)\)/g).map(match => match.slice(1, -1));
noteLink.forEach(link => {
const uuid = link.match(/\/([^\/]+)$/)
noteUUIDs.push(uuid[1]) //Sends the second matching group, as the first has a weird "/"
})
});
//Gets only the unique UUIDs
noteUUIDs = [...new Set(noteUUIDs)]
if (!noteUUIDs) throw new Error("No inline tags found to delete");
//Gets the note and transforms it into an object similar to the select type
let tagOptions = await Promise.all(noteUUIDs.map(async note => {
note = await app.findNote({ uuid: note })
const object = {
label: note.name,
value: `[${note.name}](https://www.amplenote.com/notes/${note.uuid})`
}
return object;
}))
console.log('NoteUUIDs of the inline tags:');
console.log(tagOptions);
const selectedTag = await app.prompt("Choose an inline tag to remove", {
inputs: [
{ label: 'Inline tag selection', type: 'select', options: tagOptions }
]
});
if (!selectedTag) throw new Error("Inline tag cannot be empty");
//Delete the selected tag from the tasks
await Promise.all(tasks.map(async task => {
if (task.content.includes(selectedTag)) {
let newTaskContent = task.content.replace(selectedTag, "");
newTaskContent = newTaskContent.replace(/\\/g, "");
console.log('new task name: ' + newTaskContent)
await app.updateTask(task.uuid, { content: newTaskContent });
}
}))
console.log('Inline tag removed!');
},
/**
* Edits the task details of all selected tasks
* All of the attributes that can be edited through this function are:
*
* - `Hide Until` as a date
* - `Priority` and `Urgency`
* - `Duration` in minutes
* @param {*} app
* @param {string} text
*/
async _batchEditTaskDetails(app, tasks) {
/** Items to add
* repeat (no plugin support)
* start at (would be difficult without a rule)
* hide
* priority/urgency
* duration (endAt)
*/
const prompt = await app.prompt("Select the properties to edit", {
inputs: [
{ label: "Hide task until (full dates only)", placeholder: "July 26", type: "text" },
{ label: "Duration (in minutes and numbers only)", type: "text" },
{ label: "important", type: "checkbox" },
{ label: "Urgent", type: "checkbox" },
{ label: "Score (numbers only)", type: "text" },
]
});
const [hideUntil, duration, priority, urgent, score] = prompt;
let durationNumber;
let scoreNumber;
if (duration) {
durationNumber = parseInt(duration);
if (isNaN(durationNumber)) throw new Error("Duration field must be a number");
}
if (score) {
scoreNumber = parseInt(score);
if (isNaN(scoreNumber)) throw new Error("Score field must be a number");
}
await Promise.all(tasks.map(async task => {
console.log(task);
//Adding a priority for the tasks
await app.updateTask(task.uuid, { important: priority, urgent: urgent });
//Change score
if (scoreNumber) await app.updateTask(task.uuid, { score: score });
//Change Hide Until of the task
//Convert hide time to date
if (hideUntil) {
let hideDate = new Date(`${hideUntil}, 2024`);
hideDate = hideDate.getTime() / 1000; //Transforms miliseconds into seconds
console.log("Hide date in seconds: " + hideDate);
await app.updateTask(task.uuid, { hideUntil: hideDate });
}
//Change duration
if (durationNumber) {
//Throw error if a task doesn't have a Start Date
if (!task.startAt) {
throw new Error("Can't set a duration for a task that isn't scheduled");
}
//Get the start time from the task in minutes
const startTime = task.startAt * 1000;
const durationDate = new Date(startTime + durationNumber * 60 * 1000);
console.log("Time to edit: ", durationDate);
await app.updateTask(task.uuid, { endAt: Math.floor(durationDate.getTime() / 1000) });
}
}))
},
/**
* Gets the tasks from the selected note and transforms them into text
* @param {*} app
* @param {string} noteUUID
* @returns {string} with the tasks, each separated by a line break
*/
async _getTasksFromNote(app, noteUUID) {
const noteTasks = await app.getNoteTasks({ uuid: noteUUID });
if (!noteTasks) throw new Error("Current note has no tasks");
// Transform the noteTasks into an object array to match the inputs prompt
const taskOptions = noteTasks.map(task => ({
label: task.content,
type: 'checkbox'
}));
const inputTasks = await app.prompt('Select the tasks you want to act on', {
inputs: taskOptions
});
if (!inputTasks) throw new Error("Choose at least one tasks in order to proceed");
//Filters the tasks that were selected
const selectedTasks = noteTasks.filter((_, index) => inputTasks[index]);
return selectedTasks;
},
/**
* Transforms the tasks in string format into the original task object array
* @param {*} app
* @param {string} text With the selected tasks separated by line breaks
* @returns {tasks[]} Array with the selected tasks
*/
async _transformTextIntoTaskArray(app, text) {
const noteUUID = app.context.noteUUID;
const noteTasks = await app.getNoteTasks({ uuid: noteUUID });
if (!noteTasks) throw new Error("Choose at least one tasks in order to proceed");
const textTaskArray = text
.split('\n')
.map(line => line.trim())
.filter(line => line.length > 0); // Remove empty lines
const taskArray = noteTasks.filter(task => {
// Task content without newlines and markdown links
let taskContent = task.content.replace(/\\[\r\n]+/g, ' ');
taskContent = taskContent.replace(/(?:__|[*#])|\[(.*?)\]\(.*?\)|`([^`]*)`/gm, '$1$2');
taskContent = taskContent.trim();
// Compare against exact matches
return textTaskArray.includes(taskContent);
});
console.log('Chosen tasks:')
console.log(taskArray);
return taskArray;
}
}
export default plugin;