feat: support percentage

This commit is contained in:
quorafind 2024-01-17 15:35:41 +08:00
parent f33af3adea
commit bb3a77e0cf
3 changed files with 4392 additions and 33 deletions

4328
package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

View file

@ -4,6 +4,7 @@ import { taskProgressBarExtension } from './taskProgressBarWidget';
interface TaskProgressBarSettings {
addTaskProgressBarToHeading: boolean;
addNumberToProgressBar: boolean;
showPercentage: boolean;
allowAlternateTaskStatus: boolean;
alternativeMarks: string;
countSubLevel: boolean;
@ -12,10 +13,11 @@ interface TaskProgressBarSettings {
const DEFAULT_SETTINGS: TaskProgressBarSettings = {
addTaskProgressBarToHeading: false,
addNumberToProgressBar: false,
showPercentage: false,
allowAlternateTaskStatus: false,
alternativeMarks: '(x|X|-)',
countSubLevel: true,
}
};
export default class TaskProgressBarPlugin extends Plugin {
settings: TaskProgressBarSettings;
@ -59,11 +61,11 @@ 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')
@ -74,14 +76,7 @@ class TaskProgressBarSettingTab extends PluginSettingTab {
this.applySettingsUpdate();
}));
new Setting(containerEl)
.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();
}));
this.showNumberToProgressbar();
new Setting(containerEl)
.setName('Only count children of current Task')
@ -119,7 +114,7 @@ class TaskProgressBarSettingTab extends PluginSettingTab {
);
this.containerEl.createEl('h2', { text: 'Say Thank You' });
this.containerEl.createEl('h2', {text: 'Say Thank You'});
new Setting(containerEl)
.setName('Donate')
@ -128,4 +123,31 @@ class TaskProgressBarSettingTab extends PluginSettingTab {
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.')
.addToggle((toggle) =>
toggle.setValue(this.plugin.settings.addNumberToProgressBar).onChange(async (value) => {
this.plugin.settings.addNumberToProgressBar = value;
this.applySettingsUpdate();
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.')
.addToggle((toggle) =>
toggle.setValue(this.plugin.settings.showPercentage).onChange(async (value) => {
this.plugin.settings.showPercentage = value;
this.applySettingsUpdate();
}));
}
}
}

View file

@ -85,12 +85,14 @@ class TaskProgressBarWidget extends WidgetType {
changeNumber() {
if (this.plugin?.settings.addNumberToProgressBar) {
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: `[${ this.completed }/${ this.total }]`
text: text
});
}
this.numberEl.innerText = `[${ this.completed }/${ this.total }]`;
this.numberEl.innerText = `[${this.completed}/${this.total}]`;
}
toDOM() {
@ -103,14 +105,18 @@ class TaskProgressBarWidget extends WidgetType {
}
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.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}]`;
this.numberEl = this.progressBarEl.createEl('div', {
cls: 'progress-status',
text: `[${ this.completed }/${ this.total }]`
text: text
});
}
this.changePercentage();
@ -130,13 +136,13 @@ export function taskProgressBarExtension(app: App, plugin: TaskProgressBarPlugin
constructor(public view: EditorView) {
let { progress } = this.getDeco(view);
let {progress} = this.getDeco(view);
this.progressDecorations = progress;
}
update(update: ViewUpdate) {
if (update.docChanged || update.viewportChanged) {
let { progress } = this.getDeco(update.view);
let {progress} = this.getDeco(update.view);
this.progressDecorations = progress;
}
}
@ -144,14 +150,14 @@ export function taskProgressBarExtension(app: App, plugin: TaskProgressBarPlugin
getDeco(view: EditorView): {
progress: DecorationSet;
} {
let { state } = view,
let {state} = view,
// @ts-ignore
progressDecos: Range<Decoration>[] = [];
for (let part of view.visibleRanges) {
let taskBulletCursor: RegExpCursor | SearchCursor;
let headingCursor: RegExpCursor | SearchCursor;
try {
taskBulletCursor = new RegExpCursor(state.doc, "^\\s*([-*+]|\\d+\\.)\\s\\[(.)\\]", {}, part.from, part.to);
taskBulletCursor = new RegExpCursor(state.doc, "^[\\t|\\s]*([-*+]|\\d+\\.)\\s\\[(.)\\]", {}, part.from, part.to);
} catch (err) {
console.debug(err);
continue;
@ -165,7 +171,7 @@ export function taskProgressBarExtension(app: App, plugin: TaskProgressBarPlugin
}
// Showing task progress bar near heading items.
while (!headingCursor.next().done) {
let { from, to } = headingCursor.value;
let {from, to} = headingCursor.value;
const headingLine = this.view.state.doc.lineAt(from);
// @ts-ignore
const range = this.calculateRangeForTransform(this.view.state, headingLine.from);
@ -186,13 +192,13 @@ export function taskProgressBarExtension(app: App, plugin: TaskProgressBarPlugin
tasksNum = this.calculateTasksNum(this.view.state.doc.slice(range.from, range.to).text, false);
}
if (tasksNum?.total === 0) continue;
let startDeco = Decoration.widget({ widget: new TaskProgressBarWidget(app, plugin, view, headingLine.to, headingLine.to, tasksNum.completed, tasksNum.total) });
let startDeco = Decoration.widget({widget: new TaskProgressBarWidget(app, plugin, view, headingLine.to, headingLine.to, tasksNum.completed, tasksNum.total)});
progressDecos.push(startDeco.range(headingLine.to, headingLine.to));
}
}
// Showing task progress bar near bullet items.
while (!taskBulletCursor.next().done) {
let { from } = taskBulletCursor.value;
let {from} = taskBulletCursor.value;
const linePos = view.state.doc.lineAt(from)?.from;
// Don't parse any tasks in code blocks or frontmatter
@ -208,7 +214,7 @@ export function taskProgressBarExtension(app: App, plugin: TaskProgressBarPlugin
// @ts-ignore
if (!(/^\s*([-*+]|\d+\.)\s\[(.)\]/.test(this.view.state.doc.slice(line.from, line.to).text))) return;
if (!(/^[\s|\t]*([-*+]|\d+\.)\s\[(.)\]/.test(this.view.state.doc.slice(line.from, line.to).text))) return;
// @ts-ignore
const range = this.calculateRangeForTransform(this.view.state, line.to);
if (!range) continue;
@ -229,7 +235,7 @@ export function taskProgressBarExtension(app: App, plugin: TaskProgressBarPlugin
tasksNum = this.calculateTasksNum(this.view.state.doc.slice(range.from, range.to).text, true);
}
if (tasksNum.total === 0) continue;
let startDeco = Decoration.widget({ widget: new TaskProgressBarWidget(app, plugin, view, line.to, line.to, tasksNum.completed, tasksNum.total) });
let startDeco = Decoration.widget({widget: new TaskProgressBarWidget(app, plugin, view, line.to, line.to, tasksNum.completed, tasksNum.total)});
progressDecos.push(startDeco.range(line.to, line.to));
}
}
@ -247,23 +253,26 @@ export function taskProgressBarExtension(app: App, plugin: TaskProgressBarPlugin
return null;
}
return { from: line.from, to: foldRange.to };
return {from: line.from, to: foldRange.to};
}
public calculateTasksNum(textArray: string[], bullet: boolean): tasks {
let completed: number = 0;
let total: number = 0;
let level: number = 0;
if (!textArray) return { completed: 0, total: 0 };
if (!textArray) return {completed: 0, total: 0};
// @ts-ignore
const tabSize = app.vault.getConfig("tabSize");
let bulletCompleteRegex: RegExp = new RegExp("\\s+([-*+]|\\d+\\.)\\s+\\[[^ ]\\]");
let bulletTotalRegex: RegExp = new RegExp("[\\t|\\s]+([-*+]|\\d+\\.)\\s\\[(.)\\]");
const useTab = (app.vault.getConfig("useTab") === undefined || app.vault.getConfig("useTab") === true);
// @ts-ignore
const tabSize = useTab ? app.vault.getConfig("tabSize") / 4 : app.vault.getConfig("tabSize");
let bulletCompleteRegex: RegExp = new RegExp(/[\t|\s]+([-*+]|\d+\.)\s+\[[^ ]\]/);
let bulletTotalRegex: RegExp = new RegExp(/[\t|\s]+([-*+]|\d+\.)\s\[(.)\]/);
let headingCompleteRegex: RegExp = new RegExp("([-*+]|\\d+\\.)\\s+\\[[^ ]\\]");
let headingTotalRegex: RegExp = new RegExp("([-*+]|\\d+\\.)\\s\\[(.)\\]");
if (plugin?.settings.countSubLevel && bullet) {
// @ts-ignore
level = textArray[0].match(/^\s*/)[0].length / tabSize;
level = textArray[0].match(/^[\s|\t]*/)[0].length / tabSize;
// Total regex based on indent level
bulletTotalRegex = new RegExp("^[\\t|\\s]{" + (tabSize * (level + 1)) + "}([-*+]|\\d+\\.)\\s\\[(.)\\]");
}
@ -272,7 +281,7 @@ export function taskProgressBarExtension(app: App, plugin: TaskProgressBarPlugin
headingTotalRegex = new RegExp("^([-*+]|\\d+\\.)\\s\\[(.)\\]");
}
if (plugin?.settings.alternativeMarks.length > 0 && plugin?.settings.allowAlternateTaskStatus) {
bulletCompleteRegex = level !== 0 ? new RegExp("^\\s{" + (tabSize * (level + 1)) + "}([-*+]|\\d+\\.)\\s\\[" + plugin?.settings.alternativeMarks + "\\]") : new RegExp("\\s+([-*+]|\\d+\\.)\\s\\[" + plugin?.settings.alternativeMarks + "\\]");
bulletCompleteRegex = level !== 0 ? new RegExp("^[\\t|\\s]{" + (tabSize * (level + 1)) + "}([-*+]|\\d+\\.)\\s\\[" + plugin?.settings.alternativeMarks + "\\]") : new RegExp("[\\t|\\s]+([-*+]|\\d+\\.)\\s\\[" + plugin?.settings.alternativeMarks + "\\]");
if (plugin?.settings.addTaskProgressBarToHeading) {
headingCompleteRegex = level !== 0 ? new RegExp("^([-*+]|\\d+\\.)\\s+\\[" + plugin?.settings.alternativeMarks + "\\]") : new RegExp("([-*+]|\\d+\\.)\\s+\\[" + plugin?.settings.alternativeMarks + "\\]");
}
@ -291,7 +300,7 @@ export function taskProgressBarExtension(app: App, plugin: TaskProgressBarPlugin
if (textArray[i].match(headingCompleteRegex)) completed++;
}
}
return { completed: completed, total: total };
return {completed: completed, total: total};
};
},
{