mirror of
https://github.com/taskgenius/taskgenius-plugin.git
synced 2026-07-22 06:40:25 +00:00
feat: support hide progressbar based on condition
This commit is contained in:
parent
a785742cbe
commit
4d034c94d2
5 changed files with 468 additions and 4470 deletions
4328
package-lock.json
generated
4328
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -1,5 +1,6 @@
|
|||
import TaskProgressBarPlugin from "./taskProgressBarIndex";
|
||||
import { Component, MarkdownPostProcessorContext } from "obsidian";
|
||||
import { Component, MarkdownPostProcessorContext, TFile } from "obsidian";
|
||||
import { shouldHideProgressBarInPreview } from "./utils";
|
||||
|
||||
interface GroupElement {
|
||||
parentElement: HTMLElement;
|
||||
|
|
@ -23,49 +24,67 @@ function groupElementsByParent(childrenElements: HTMLElement[]) {
|
|||
|
||||
const result: GroupElement[] = [];
|
||||
parentMap.forEach((children, parent) => {
|
||||
result.push({parentElement: parent, childrenElement: children});
|
||||
result.push({ parentElement: parent, childrenElement: children });
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function loadProgressbar(plugin: TaskProgressBarPlugin, groupedElements: GroupElement[], type: 'dataview' | 'normal') {
|
||||
function loadProgressbar(
|
||||
plugin: TaskProgressBarPlugin,
|
||||
groupedElements: GroupElement[],
|
||||
type: "dataview" | "normal"
|
||||
) {
|
||||
for (let group of groupedElements) {
|
||||
if (group.parentElement.parentElement && group.parentElement?.parentElement.hasClass('task-list-item')) {
|
||||
|
||||
if (
|
||||
group.parentElement.parentElement &&
|
||||
group.parentElement?.parentElement.hasClass("task-list-item")
|
||||
) {
|
||||
const progressBar = new ProgressBar(plugin, group, type).onload();
|
||||
|
||||
const previousSibling = group.parentElement.previousElementSibling;
|
||||
if (previousSibling && previousSibling.tagName === 'P') {
|
||||
if (previousSibling && previousSibling.tagName === "P") {
|
||||
previousSibling.appendChild(progressBar);
|
||||
} else {
|
||||
group.parentElement.parentElement.insertBefore(progressBar, group.parentElement);
|
||||
group.parentElement.parentElement.insertBefore(
|
||||
progressBar,
|
||||
group.parentElement
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function updateProgressBarInElement({plugin, element, ctx}: {
|
||||
plugin: TaskProgressBarPlugin, element: HTMLElement, ctx: MarkdownPostProcessorContext
|
||||
export function updateProgressBarInElement({
|
||||
plugin,
|
||||
element,
|
||||
ctx,
|
||||
}: {
|
||||
plugin: TaskProgressBarPlugin;
|
||||
element: HTMLElement;
|
||||
ctx: MarkdownPostProcessorContext;
|
||||
}) {
|
||||
console.log('updateProgressBarInElement');
|
||||
if (element.find('ul.contains-task-list')) {
|
||||
// Check if progress bars should be hidden based on settings
|
||||
if (shouldHideProgressBarInPreview(plugin, ctx)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const elements = element.findAll('.task-list-item');
|
||||
if (element.find("ul.contains-task-list")) {
|
||||
const elements = element.findAll(".task-list-item");
|
||||
const groupedElements = groupElementsByParent(elements);
|
||||
loadProgressbar(plugin, groupedElements, 'normal');
|
||||
} else if (element.closest('.dataview-container')) {
|
||||
const parentElement = element.closest('.dataview-container');
|
||||
loadProgressbar(plugin, groupedElements, "normal");
|
||||
} else if (element.closest(".dataview-container")) {
|
||||
const parentElement = element.closest(".dataview-container");
|
||||
if (!parentElement) return;
|
||||
if (parentElement.getAttribute('data-task-progress-bar') === 'true') return;
|
||||
const elements = parentElement.findAll('.task-list-item');
|
||||
if (parentElement.getAttribute("data-task-progress-bar") === "true")
|
||||
return;
|
||||
const elements = parentElement.findAll(".task-list-item");
|
||||
const groupedElements = groupElementsByParent(elements);
|
||||
loadProgressbar(plugin, groupedElements, 'dataview');
|
||||
parentElement.setAttribute('data-task-progress-bar', 'true');
|
||||
loadProgressbar(plugin, groupedElements, "dataview");
|
||||
parentElement.setAttribute("data-task-progress-bar", "true");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class ProgressBar extends Component {
|
||||
progressBarEl: HTMLSpanElement;
|
||||
progressBackGroundEl: HTMLDivElement;
|
||||
|
|
@ -79,40 +98,48 @@ class ProgressBar extends Component {
|
|||
|
||||
group: GroupElement;
|
||||
|
||||
constructor(plugin: TaskProgressBarPlugin, group: GroupElement, readonly type: 'dataview' | 'normal') {
|
||||
constructor(
|
||||
plugin: TaskProgressBarPlugin,
|
||||
group: GroupElement,
|
||||
readonly type: "dataview" | "normal"
|
||||
) {
|
||||
super();
|
||||
this.plugin = plugin;
|
||||
|
||||
this.group = group;
|
||||
this.type === 'dataview' && this.updateCompletedAndTotalDataview();
|
||||
this.type === 'normal' && this.updateCompletedAndTotal();
|
||||
this.type === "dataview" && this.updateCompletedAndTotalDataview();
|
||||
this.type === "normal" && this.updateCompletedAndTotal();
|
||||
|
||||
for (let el of this.group.childrenElement) {
|
||||
this.type === 'normal' && el.on('click', 'input', () => {
|
||||
setTimeout(() => {
|
||||
this.updateCompletedAndTotal();
|
||||
this.changePercentage();
|
||||
this.changeNumber();
|
||||
}, 200);
|
||||
});
|
||||
|
||||
this.type === 'dataview' && this.registerDomEvent(el, 'mousedown', (ev) => {
|
||||
if (!ev.target) return;
|
||||
if ((ev.target as HTMLElement).tagName === 'INPUT') {
|
||||
this.type === "normal" &&
|
||||
el.on("click", "input", () => {
|
||||
setTimeout(() => {
|
||||
console.log('click');
|
||||
console.log(el);
|
||||
this.updateCompletedAndTotalDataview();
|
||||
this.updateCompletedAndTotal();
|
||||
this.changePercentage();
|
||||
this.changeNumber();
|
||||
}, 200);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
this.type === "dataview" &&
|
||||
this.registerDomEvent(el, "mousedown", (ev) => {
|
||||
if (!ev.target) return;
|
||||
if ((ev.target as HTMLElement).tagName === "INPUT") {
|
||||
setTimeout(() => {
|
||||
this.updateCompletedAndTotalDataview();
|
||||
this.changePercentage();
|
||||
this.changeNumber();
|
||||
}, 200);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
updateCompletedAndTotalDataview() {
|
||||
const checked = this.group.childrenElement.filter((el) => el.getAttribute('data-task') && el.getAttribute('data-task') !== ' ').length;
|
||||
const checked = this.group.childrenElement.filter(
|
||||
(el) =>
|
||||
el.getAttribute("data-task") &&
|
||||
el.getAttribute("data-task") !== " "
|
||||
).length;
|
||||
const total = this.group.childrenElement.length;
|
||||
|
||||
this.numberEl?.detach();
|
||||
|
|
@ -122,7 +149,9 @@ class ProgressBar extends Component {
|
|||
}
|
||||
|
||||
updateCompletedAndTotal() {
|
||||
const checked = this.group.childrenElement.filter((el) => el.hasClass('is-checked')).length;
|
||||
const checked = this.group.childrenElement.filter((el) =>
|
||||
el.hasClass("is-checked")
|
||||
).length;
|
||||
const total = this.group.childrenElement.length;
|
||||
|
||||
this.numberEl?.detach();
|
||||
|
|
@ -132,34 +161,42 @@ class ProgressBar extends Component {
|
|||
}
|
||||
|
||||
changePercentage() {
|
||||
const percentage = Math.round(this.completed / this.total * 10000) / 100;
|
||||
this.progressEl.style.width = percentage + '%';
|
||||
const percentage =
|
||||
Math.round((this.completed / this.total) * 10000) / 100;
|
||||
this.progressEl.style.width = percentage + "%";
|
||||
switch (true) {
|
||||
case percentage >= 0 && percentage < 25:
|
||||
this.progressEl.className = 'progress-bar-inline progress-bar-inline-0';
|
||||
this.progressEl.className =
|
||||
"progress-bar-inline progress-bar-inline-0";
|
||||
break;
|
||||
case percentage >= 25 && percentage < 50:
|
||||
this.progressEl.className = 'progress-bar-inline progress-bar-inline-1';
|
||||
this.progressEl.className =
|
||||
"progress-bar-inline progress-bar-inline-1";
|
||||
break;
|
||||
case percentage >= 50 && percentage < 75:
|
||||
this.progressEl.className = 'progress-bar-inline progress-bar-inline-2';
|
||||
this.progressEl.className =
|
||||
"progress-bar-inline progress-bar-inline-2";
|
||||
break;
|
||||
case percentage >= 75 && percentage < 100:
|
||||
this.progressEl.className = 'progress-bar-inline progress-bar-inline-3';
|
||||
this.progressEl.className =
|
||||
"progress-bar-inline progress-bar-inline-3";
|
||||
break;
|
||||
case percentage >= 100:
|
||||
this.progressEl.className = 'progress-bar-inline progress-bar-inline-4';
|
||||
this.progressEl.className =
|
||||
"progress-bar-inline progress-bar-inline-4";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
changeNumber() {
|
||||
if (this.plugin?.settings.addNumberToProgressBar) {
|
||||
const text = this.plugin?.settings.showPercentage ? `${Math.round(this.completed / this.total * 10000) / 100}%` : `[${this.completed}/${this.total}]`;
|
||||
const text = this.plugin?.settings.showPercentage
|
||||
? `${Math.round((this.completed / this.total) * 10000) / 100}%`
|
||||
: `[${this.completed}/${this.total}]`;
|
||||
|
||||
this.numberEl = this.progressBarEl.createEl('div', {
|
||||
cls: 'progress-status',
|
||||
text: text
|
||||
this.numberEl = this.progressBarEl.createEl("div", {
|
||||
cls: "progress-status",
|
||||
text: text,
|
||||
});
|
||||
|
||||
return;
|
||||
|
|
@ -168,19 +205,25 @@ class ProgressBar extends Component {
|
|||
}
|
||||
|
||||
onload() {
|
||||
this.progressBarEl = createSpan(this.plugin?.settings.addNumberToProgressBar ? 'cm-task-progress-bar with-number' : 'cm-task-progress-bar');
|
||||
this.progressBackGroundEl = this.progressBarEl.createEl('div', {cls: 'progress-bar-inline-background'});
|
||||
this.progressEl = this.progressBackGroundEl.createEl('div');
|
||||
this.progressBarEl = createSpan(
|
||||
this.plugin?.settings.addNumberToProgressBar
|
||||
? "cm-task-progress-bar with-number"
|
||||
: "cm-task-progress-bar"
|
||||
);
|
||||
this.progressBackGroundEl = this.progressBarEl.createEl("div", {
|
||||
cls: "progress-bar-inline-background",
|
||||
});
|
||||
this.progressEl = this.progressBackGroundEl.createEl("div");
|
||||
|
||||
if (this.plugin?.settings.addNumberToProgressBar && this.total) {
|
||||
const text = this.plugin?.settings.showPercentage
|
||||
? `${Math.round((this.completed / this.total) * 10000) / 100}%`
|
||||
: `[${this.completed}/${this.total}]`;
|
||||
|
||||
const text = this.plugin?.settings.showPercentage ? `${Math.round(this.completed / this.total * 10000) / 100}%` : `[${this.completed}/${this.total}]`;
|
||||
|
||||
this.numberEl = this.progressBarEl.createEl('div', {
|
||||
cls: 'progress-status',
|
||||
text: text
|
||||
this.numberEl = this.progressBarEl.createEl("div", {
|
||||
cls: "progress-status",
|
||||
text: text,
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
this.changePercentage();
|
||||
|
|
@ -190,6 +233,5 @@ class ProgressBar extends Component {
|
|||
|
||||
onunload() {
|
||||
super.onunload();
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { App, Editor, Plugin, PluginSettingTab, Setting } from 'obsidian';
|
||||
import { taskProgressBarExtension } from './widget';
|
||||
import { App, Editor, Plugin, PluginSettingTab, Setting } from "obsidian";
|
||||
import { taskProgressBarExtension } from "./widget";
|
||||
import { updateProgressBarInElement } from "./readModeWidget";
|
||||
|
||||
interface TaskProgressBarSettings {
|
||||
|
|
@ -9,6 +9,10 @@ interface TaskProgressBarSettings {
|
|||
allowAlternateTaskStatus: boolean;
|
||||
alternativeMarks: string;
|
||||
countSubLevel: boolean;
|
||||
hideProgressBarBasedOnConditions: boolean;
|
||||
hideProgressBarTags: string;
|
||||
hideProgressBarFolders: string;
|
||||
hideProgressBarMetadata: string;
|
||||
}
|
||||
|
||||
const DEFAULT_SETTINGS: TaskProgressBarSettings = {
|
||||
|
|
@ -16,8 +20,12 @@ const DEFAULT_SETTINGS: TaskProgressBarSettings = {
|
|||
addNumberToProgressBar: false,
|
||||
showPercentage: false,
|
||||
allowAlternateTaskStatus: false,
|
||||
alternativeMarks: '(x|X|-)',
|
||||
alternativeMarks: "(x|X|-)",
|
||||
countSubLevel: true,
|
||||
hideProgressBarBasedOnConditions: false,
|
||||
hideProgressBarTags: "no-progress-bar",
|
||||
hideProgressBarFolders: "",
|
||||
hideProgressBarMetadata: "hide-progress-bar",
|
||||
};
|
||||
|
||||
export default class TaskProgressBarPlugin extends Plugin {
|
||||
|
|
@ -30,17 +38,21 @@ export default class TaskProgressBarPlugin extends Plugin {
|
|||
this.registerEditorExtension(taskProgressBarExtension(this.app, this));
|
||||
this.registerMarkdownPostProcessor((el, ctx) => {
|
||||
updateProgressBarInElement({
|
||||
plugin: this, element: el, ctx: ctx
|
||||
plugin: this,
|
||||
element: el,
|
||||
ctx: ctx,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
onunload() {
|
||||
|
||||
}
|
||||
onunload() {}
|
||||
|
||||
async loadSettings() {
|
||||
this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());
|
||||
this.settings = Object.assign(
|
||||
{},
|
||||
DEFAULT_SETTINGS,
|
||||
await this.loadData()
|
||||
);
|
||||
}
|
||||
|
||||
async saveSettings() {
|
||||
|
|
@ -66,43 +78,57 @@ class TaskProgressBarSettingTab extends PluginSettingTab {
|
|||
}
|
||||
|
||||
display(): void {
|
||||
const {containerEl} = this;
|
||||
const { containerEl } = this;
|
||||
|
||||
containerEl.empty();
|
||||
|
||||
containerEl.createEl('h2', {text: '📍 Task Progress Bar'});
|
||||
containerEl.createEl("h2", { text: "📍 Task Progress Bar" });
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('Add progress bar to Heading')
|
||||
.setDesc('Toggle this to allow this plugin to add progress bar for Task below the headings.')
|
||||
.setName("Add progress bar to Heading")
|
||||
.setDesc(
|
||||
"Toggle this to allow this plugin to add progress bar for Task below the headings."
|
||||
)
|
||||
.addToggle((toggle) =>
|
||||
toggle.setValue(this.plugin.settings.addTaskProgressBarToHeading).onChange(async (value) => {
|
||||
this.plugin.settings.addTaskProgressBarToHeading = value;
|
||||
this.applySettingsUpdate();
|
||||
}));
|
||||
toggle
|
||||
.setValue(this.plugin.settings.addTaskProgressBarToHeading)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.addTaskProgressBarToHeading =
|
||||
value;
|
||||
this.applySettingsUpdate();
|
||||
})
|
||||
);
|
||||
|
||||
this.showNumberToProgressbar();
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('Count sub children level of current Task')
|
||||
.setDesc('Toggle this to allow this plugin to count sub tasks.')
|
||||
.setName("Count sub children level of current Task")
|
||||
.setDesc("Toggle this to allow this plugin to count sub tasks.")
|
||||
.addToggle((toggle) =>
|
||||
toggle.setValue(this.plugin.settings.countSubLevel).onChange(async (value) => {
|
||||
this.plugin.settings.countSubLevel = value;
|
||||
this.applySettingsUpdate();
|
||||
}));
|
||||
toggle
|
||||
.setValue(this.plugin.settings.countSubLevel)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.countSubLevel = value;
|
||||
this.applySettingsUpdate();
|
||||
})
|
||||
);
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('Allow alternate task status')
|
||||
.setDesc('Toggle this to allow this plugin to treat different tasks mark as completed or uncompleted tasks.')
|
||||
.setName("Allow alternate task status")
|
||||
.setDesc(
|
||||
"Toggle this to allow this plugin to treat different tasks mark as completed or uncompleted tasks."
|
||||
)
|
||||
.addToggle((toggle) =>
|
||||
toggle.setValue(this.plugin.settings.allowAlternateTaskStatus).onChange(async (value) => {
|
||||
this.plugin.settings.allowAlternateTaskStatus = value;
|
||||
this.applySettingsUpdate();
|
||||
}));
|
||||
toggle
|
||||
.setValue(this.plugin.settings.allowAlternateTaskStatus)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.allowAlternateTaskStatus = value;
|
||||
this.applySettingsUpdate();
|
||||
})
|
||||
);
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('Completed alternative marks')
|
||||
.setName("Completed alternative marks")
|
||||
.setDesc('Set completed alternative marks here. Like "x|X|-"')
|
||||
.addText((text) =>
|
||||
text
|
||||
|
|
@ -110,49 +136,135 @@ class TaskProgressBarSettingTab extends PluginSettingTab {
|
|||
.setValue(this.plugin.settings.alternativeMarks)
|
||||
.onChange(async (value) => {
|
||||
if (value.length === 0) {
|
||||
this.plugin.settings.alternativeMarks = DEFAULT_SETTINGS.alternativeMarks;
|
||||
this.plugin.settings.alternativeMarks =
|
||||
DEFAULT_SETTINGS.alternativeMarks;
|
||||
} else {
|
||||
this.plugin.settings.alternativeMarks = value;
|
||||
}
|
||||
this.applySettingsUpdate();
|
||||
}),
|
||||
})
|
||||
);
|
||||
|
||||
|
||||
this.containerEl.createEl('h2', {text: 'Say Thank You'});
|
||||
new Setting(containerEl)
|
||||
.setName("Conditional Progress Bar Display")
|
||||
.setHeading();
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('Donate')
|
||||
.setDesc('If you like this plugin, consider donating to support continued development:')
|
||||
.setName("Hide progress bars based on conditions")
|
||||
.setDesc(
|
||||
"Toggle this to enable hiding progress bars based on tags, folders, or metadata."
|
||||
)
|
||||
.addToggle((toggle) =>
|
||||
toggle
|
||||
.setValue(
|
||||
this.plugin.settings.hideProgressBarBasedOnConditions
|
||||
)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.hideProgressBarBasedOnConditions =
|
||||
value;
|
||||
this.applySettingsUpdate();
|
||||
|
||||
setTimeout(() => {
|
||||
this.display();
|
||||
}, 200);
|
||||
})
|
||||
);
|
||||
|
||||
if (this.plugin.settings.hideProgressBarBasedOnConditions) {
|
||||
new Setting(containerEl)
|
||||
.setName("Hide by tags")
|
||||
.setDesc(
|
||||
'Specify tags that will hide progress bars (comma-separated, without #). Example: "no-progress-bar,hide-progress"'
|
||||
)
|
||||
.addText((text) =>
|
||||
text
|
||||
.setPlaceholder(DEFAULT_SETTINGS.hideProgressBarTags)
|
||||
.setValue(this.plugin.settings.hideProgressBarTags)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.hideProgressBarTags = value;
|
||||
this.applySettingsUpdate();
|
||||
})
|
||||
);
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName("Hide by folders")
|
||||
.setDesc(
|
||||
'Specify folder paths that will hide progress bars (comma-separated). Example: "Daily Notes,Projects/Hidden"'
|
||||
)
|
||||
.addText((text) =>
|
||||
text
|
||||
.setPlaceholder("folder1,folder2/subfolder")
|
||||
.setValue(this.plugin.settings.hideProgressBarFolders)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.hideProgressBarFolders = value;
|
||||
this.applySettingsUpdate();
|
||||
})
|
||||
);
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName("Hide by metadata")
|
||||
.setDesc(
|
||||
'Specify frontmatter metadata that will hide progress bars. Example: "hide-progress-bar: true"'
|
||||
)
|
||||
.addText((text) =>
|
||||
text
|
||||
.setPlaceholder(
|
||||
DEFAULT_SETTINGS.hideProgressBarMetadata
|
||||
)
|
||||
.setValue(this.plugin.settings.hideProgressBarMetadata)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.hideProgressBarMetadata =
|
||||
value;
|
||||
this.applySettingsUpdate();
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
this.containerEl.createEl("h2", { text: "Say Thank You" });
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName("Donate")
|
||||
.setDesc(
|
||||
"If you like this plugin, consider donating to support continued development:"
|
||||
)
|
||||
.addButton((bt) => {
|
||||
bt.buttonEl.outerHTML = `<a href="https://www.buymeacoffee.com/boninall"><img src="https://img.buymeacoffee.com/button-api/?text=Buy me a coffee&emoji=&slug=boninall&button_colour=6495ED&font_colour=ffffff&font_family=Inter&outline_colour=000000&coffee_colour=FFDD00"></a>`;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
showNumberToProgressbar() {
|
||||
new Setting(this.containerEl)
|
||||
.setName('Add number to the Progress Bar')
|
||||
.setDesc('Toggle this to allow this plugin to add tasks number to progress bar.')
|
||||
.setName("Add number to the Progress Bar")
|
||||
.setDesc(
|
||||
"Toggle this to allow this plugin to add tasks number to progress bar."
|
||||
)
|
||||
.addToggle((toggle) =>
|
||||
toggle.setValue(this.plugin.settings.addNumberToProgressBar).onChange(async (value) => {
|
||||
this.plugin.settings.addNumberToProgressBar = value;
|
||||
this.applySettingsUpdate();
|
||||
toggle
|
||||
.setValue(this.plugin.settings.addNumberToProgressBar)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.addNumberToProgressBar = value;
|
||||
this.applySettingsUpdate();
|
||||
|
||||
setTimeout(() => {
|
||||
this.display();
|
||||
}, 200);
|
||||
}));
|
||||
setTimeout(() => {
|
||||
this.display();
|
||||
}, 200);
|
||||
})
|
||||
);
|
||||
|
||||
if (this.plugin.settings.addNumberToProgressBar) {
|
||||
new Setting(this.containerEl)
|
||||
.setName('Show percentage')
|
||||
.setDesc('Toggle this to allow this plugin to show percentage in the progress bar.')
|
||||
.setName("Show percentage")
|
||||
.setDesc(
|
||||
"Toggle this to allow this plugin to show percentage in the progress bar."
|
||||
)
|
||||
.addToggle((toggle) =>
|
||||
toggle.setValue(this.plugin.settings.showPercentage).onChange(async (value) => {
|
||||
this.plugin.settings.showPercentage = value;
|
||||
this.applySettingsUpdate();
|
||||
}));
|
||||
toggle
|
||||
.setValue(this.plugin.settings.showPercentage)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.showPercentage = value;
|
||||
this.applySettingsUpdate();
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
141
src/utils.ts
Normal file
141
src/utils.ts
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
import { EditorView } from "@codemirror/view";
|
||||
|
||||
import TaskProgressBarPlugin from "./taskProgressBarIndex";
|
||||
import { editorInfoField, MarkdownPostProcessorContext, TFile } from "obsidian";
|
||||
|
||||
|
||||
// Helper function to check if progress bars should be hidden
|
||||
export function shouldHideProgressBarInPreview(
|
||||
plugin: TaskProgressBarPlugin,
|
||||
ctx: MarkdownPostProcessorContext
|
||||
): boolean {
|
||||
if (!plugin.settings.hideProgressBarBasedOnConditions) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const abstractFile = ctx.sourcePath
|
||||
? plugin.app.vault.getAbstractFileByPath(ctx.sourcePath)
|
||||
: null;
|
||||
if (!abstractFile) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if it's a file and not a folder
|
||||
if (!(abstractFile instanceof TFile)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const file = abstractFile as TFile;
|
||||
|
||||
// Check folder paths
|
||||
if (plugin.settings.hideProgressBarFolders) {
|
||||
const folders = plugin.settings.hideProgressBarFolders
|
||||
.split(",")
|
||||
.map((f) => f.trim());
|
||||
const filePath = file.path;
|
||||
|
||||
for (const folder of folders) {
|
||||
if (folder && filePath.startsWith(folder)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check tags
|
||||
if (plugin.settings.hideProgressBarTags) {
|
||||
const tags = plugin.settings.hideProgressBarTags
|
||||
.split(",")
|
||||
.map((t) => t.trim());
|
||||
const fileCache = plugin.app.metadataCache.getFileCache(file);
|
||||
|
||||
if (fileCache && fileCache.tags) {
|
||||
for (const tag of tags) {
|
||||
if (fileCache.tags.some((t) => t.tag === "#" + tag)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check metadata
|
||||
if (plugin.settings.hideProgressBarMetadata) {
|
||||
const metadataCache = plugin.app.metadataCache.getFileCache(file);
|
||||
|
||||
if (metadataCache && metadataCache.frontmatter) {
|
||||
// Parse the metadata string (format: "key: value")
|
||||
const key = plugin.settings.hideProgressBarMetadata;
|
||||
if (key && metadataCache.frontmatter[key] !== undefined) {
|
||||
return !!metadataCache.frontmatter[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Helper function to check if progress bars should be hidden
|
||||
export function shouldHideProgressBarInLivePriview(
|
||||
plugin: TaskProgressBarPlugin,
|
||||
view: EditorView
|
||||
): boolean {
|
||||
if (!plugin.settings.hideProgressBarBasedOnConditions) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the current file
|
||||
const editorInfo = view.state.field(editorInfoField);
|
||||
if (!editorInfo) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const file = editorInfo.file;
|
||||
if (!file) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check folder paths
|
||||
if (plugin.settings.hideProgressBarFolders) {
|
||||
const folders = plugin.settings.hideProgressBarFolders
|
||||
.split(",")
|
||||
.map((f) => f.trim());
|
||||
const filePath = file.path;
|
||||
|
||||
for (const folder of folders) {
|
||||
if (folder && filePath.startsWith(folder)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check tags
|
||||
if (plugin.settings.hideProgressBarTags) {
|
||||
const tags = plugin.settings.hideProgressBarTags
|
||||
.split(",")
|
||||
.map((t) => t.trim());
|
||||
|
||||
// Try to get cache for tags
|
||||
const fileCache = plugin.app.metadataCache.getFileCache(file);
|
||||
if (fileCache && fileCache.tags) {
|
||||
for (const tag of tags) {
|
||||
if (fileCache.tags.some((t) => t.tag === "#" + tag)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check metadata
|
||||
if (plugin.settings.hideProgressBarMetadata) {
|
||||
const metadataCache = plugin.app.metadataCache.getFileCache(file);
|
||||
|
||||
if (metadataCache && metadataCache.frontmatter) {
|
||||
// Parse the metadata string (format: "key: value")
|
||||
const key = plugin.settings.hideProgressBarMetadata;
|
||||
if (key && key in metadataCache.frontmatter) {
|
||||
return !!metadataCache.frontmatter[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
@ -5,23 +5,23 @@ import {
|
|||
ViewPlugin,
|
||||
ViewUpdate,
|
||||
WidgetType,
|
||||
} from '@codemirror/view';
|
||||
} from "@codemirror/view";
|
||||
import { SearchCursor } from "@codemirror/search";
|
||||
import { App, MarkdownView } from 'obsidian';
|
||||
import { EditorState } from "@codemirror/state";
|
||||
import { App, editorInfoField, MarkdownView, TFile } from "obsidian";
|
||||
import { EditorState, Range } from "@codemirror/state";
|
||||
// @ts-ignore
|
||||
import { foldable, syntaxTree, tokenClassNodeProp } from "@codemirror/language";
|
||||
import { RegExpCursor } from "./regexp-cursor";
|
||||
import TaskProgressBarPlugin from "./taskProgressBarIndex";
|
||||
import { shouldHideProgressBarInLivePriview } from "./utils";
|
||||
|
||||
interface tasks {
|
||||
completed: number;
|
||||
total: number;
|
||||
}
|
||||
|
||||
interface Text {
|
||||
text: string;
|
||||
}
|
||||
|
||||
|
||||
|
||||
class TaskProgressBarWidget extends WidgetType {
|
||||
progressBarEl: HTMLSpanElement;
|
||||
|
|
@ -36,7 +36,7 @@ class TaskProgressBarWidget extends WidgetType {
|
|||
readonly from: number,
|
||||
readonly to: number,
|
||||
readonly completed: number,
|
||||
readonly total: number,
|
||||
readonly total: number
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
|
@ -55,48 +55,64 @@ class TaskProgressBarWidget extends WidgetType {
|
|||
if (this.completed !== other.completed || this.total !== other.total) {
|
||||
return false;
|
||||
}
|
||||
if (offset.line === originalOffset.line && this.completed === other.completed && this.total === other.total) {
|
||||
if (
|
||||
offset.line === originalOffset.line &&
|
||||
this.completed === other.completed &&
|
||||
this.total === other.total
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
return other.completed === this.completed && other.total === this.total;
|
||||
}
|
||||
|
||||
changePercentage() {
|
||||
const percentage = Math.round(this.completed / this.total * 10000) / 100;
|
||||
this.progressEl.style.width = percentage + '%';
|
||||
const percentage =
|
||||
Math.round((this.completed / this.total) * 10000) / 100;
|
||||
this.progressEl.style.width = percentage + "%";
|
||||
switch (true) {
|
||||
case percentage >= 0 && percentage < 25:
|
||||
this.progressEl.className = 'progress-bar-inline progress-bar-inline-0';
|
||||
this.progressEl.className =
|
||||
"progress-bar-inline progress-bar-inline-0";
|
||||
break;
|
||||
case percentage >= 25 && percentage < 50:
|
||||
this.progressEl.className = 'progress-bar-inline progress-bar-inline-1';
|
||||
this.progressEl.className =
|
||||
"progress-bar-inline progress-bar-inline-1";
|
||||
break;
|
||||
case percentage >= 50 && percentage < 75:
|
||||
this.progressEl.className = 'progress-bar-inline progress-bar-inline-2';
|
||||
this.progressEl.className =
|
||||
"progress-bar-inline progress-bar-inline-2";
|
||||
break;
|
||||
case percentage >= 75 && percentage < 100:
|
||||
this.progressEl.className = 'progress-bar-inline progress-bar-inline-3';
|
||||
this.progressEl.className =
|
||||
"progress-bar-inline progress-bar-inline-3";
|
||||
break;
|
||||
case percentage >= 100:
|
||||
this.progressEl.className = 'progress-bar-inline progress-bar-inline-4';
|
||||
this.progressEl.className =
|
||||
"progress-bar-inline progress-bar-inline-4";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
changeNumber() {
|
||||
if (this.plugin?.settings.addNumberToProgressBar) {
|
||||
const text = this.plugin?.settings.showPercentage ? `${Math.round(this.completed / this.total * 10000) / 100}%` : `[${this.completed}/${this.total}]`;
|
||||
const text = this.plugin?.settings.showPercentage
|
||||
? `${Math.round((this.completed / this.total) * 10000) / 100}%`
|
||||
: `[${this.completed}/${this.total}]`;
|
||||
|
||||
this.numberEl = this.progressBarEl.createEl('div', {
|
||||
cls: 'progress-status',
|
||||
text: text
|
||||
this.numberEl = this.progressBarEl.createEl("div", {
|
||||
cls: "progress-status",
|
||||
text: text,
|
||||
});
|
||||
}
|
||||
this.numberEl.innerText = `[${this.completed}/${this.total}]`;
|
||||
}
|
||||
|
||||
toDOM() {
|
||||
if (!this.plugin?.settings.addNumberToProgressBar && this.numberEl !== undefined) this.numberEl.detach();
|
||||
if (
|
||||
!this.plugin?.settings.addNumberToProgressBar &&
|
||||
this.numberEl !== undefined
|
||||
)
|
||||
this.numberEl.detach();
|
||||
|
||||
if (this.progressBarEl !== undefined) {
|
||||
this.changePercentage();
|
||||
|
|
@ -104,19 +120,25 @@ class TaskProgressBarWidget extends WidgetType {
|
|||
return this.progressBarEl;
|
||||
}
|
||||
|
||||
this.progressBarEl = createSpan(this.plugin?.settings.addNumberToProgressBar ? 'cm-task-progress-bar with-number' : 'cm-task-progress-bar');
|
||||
this.progressBackGroundEl = this.progressBarEl.createEl('div', {cls: 'progress-bar-inline-background'});
|
||||
this.progressEl = this.progressBackGroundEl.createEl('div');
|
||||
this.progressBarEl = createSpan(
|
||||
this.plugin?.settings.addNumberToProgressBar
|
||||
? "cm-task-progress-bar with-number"
|
||||
: "cm-task-progress-bar"
|
||||
);
|
||||
this.progressBackGroundEl = this.progressBarEl.createEl("div", {
|
||||
cls: "progress-bar-inline-background",
|
||||
});
|
||||
this.progressEl = this.progressBackGroundEl.createEl("div");
|
||||
|
||||
if (this.plugin?.settings.addNumberToProgressBar && this.total) {
|
||||
const text = this.plugin?.settings.showPercentage
|
||||
? `${Math.round((this.completed / this.total) * 10000) / 100}%`
|
||||
: `[${this.completed}/${this.total}]`;
|
||||
|
||||
const text = this.plugin?.settings.showPercentage ? `${Math.round(this.completed / this.total * 10000) / 100}%` : `[${this.completed}/${this.total}]`;
|
||||
|
||||
this.numberEl = this.progressBarEl.createEl('div', {
|
||||
cls: 'progress-status',
|
||||
text: text
|
||||
this.numberEl = this.progressBarEl.createEl("div", {
|
||||
cls: "progress-status",
|
||||
text: text,
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
this.changePercentage();
|
||||
|
|
@ -153,6 +175,14 @@ export function taskProgressBarExtension(app: App, plugin: TaskProgressBarPlugin
|
|||
let {state} = view,
|
||||
// @ts-ignore
|
||||
progressDecos: Range<Decoration>[] = [];
|
||||
|
||||
// Check if progress bars should be hidden based on settings
|
||||
if (shouldHideProgressBarInLivePriview(plugin, view)) {
|
||||
return {
|
||||
progress: Decoration.none,
|
||||
};
|
||||
}
|
||||
|
||||
for (let part of view.visibleRanges) {
|
||||
let taskBulletCursor: RegExpCursor | SearchCursor;
|
||||
let headingCursor: RegExpCursor | SearchCursor;
|
||||
|
|
@ -304,6 +334,7 @@ export function taskProgressBarExtension(app: App, plugin: TaskProgressBarPlugin
|
|||
if (textArray[i].match(headingTotalRegex)) total++;
|
||||
if (textArray[i].match(headingCompleteRegex)) completed++;
|
||||
}
|
||||
|
||||
}
|
||||
return {completed: completed, total: total};
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in a new issue