From ded4429403405b1222049fb7cfc108acaa1bc3ed Mon Sep 17 00:00:00 2001 From: Alex Wilde Date: Sat, 22 Oct 2022 20:28:53 +0200 Subject: [PATCH 1/3] Add hooks to let other plugins extend the Tasks plugin. --- src/Query/Query.ts | 17 ++++++++++++++++- src/QueryRenderer.ts | 37 ++++++++++++++++++++++++++++++++++--- 2 files changed, 50 insertions(+), 4 deletions(-) diff --git a/src/Query/Query.ts b/src/Query/Query.ts index f1ab1a43ab..91ad937736 100644 --- a/src/Query/Query.ts +++ b/src/Query/Query.ts @@ -6,6 +6,7 @@ import type { TaskGroups } from './TaskGroups'; import { parseFilter } from './FilterParser'; import { Group } from './Group'; import type { Filter } from './Filter/Filter'; +import type { ExtendParserHook } from 'QueryRenderer'; export type SortingProperty = | 'urgency' @@ -69,7 +70,7 @@ export class Query implements IQuery { private readonly commentRegexp = /^#.*/; - constructor({ source }: { source: string }) { + constructor({ source, extensions }: { source: string, extensions: ExtendParserHook[] }) { this.source = source; source .split('\n') @@ -98,6 +99,8 @@ export class Query implements IQuery { break; case this.parseFilter(line): break; + case this.parseExtensions(extensions, line): + break; default: this._error = `do not understand query: ${line}`; } @@ -223,4 +226,16 @@ export class Query implements IQuery { this._error = 'do not understand query grouping'; } } + + private parseExtensions( extensions: ExtendParserHook[], line: string ): boolean { + let found = false; + // Let plugins that implement the "extendParse" hook parse the given + // line + extensions.forEach((extendParser: ExtendParserHook) => { + if (extendParser(line, this.layoutOptions)) { + found = true; + } + }); + return found; + } } diff --git a/src/QueryRenderer.ts b/src/QueryRenderer.ts index 67c4806536..607cb1af79 100644 --- a/src/QueryRenderer.ts +++ b/src/QueryRenderer.ts @@ -7,6 +7,7 @@ import { replaceTaskWithTasks } from './File'; import { Query } from './Query/Query'; import type { GroupHeading } from './Query/GroupHeading'; import { TaskModal } from './TaskModal'; +import { Task as TaskModel } from './Task'; import type { TasksEvents } from './TasksEvents'; import type { Task } from './Task'; @@ -36,6 +37,9 @@ export class QueryRenderer { } } +export type ExtendTaskHook = (listItem: HTMLLIElement, task: Task, api: object) => void +export type ExtendParserHook = (line: string, layoutOptions: object) => boolean + class QueryRenderChild extends MarkdownRenderChild { private readonly app: App; private readonly events: TasksEvents; @@ -47,6 +51,9 @@ class QueryRenderChild extends MarkdownRenderChild { private renderEventRef: EventRef | undefined; private queryReloadTimeout: NodeJS.Timeout | undefined; + private extendTask: ExtendTaskHook[]; + private extendParser: ExtendParserHook[]; + constructor({ app, events, @@ -66,18 +73,34 @@ class QueryRenderChild extends MarkdownRenderChild { this.events = events; this.source = source; this.filePath = filePath; + this.extendTask = []; + this.extendParser = []; + + // Cache which plugins implement our extension hooks + // @ts-ignore + Object.keys(this.app.plugins.plugins).forEach((name) => { + // @ts-ignore + const plugin = this.app.plugins.plugins[name]; + if (plugin.extendTask) { + this.extendTask.push(plugin.extendTask) + } + + if (plugin.extendParser) { + this.extendParser.push(plugin.extendParser) + } + }) // The engine is chosen on the basis of the code block language. Currently // there is only the main engine for the plugin, this allows others to be // added later. switch (this.containerEl.className) { case 'block-language-tasks': - this.query = new Query({ source }); + this.query = new Query({ source, extensions: this.extendParser }); this.queryType = 'tasks'; break; default: - this.query = new Query({ source }); + this.query = new Query({ source, extensions: this.extendParser }); this.queryType = 'tasks'; break; } @@ -118,7 +141,7 @@ class QueryRenderChild extends MarkdownRenderChild { const millisecondsToMidnight = midnight.getTime() - now.getTime(); this.queryReloadTimeout = setTimeout(() => { - this.query = new Query({ source: this.source }); + this.query = new Query({ source: this.source, extensions: this.extendParser }); // Process the current cache state: this.events.triggerRequestCacheUpdate(this.render.bind(this)); this.reloadQueryAtMidnight(); @@ -200,6 +223,14 @@ class QueryRenderChild extends MarkdownRenderChild { this.addEditButton(listItem, task); } + // Let plugins that implement the "extendTask" hook extend the + // current task + this.extendTask.forEach((extendTask: ExtendTaskHook) => extendTask(listItem, task, { + layoutOptions: this.query.layoutOptions, + Task: TaskModel, + replaceTaskWithTasks + })) + taskList.appendChild(listItem); } From 1a46f14046220b57d2eaaef9be575368e6cc4573 Mon Sep 17 00:00:00 2001 From: Alex Wilde Date: Tue, 25 Oct 2022 11:13:10 +0200 Subject: [PATCH 2/3] Make argument optional. --- src/Query/Query.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Query/Query.ts b/src/Query/Query.ts index 91ad937736..03fde59eff 100644 --- a/src/Query/Query.ts +++ b/src/Query/Query.ts @@ -1,3 +1,4 @@ +import type { ExtendParserHook } from 'QueryRenderer'; import { LayoutOptions } from '../LayoutOptions'; import type { Task } from '../Task'; import type { IQuery } from '../IQuery'; @@ -6,7 +7,6 @@ import type { TaskGroups } from './TaskGroups'; import { parseFilter } from './FilterParser'; import { Group } from './Group'; import type { Filter } from './Filter/Filter'; -import type { ExtendParserHook } from 'QueryRenderer'; export type SortingProperty = | 'urgency' @@ -70,7 +70,7 @@ export class Query implements IQuery { private readonly commentRegexp = /^#.*/; - constructor({ source, extensions }: { source: string, extensions: ExtendParserHook[] }) { + constructor({ source, extensions = [] }: { source: string; extensions?: ExtendParserHook[] }) { this.source = source; source .split('\n') @@ -226,8 +226,8 @@ export class Query implements IQuery { this._error = 'do not understand query grouping'; } } - - private parseExtensions( extensions: ExtendParserHook[], line: string ): boolean { + + private parseExtensions(extensions: ExtendParserHook[], line: string): boolean { let found = false; // Let plugins that implement the "extendParse" hook parse the given // line From 25ae0eef0d8b6f45e24ec85f33c13283a988a8ca Mon Sep 17 00:00:00 2001 From: Alex Wilde Date: Tue, 25 Oct 2022 11:14:04 +0200 Subject: [PATCH 3/3] Formatting. --- src/QueryRenderer.ts | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/QueryRenderer.ts b/src/QueryRenderer.ts index 607cb1af79..d3d2556097 100644 --- a/src/QueryRenderer.ts +++ b/src/QueryRenderer.ts @@ -37,8 +37,8 @@ export class QueryRenderer { } } -export type ExtendTaskHook = (listItem: HTMLLIElement, task: Task, api: object) => void -export type ExtendParserHook = (line: string, layoutOptions: object) => boolean +export type ExtendTaskHook = (listItem: HTMLLIElement, task: Task, api: object) => void; +export type ExtendParserHook = (line: string, layoutOptions: object) => boolean; class QueryRenderChild extends MarkdownRenderChild { private readonly app: App; @@ -82,13 +82,13 @@ class QueryRenderChild extends MarkdownRenderChild { // @ts-ignore const plugin = this.app.plugins.plugins[name]; if (plugin.extendTask) { - this.extendTask.push(plugin.extendTask) + this.extendTask.push(plugin.extendTask); } if (plugin.extendParser) { - this.extendParser.push(plugin.extendParser) + this.extendParser.push(plugin.extendParser); } - }) + }); // The engine is chosen on the basis of the code block language. Currently // there is only the main engine for the plugin, this allows others to be @@ -225,11 +225,13 @@ class QueryRenderChild extends MarkdownRenderChild { // Let plugins that implement the "extendTask" hook extend the // current task - this.extendTask.forEach((extendTask: ExtendTaskHook) => extendTask(listItem, task, { - layoutOptions: this.query.layoutOptions, - Task: TaskModel, - replaceTaskWithTasks - })) + this.extendTask.forEach((extendTask: ExtendTaskHook) => + extendTask(listItem, task, { + layoutOptions: this.query.layoutOptions, + Task: TaskModel, + replaceTaskWithTasks, + }), + ); taskList.appendChild(listItem); }