From 2f67b32835949cd4e44c6c2b7260d68e8e51226f Mon Sep 17 00:00:00 2001 From: chrabia297 Date: Mon, 4 Dec 2023 23:11:16 +0100 Subject: [PATCH] feat: added change task status context menu --- src/Task.ts | 18 +++++++++++++++++- src/TaskLineRenderer.ts | 29 ++++++++++++++++++++++++++++- 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/src/Task.ts b/src/Task.ts index 4620d59687..0528b8e257 100644 --- a/src/Task.ts +++ b/src/Task.ts @@ -378,6 +378,12 @@ export class Task { const newStatus = StatusRegistry.getInstance().getNextStatusOrCreate(this.status); + const newTasks = this.handleNewStatus(newStatus); + logEndOfTaskEdit(logger, codeLocation, newTasks); + return newTasks; + } + + private handleNewStatus(newStatus: Status): Task[] { let newDoneDate = null; let nextOccurrence: { @@ -430,7 +436,6 @@ export class Task { // Write next occurrence before previous occurrence. newTasks.push(toggledTask); - logEndOfTaskEdit(logger, codeLocation, newTasks); return newTasks; } @@ -458,6 +463,17 @@ export class Task { return recurrenceOnNextLine ? newTasks.reverse() : newTasks; } + public handleStatusChangeFromContextMenuWithRecurrenceInUsersOrder(newStatus: Status): Task[] { + const logger = logging.getLogger('tasks.Task'); + logger.trace( + `changed task ${this.taskLocation.path} ${this.taskLocation.lineNumber} ${this.originalMarkdown} status to ${newStatus}`, + ); + + const newTasks = this.handleNewStatus(newStatus); + const { recurrenceOnNextLine: recurrenceOnNextLine } = getSettings(); + return recurrenceOnNextLine ? newTasks.reverse() : newTasks; + } + /** * Return whether the task is considered done. * @returns true if the status type is {@link StatusType.DONE}, {@link StatusType.CANCELLED} or {@link StatusType.NON_TASK}, and false otherwise. diff --git a/src/TaskLineRenderer.ts b/src/TaskLineRenderer.ts index 7b379e45ca..eba7f6a9b7 100644 --- a/src/TaskLineRenderer.ts +++ b/src/TaskLineRenderer.ts @@ -1,8 +1,9 @@ import type { Moment } from 'moment'; -import { Component, MarkdownRenderer } from 'obsidian'; +import { Component, MarkdownRenderer, Menu, MenuItem } from 'obsidian'; import { GlobalFilter } from './Config/GlobalFilter'; import { TASK_FORMATS, getSettings } from './Config/Settings'; import { replaceTaskWithTasks } from './File'; +import { StatusRegistry } from './StatusRegistry'; import type { Task } from './Task'; import * as taskModule from './Task'; import { TaskFieldRenderer } from './TaskFieldRenderer'; @@ -123,6 +124,32 @@ export class TaskLineRenderer { }); }); + checkbox.addEventListener('contextmenu', async (ev: MouseEvent) => { + const menu = new Menu(); + const commonTitle = 'Change status to: '; + + const getMenuItemCallback = (item: MenuItem, statusName: string, newStatusSymbol: string) => { + item.setTitle(`${commonTitle} ${statusName}`).onClick(() => { + const status = StatusRegistry.getInstance().bySymbol(newStatusSymbol); + const newTask = task.handleStatusChangeFromContextMenuWithRecurrenceInUsersOrder(status); + replaceTaskWithTasks({ + originalTask: task, + newTasks: newTask, + }); + }); + }; + + const { statusSettings } = getSettings(); + for (const status of statusSettings.coreStatuses) { + menu.addItem((item) => getMenuItemCallback(item, status.name, status.symbol)); + } + for (const status of statusSettings.customStatuses) { + menu.addItem((item) => getMenuItemCallback(item, status.name, status.symbol)); + } + + menu.showAtPosition({ x: ev.clientX, y: ev.clientY }); + }); + li.prepend(checkbox); // Set these to be compatible with stock obsidian lists: