diff --git a/.gitignore b/.gitignore index 496ada1..117482e 100644 --- a/.gitignore +++ b/.gitignore @@ -10,4 +10,4 @@ main.js # Comment one of the following lock file in your plugin! pnpm-lock.yaml -npm-lock.yaml \ No newline at end of file +npm-lock.yaml diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..117482e --- /dev/null +++ b/.prettierignore @@ -0,0 +1,13 @@ +dist/ + +# npm +node_modules +package-lock.json + +# Outputs +main.js +*.js.map + +# Comment one of the following lock file in your plugin! +pnpm-lock.yaml +npm-lock.yaml diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 0000000..0967ef4 --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1 @@ +{} diff --git a/data.json b/data.json index e70da4a..ffa7684 100644 --- a/data.json +++ b/data.json @@ -1 +1,12 @@ -{"vimMode":false,"defaultPriority":30,"queueFolderPath":"IW-Queues","queueFilePath":"queue.md","defaultAFactor":2,"defaultInterval":1,"defaultQueueType":"simple","defaultPriorityMin":35,"defaultPriorityMax":90,"skipAddNoteWindow":true} \ No newline at end of file +{ + "vimMode": false, + "defaultPriority": 30, + "queueFolderPath": "IW-Queues", + "queueFilePath": "queue.md", + "defaultAFactor": 2, + "defaultInterval": 1, + "defaultQueueType": "afactor", + "defaultPriorityMin": 27, + "defaultPriorityMax": 85, + "skipAddNoteWindow": true +} diff --git a/manifest.json b/manifest.json index 9df30d9..0181db2 100644 --- a/manifest.json +++ b/manifest.json @@ -1,10 +1,10 @@ -{ - "id": "obsidian-incremental-writing", - "name": "Incremental Writing", - "description": "Incrementally review notes and blocks over time.", - "isDesktopOnly": true, - "version": "0.3.4", - "author": "Experimental Learning", - "authorUrl": "https://github.com/bjsi/incremental-writing", - "js": "main.js" -} +{ + "id": "obsidian-incremental-writing", + "name": "Incremental Writing", + "description": "Incrementally review notes and blocks over time.", + "isDesktopOnly": true, + "version": "0.3.4", + "author": "Experimental Learning", + "authorUrl": "https://github.com/bjsi/incremental-writing", + "js": "main.js" +} diff --git a/package.json b/package.json index 486b637..8bd7bca 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "@rollup/plugin-typescript": "8.1.1", "@types/node": "14.14.25", "obsidian": "https://github.com/obsidianmd/obsidian-api/tarball/master", + "prettier": "2.2.1", "rollup": "2.38.5", "tslib": "2.1.0", "typescript": "4.1.3" diff --git a/rollup.config.js b/rollup.config.js index 4407f32..6861632 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -1,15 +1,15 @@ -import typescript from "@rollup/plugin-typescript"; -import { nodeResolve } from "@rollup/plugin-node-resolve"; -import commonjs from "@rollup/plugin-commonjs"; - -export default { - input: "./src/main.ts", - output: { - dir: ".", - sourcemap: "inline", - format: "cjs", - exports: "default", - }, - external: ["obsidian"], - plugins: [typescript(), nodeResolve({ browser: true }), commonjs()], -}; +import typescript from "@rollup/plugin-typescript"; +import { nodeResolve } from "@rollup/plugin-node-resolve"; +import commonjs from "@rollup/plugin-commonjs"; + +export default { + input: "./src/main.ts", + output: { + dir: ".", + sourcemap: "inline", + format: "cjs", + exports: "default", + }, + external: ["obsidian"], + plugins: [typescript(), nodeResolve({ browser: true }), commonjs()], +}; diff --git a/src/hashset.ts b/src/hashset.ts deleted file mode 100644 index a98d3a0..0000000 --- a/src/hashset.ts +++ /dev/null @@ -1,27 +0,0 @@ -export class HashSet { - private values= {} - - //@ts-ignore - add(val) { - //@ts-ignore - this.values[val] = true - } - - //@ts-ignore - has(val) { - //@ts-ignore - return this.values[val] === true - - } - - //@ts-ignore - remove(val) { - //@ts-ignore - delete this.values[val] - - } - - getValues() { - return Object.keys(this.values) - } -} diff --git a/src/helpers/block-utils.ts b/src/helpers/block-utils.ts index 1cae737..0169856 100644 --- a/src/helpers/block-utils.ts +++ b/src/helpers/block-utils.ts @@ -1,40 +1,43 @@ -import { ObsidianUtilsBase } from "./obsidian-utils-base" -import { App, TFile } from "obsidian" +import { ObsidianUtilsBase } from "./obsidian-utils-base"; +import { App, TFile } from "obsidian"; export class BlockUtils extends ObsidianUtilsBase { + constructor(app: App) { + super(app); + } - constructor (app: App){ - super(app); - } - - // TODO: Rewrite - getBlock(inputLine: string, noteFile: TFile): string { //Returns the string of a block ID if block is found, or "" if not. - let noteBlocks = this.app.metadataCache.getFileCache(noteFile).blocks; - console.log("Checking if line '" + inputLine + "' is a block."); - let blockString = ""; - if (noteBlocks) { // the file does contain blocks. If not, return "" - for (let eachBlock in noteBlocks) { // iterate through the blocks. - console.log("Checking block ^" + eachBlock); - let blockRegExp = new RegExp("(" + eachBlock + ")$", "gim"); - if (inputLine.match(blockRegExp)) { // if end of inputLine matches block, return it - blockString = eachBlock; - console.log("Found block ^" + blockString); - return blockString; - } - } - return blockString; - } - return blockString; + // TODO: Rewrite + getBlock(inputLine: string, noteFile: TFile): string { + //Returns the string of a block ID if block is found, or "" if not. + let noteBlocks = this.app.metadataCache.getFileCache(noteFile).blocks; + console.log("Checking if line '" + inputLine + "' is a block."); + let blockString = ""; + if (noteBlocks) { + // the file does contain blocks. If not, return "" + for (let eachBlock in noteBlocks) { + // iterate through the blocks. + console.log("Checking block ^" + eachBlock); + let blockRegExp = new RegExp("(" + eachBlock + ")$", "gim"); + if (inputLine.match(blockRegExp)) { + // if end of inputLine matches block, return it + blockString = eachBlock; + console.log("Found block ^" + blockString); + return blockString; + } + } + return blockString; } + return blockString; + } - createBlockHash(): string { - // Credit to https://stackoverflow.com/a/1349426 - let result = ''; - var characters = 'abcdefghijklmnopqrstuvwxyz0123456789'; - var charactersLength = characters.length; - for ( var i = 0; i < 7; i++ ) { - result += characters.charAt(Math.floor(Math.random() * charactersLength)); - } - return result; + createBlockHash(): string { + // Credit to https://stackoverflow.com/a/1349426 + let result = ""; + var characters = "abcdefghijklmnopqrstuvwxyz0123456789"; + var charactersLength = characters.length; + for (var i = 0; i < 7; i++) { + result += characters.charAt(Math.floor(Math.random() * charactersLength)); } + return result; + } } diff --git a/src/helpers/date-utils.ts b/src/helpers/date-utils.ts index 88a28e4..66f16e0 100644 --- a/src/helpers/date-utils.ts +++ b/src/helpers/date-utils.ts @@ -1,31 +1,28 @@ export class DateUtils { - static addDays(date: Date, days: number) { - var result = new Date(date); - result.setDate(result.getDate() + days); - return result; - } + static addDays(date: Date, days: number) { + var result = new Date(date); + result.setDate(result.getDate() + days); + return result; + } - static formatDate(d: Date) { - - var month = '' + (d.getMonth() + 1); - var day = '' + d.getDate(); - var year = d.getFullYear(); + static formatDate(d: Date) { + var month = "" + (d.getMonth() + 1); + var day = "" + d.getDate(); + var year = d.getFullYear(); - if (month.length < 2) - month = '0' + month; - if (day.length < 2) - day = '0' + day; + if (month.length < 2) month = "0" + month; + if (day.length < 2) day = "0" + day; - return [year, month, day].join('-'); - } + return [year, month, day].join("-"); + } - static isValid(date: Date) { - return (date instanceof Date && !isNaN(date.valueOf())) - } + static isValid(date: Date) { + return date instanceof Date && !isNaN(date.valueOf()); + } - static dateDifference(date1: Date, date2: Date) { - const oneDay = 24 * 60 * 60 * 1000; // hours*minutes*seconds*milliseconds - // @ts-ignore - return Math.round(Math.abs((date1 - date2) / oneDay)); - } + static dateDifference(date1: Date, date2: Date) { + const oneDay = 24 * 60 * 60 * 1000; // hours*minutes*seconds*milliseconds + // @ts-ignore + return Math.round(Math.abs((date1 - date2) / oneDay)); + } } diff --git a/src/helpers/file-utils.ts b/src/helpers/file-utils.ts index a734dcb..1b2205b 100644 --- a/src/helpers/file-utils.ts +++ b/src/helpers/file-utils.ts @@ -1,58 +1,63 @@ -import { normalizePath, MarkdownView, App, TFile, TFolder } from "obsidian" -import { ObsidianUtilsBase } from "./obsidian-utils-base" +import { normalizePath, MarkdownView, App, TFile, TFolder } from "obsidian"; +import { ObsidianUtilsBase } from "./obsidian-utils-base"; // TODO: read: https://github.com/lynchjames/obsidian-day-planner/blob/d1eb7ce187e7757b7a3880358a6ee184b3b025da/src/file.ts#L48 export class FileUtils extends ObsidianUtilsBase { - - constructor(app: App) { - super(app); - } - - async createIfNotExists(file: string, data: string) { - const normalizedPath = normalizePath(file); - if (!await this.app.vault.adapter.exists(normalizedPath)) { - let folderPath = this.getParentOfNormalized(normalizedPath); - await this.createFolders(folderPath); - await this.app.vault.create(normalizedPath, data); - } - } - - toLinkText(file: TFile) { - return this.app.metadataCache.fileToLinktext(file, file.path, true); - } - - getParentOfNormalized(normalizedPath: string) { - let pathSplit = normalizedPath.split('/'); - return pathSplit.slice(0, pathSplit.length - 1).join('/'); - } - - async createFolders(normalizedPath: string) { - let current = normalizedPath; - while (current && !await this.app.vault.adapter.exists(current)) { - await this.app.vault.createFolder(current); - current = this.getParentOfNormalized(current); - } - } - - isDescendantOf(file: TFile, folder: TFolder): boolean { - let ancestor = file.parent; - while (ancestor && !ancestor.isRoot()) { - if (ancestor === folder) { - return true; - } - ancestor = ancestor.parent; - } - return false; - } - - async goTo(filePath: string, newLeaf: boolean) { - let file = this.app.vault.getAbstractFileByPath(filePath) as TFile; - let link = this.app.metadataCache.fileToLinktext(file, ""); - await this.app.workspace.openLinkText(link, "", newLeaf); - } - - getActiveNoteFile() { - return (this.app.workspace.activeLeaf.view as MarkdownView).file; - } + constructor(app: App) { + super(app); + } + + async createIfNotExists(file: string, data: string) { + const normalizedPath = normalizePath(file); + if (!(await this.app.vault.adapter.exists(normalizedPath))) { + let folderPath = this.getParentOfNormalized(normalizedPath); + await this.createFolders(folderPath); + await this.app.vault.create(normalizedPath, data); + } + } + + getTFile(filePath: string) { + let file = this.app.vault.getAbstractFileByPath(filePath); + if (file instanceof TFile) return file; + return null; + } + + toLinkText(file: TFile) { + return this.app.metadataCache.fileToLinktext(file, "", true); + } + + getParentOfNormalized(normalizedPath: string) { + let pathSplit = normalizedPath.split("/"); + return pathSplit.slice(0, pathSplit.length - 1).join("/"); + } + + async createFolders(normalizedPath: string) { + let current = normalizedPath; + while (current && !(await this.app.vault.adapter.exists(current))) { + await this.app.vault.createFolder(current); + current = this.getParentOfNormalized(current); + } + } + + isDescendantOf(file: TFile, folder: TFolder): boolean { + let ancestor = file.parent; + while (ancestor && !ancestor.isRoot()) { + if (ancestor === folder) { + return true; + } + ancestor = ancestor.parent; + } + return false; + } + + async goTo(filePath: string, newLeaf: boolean) { + let file = this.app.vault.getAbstractFileByPath(filePath) as TFile; + let link = this.app.metadataCache.fileToLinktext(file, ""); + await this.app.workspace.openLinkText(link, "", newLeaf); + } + + getActiveNoteFile() { + return this.app.workspace.getActiveViewOfType(MarkdownView)?.file; + } } diff --git a/src/helpers/functools.ts b/src/helpers/functools.ts index 858f1b2..8c51406 100644 --- a/src/helpers/functools.ts +++ b/src/helpers/functools.ts @@ -1,23 +1,23 @@ // From: https://decipher.dev/30-seconds-of-typescript/docs/throttle/ export const throttle = (fn: Function, wait: number = 300) => { - let inThrottle: boolean, + let inThrottle: boolean, lastFn: ReturnType, lastTime: number; - return function (this: any) { - const context = this, - args = arguments; - if (!inThrottle) { - fn.apply(context, args); - lastTime = Date.now(); - inThrottle = true; - } else { - clearTimeout(lastFn); - lastFn = setTimeout(() => { - if (Date.now() - lastTime >= wait) { - fn.apply(context, args); - lastTime = Date.now(); - } - }, Math.max(wait - (Date.now() - lastTime), 0)); + return function (this: any) { + const context = this, + args = arguments; + if (!inThrottle) { + fn.apply(context, args); + lastTime = Date.now(); + inThrottle = true; + } else { + clearTimeout(lastFn); + lastFn = setTimeout(() => { + if (Date.now() - lastTime >= wait) { + fn.apply(context, args); + lastTime = Date.now(); } - }; + }, Math.max(wait - (Date.now() - lastTime), 0)); + } + }; }; diff --git a/src/helpers/link-utils.ts b/src/helpers/link-utils.ts index aa7d305..40fd367 100644 --- a/src/helpers/link-utils.ts +++ b/src/helpers/link-utils.ts @@ -1,45 +1,39 @@ -import { App, TFile } from "obsidian" -import { ObsidianUtilsBase } from "./obsidian-utils-base" -import { getLinkpath, normalizePath } from "obsidian" +import { App, TFile } from "obsidian"; +import { ObsidianUtilsBase } from "./obsidian-utils-base"; +import { getLinkpath, normalizePath } from "obsidian"; export class LinkEx extends ObsidianUtilsBase { - - constructor(app: App) { - super(app) - } + constructor(app: App) { + super(app); + } - static addBrackets(link: string) { - if (!link.startsWith("[[")) - link = "[[" + link; + static addBrackets(link: string) { + if (!link.startsWith("[[")) link = "[[" + link; - if (!link.endsWith("]]")) - link = link + "]]"; + if (!link.endsWith("]]")) link = link + "]]"; - return link; - } + return link; + } - getLink(path: string): string { - let file = this.app.vault.getAbstractFileByPath(path) as TFile; - return this.app.metadataCache.fileToLinktext(file, ""); + static removeBrackets(link: string) { + if (link.startsWith("[[")) { + link = link.substr(2); } - static removeBrackets(link: string) { - if (link.startsWith("[[")) - link = link.substr(2) - - if (link.endsWith("]]")) - link = link.substr(0, link.length - 2); - - return link; + if (link.endsWith("]]")) { + link = link.substr(0, link.length - 2); } - getLinksIn(file: TFile): string[] { - let links = this.app.metadataCache.getFileCache(file).links; - if (links) - return links - .map(l => getLinkpath(l.link)) - .map(l => this.app.metadataCache.getFirstLinkpathDest(l, file.path)) - .map(f => f.path) - return [] - } + return link; + } + + getLinksIn(file: TFile): string[] { + let links = this.app.metadataCache.getFileCache(file).links; + if (links) + return links + .map((l) => getLinkpath(l.link)) + .map((l) => this.app.metadataCache.getFirstLinkpathDest(l, file.path)) + .map((f) => f.path); + return []; + } } diff --git a/src/helpers/obsidian-utils-base.ts b/src/helpers/obsidian-utils-base.ts index 9483b91..b478ec0 100644 --- a/src/helpers/obsidian-utils-base.ts +++ b/src/helpers/obsidian-utils-base.ts @@ -1,11 +1,9 @@ -import { App } from "obsidian" +import { App } from "obsidian"; export abstract class ObsidianUtilsBase { - - app: App + app: App; - constructor(app: App) { - this.app = app; - } + constructor(app: App) { + this.app = app; + } } - diff --git a/src/helpers/priority-utils.ts b/src/helpers/priority-utils.ts index a2c93aa..5106ebb 100644 --- a/src/helpers/priority-utils.ts +++ b/src/helpers/priority-utils.ts @@ -1,9 +1,9 @@ export class PriorityUtils { - static isValid(p: number) { - return (!isNaN(p) && (p >= 0 && p <= 100)); - } + static isValid(p: number) { + return !isNaN(p) && p >= 0 && p <= 100; + } - static getPriorityBetween(pMin: number, pMax: number) { - return Math.random() * (pMax - pMin) + pMin; - } + static getPriorityBetween(pMin: number, pMax: number) { + return Math.random() * (pMax - pMin) + pMin; + } } diff --git a/src/logger.ts b/src/logger.ts index 9bca9c9..90ed833 100644 --- a/src/logger.ts +++ b/src/logger.ts @@ -1,19 +1,17 @@ -import { Notice } from "obsidian" +import { Notice } from "obsidian"; export class LogTo { - static getTime() { - return new Date().toTimeString().substr(0, 8); - } + static getTime() { + return new Date().toTimeString().substr(0, 8); + } - static Debug(message: string, notify: boolean = false) { - console.debug(`[${LogTo.getTime()}] (IW Plugin): ${message}`); - if (notify) - new Notice(message); - } + static Debug(message: string, notify: boolean = false) { + console.debug(`[${LogTo.getTime()}] (IW Plugin): ${message}`); + if (notify) new Notice(message); + } - static Console(message: string, notify: boolean = false) { - console.log(`[${LogTo.getTime()}] (IW Plugin): ${message}`); - if (notify) - new Notice(message); - } + static Console(message: string, notify: boolean = false) { + console.log(`[${LogTo.getTime()}] (IW Plugin): ${message}`); + if (notify) new Notice(message); + } } diff --git a/src/main.ts b/src/main.ts index 1431dc8..f461097 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,258 +1,280 @@ -import { TFolder, Plugin, TFile, ButtonComponent } from "obsidian"; -import { Queue } from "./queue" -import { LogTo } from "./logger" -import { ReviewFileModal, ReviewNoteModal, ReviewBlockModal } from "./views/modals" -import { IWSettings, DefaultSettings } from "./settings" -import { IWSettingsTab } from "./views/settings-tab" -import { StatusBar } from "./views/status-bar" -import { QueueLoadModal } from "./views/queue-modal" -import { LinkEx } from "./helpers/link-utils" -import { FileUtils } from "./helpers/file-utils" -import { BulkAdderModal } from "./views/bulk-adding" -import { BlockUtils } from "./helpers/block-utils" -import { FuzzyNoteAdder } from "./views/fuzzy-note-adder" - - -export default class IW extends Plugin { - - settings: IWSettings; - statusBar: StatusBar - queue: Queue; - - // - // Utils - - links: LinkEx = new LinkEx(this.app); - files: FileUtils = new FileUtils(this.app); - blocks: BlockUtils = new BlockUtils(this.app); - - async loadConfig() { - this.settings = (await this.loadData()) || new DefaultSettings(); - this.addSettingTab(new IWSettingsTab(this.app, this)); - } - - getDefaultQueuePath() { - return [this.settings.queueFolderPath, this.settings.queueFilePath].join("/") - } - - async onload() { - LogTo.Console("Loading..."); - await this.loadConfig(); - this.registerCommands(); - this.subscribeToEvents(); - this.createStatusBar(); - let queuePath = this.getDefaultQueuePath(); - this.queue = new Queue(this, queuePath); - this.statusBar.updateCurrentQueue(queuePath) - } - - async getFound() { - const searchLeaf = this.app.workspace.getLeavesOfType('search')[0]; - const view = await searchLeaf.open(searchLeaf.view); - // @ts-ignore - return Array.from(view.dom.resultDomLookup.keys()); - } - - async addSearchButton() { - const searchLeaf = this.app.workspace.getLeavesOfType('search')[0]; - const view = await searchLeaf.open(searchLeaf.view); - let btn = (view).addToQueueButton; - - if (!btn){ - (view).addToQueueButton = new ButtonComponent(view.containerEl.children[0].firstChild as HTMLElement) - .setClass("nav-action-button") - .setIcon("sheets-in-box") - .setTooltip("Add to IW Queue") - .setDisabled(false) - .onClick(async () => await this.addSearchResultsToQueue()) - } - } - - async getSearchResults(): Promise { - return await this.getFound() as TFile[]; - } - - async addSearchResultsToQueue() { - let files = await this.getSearchResults(); - let links = files.map(file => file.path); - if (links) { - new BulkAdderModal(this, this.queue.queuePath, links).open(); - } - else { - LogTo.Console("No files to add.", true); - } - } - - loadQueue(filePath: string) { - if (filePath) { - this.statusBar.updateCurrentQueue(filePath); - this.queue = new Queue(this, filePath); - LogTo.Console("Loaded Queue: " + filePath, true); - } - else { - LogTo.Console("Failed to load queue: " + filePath, true); - } - } - - registerCommands() { - - // - // Queue Browsing - - this.addCommand({ - id: 'open-queue-current-pane', - name: 'Open queue in current pane.', - callback: () => this.queue.goToQueue(false), - hotkeys: [], - }); - - this.addCommand({ - id: 'open-queue-new-pane', - name: 'Open queue in new pane.', - callback: () => this.queue.goToQueue(true), - hotkeys: [], - }); - - // - // Repetitions - - this.addCommand({ - id: 'current-iw-repetition', - name: 'Current repetition.', - callback: () => this.queue.goToCurrentRep(), - hotkeys: [] - }); - - this.addCommand({ - id: 'dismiss-current-repetition', - name: 'Dismiss current repetition.', - callback: () => this.queue.dismissCurrent(), - hotkeys: [] - }); - - this.addCommand({ - id: 'next-iw-repetition', - name: 'Next repetition.', - callback: () => this.queue.nextRepetition(), - hotkeys: [] - }); - - // - // Element Adding. - - this.addCommand({ - id: 'note-add-iw-queue', - name: 'Add note to queue.', - callback: () => new ReviewNoteModal(this).open() - }); - - this.addCommand({ - id: 'fuzzy-note-add-iw-queue', - name: 'Add note to queue through a fuzzy finder', - callback: () => { - let leaf = this.app.workspace.activeLeaf; - if (leaf) { - new FuzzyNoteAdder(this).open(); - } - }, - hotkeys: [] - }); - - this.addCommand({ - id: 'block-add-iw-queue', - name: 'Add block to queue.', - callback: () => { - let leaf = this.app.workspace.activeLeaf; - if (leaf) { - new ReviewBlockModal(this).open(); - } - }, - hotkeys: [] - }); - - this.addCommand({ - id: 'add-links-within-note', - name: 'Add links within note to queue.', - callback: () => { - let leaf = this.app.workspace.activeLeaf; - if (leaf) { - let file = this.files.getActiveNoteFile(); - if (file) { - let links = this.links.getLinksIn(file); - if (links && links.length) - new BulkAdderModal(this, this.queue.queuePath, links).open(); - else - LogTo.Console("No links in the current file.", true); - } - } - }, - hotkeys: [] - }) - - // - // Queue Loading - - this.addCommand({ - id: 'load-iw-queue', - name: 'Load a queue.', - callback: () => { - let leaf = this.app.workspace.activeLeaf; - if (leaf) { - new QueueLoadModal(this).open(); - } - }, - hotkeys: [] - }); - } - - createStatusBar() { - this.statusBar = new StatusBar(this.addStatusBarItem(), this); - this.statusBar.initStatusBar(); - } - - subscribeToEvents() { - this.app.workspace.onLayoutReady(() => { - this.addSearchButton(); - }); - - this.registerEvent( - this.app.workspace.on('file-menu', (menu, file, source: string) => { - if (file === null) { - return; - } - - if (file instanceof TFile && file.extension === "md") { - menu.addItem((item) => { - item.setTitle(`Add File to IW Queue`) - .setIcon('sheets-in-box') - .onClick((evt) => { - new ReviewFileModal(this, file.path).open(); - }); - }); - } - else if (file instanceof TFolder) { - menu.addItem((item) => { - item.setTitle(`Add Folder to IW Queue`) - .setIcon('sheets-in-box') - .onClick((evt) => { - let files = this.app.vault.getMarkdownFiles() - .filter(f => this.files.isDescendantOf(f, file)) - .map(f => f.path); - - if (files){ - new BulkAdderModal(this, this.queue.queuePath, files).open(); - } - else - LogTo.Console("Folder contains no files!", true); - }); - }); - } - })); - } - - onunload() { - LogTo.Console("Disabled and unloaded."); - // TODO: Remove button from search - // TODO: Remove Status bar - } -} +import { TFolder, Plugin, TFile, ButtonComponent } from "obsidian"; +import { Queue } from "./queue"; +import { LogTo } from "./logger"; +import { + ReviewFileModal, + ReviewNoteModal, + ReviewBlockModal, +} from "./views/modals"; +import { IWSettings, DefaultSettings } from "./settings"; +import { IWSettingsTab } from "./views/settings-tab"; +import { StatusBar } from "./views/status-bar"; +import { QueueLoadModal } from "./views/queue-modal"; +import { LinkEx } from "./helpers/link-utils"; +import { FileUtils } from "./helpers/file-utils"; +import { BulkAdderModal } from "./views/bulk-adding"; +import { BlockUtils } from "./helpers/block-utils"; +import { FuzzyNoteAdder } from "./views/fuzzy-note-adder"; + +export default class IW extends Plugin { + settings: IWSettings; + statusBar: StatusBar; + queue: Queue; + + // + // Utils + + links: LinkEx = new LinkEx(this.app); + files: FileUtils = new FileUtils(this.app); + blocks: BlockUtils = new BlockUtils(this.app); + + async loadConfig() { + this.settings = this.settings = Object.assign( + {}, + DefaultSettings, + await this.loadData() + ); + } + + getDefaultQueuePath() { + return [this.settings.queueFolderPath, this.settings.queueFileName].join( + "/" + ); + } + + async onload() { + LogTo.Console("Loading..."); + await this.loadConfig(); + this.addSettingTab(new IWSettingsTab(this.app, this)); + this.registerCommands(); + this.subscribeToEvents(); + this.createStatusBar(); + let queuePath = this.getDefaultQueuePath(); + this.queue = new Queue(this, queuePath); + this.statusBar.updateCurrentQueue(queuePath); + } + + async getSearchLeafView() { + return this.app.workspace.getLeavesOfType("search")[0]?.view; + } + + async getFound() { + const view = await this.getSearchLeafView(); + if (!view) { + LogTo.Console("Failed to get search leaf view."); + return []; + } + // @ts-ignore + return Array.from(view.dom.resultDomLookup.keys()); + } + + async addSearchButton() { + const view = await this.getSearchLeafView(); + if (!view) { + LogTo.Console("Failed to add button to the search pane."); + return; + } + (view).addToQueueButton = new ButtonComponent( + view.containerEl.children[0].firstChild as HTMLElement + ) + .setClass("nav-action-button") + .setIcon("sheets-in-box") + .setTooltip("Add to IW Queue") + .onClick(async () => await this.addSearchResultsToQueue()); + } + + async getSearchResults(): Promise { + return (await this.getFound()) as TFile[]; + } + + async addSearchResultsToQueue() { + let files = await this.getSearchResults(); + let links = files.map((file) => file.path); + if (links) { + new BulkAdderModal(this, this.queue.queuePath, links).open(); + } else { + LogTo.Console("No files to add.", true); + } + } + + loadQueue(filePath: string) { + if (filePath) { + this.statusBar.updateCurrentQueue(filePath); + this.queue = new Queue(this, filePath); + LogTo.Console("Loaded Queue: " + filePath, true); + } else { + LogTo.Console("Failed to load queue: " + filePath, true); + } + } + + registerCommands() { + // + // Queue Browsing + + this.addCommand({ + id: "open-queue-current-pane", + name: "Open queue in current pane.", + callback: () => this.queue.goToQueue(false), + hotkeys: [], + }); + + this.addCommand({ + id: "open-queue-new-pane", + name: "Open queue in new pane.", + callback: () => this.queue.goToQueue(true), + hotkeys: [], + }); + + // + // Repetitions + + this.addCommand({ + id: "current-iw-repetition", + name: "Current repetition.", + callback: () => this.queue.goToCurrentRep(), + hotkeys: [], + }); + + this.addCommand({ + id: "dismiss-current-repetition", + name: "Dismiss current repetition.", + callback: () => this.queue.dismissCurrent(), + hotkeys: [], + }); + + this.addCommand({ + id: "next-iw-repetition", + name: "Next repetition.", + callback: () => this.queue.nextRepetition(), + hotkeys: [], + }); + + // + // Element Adding. + + this.addCommand({ + id: "note-add-iw-queue", + name: "Add note to queue.", + checkCallback: (checking: boolean) => { + if (checking) { + return this.files.getActiveNoteFile() != null; + } + new ReviewNoteModal(this).open(); + }, + }); + + this.addCommand({ + id: "fuzzy-note-add-iw-queue", + name: "Add note to queue through a fuzzy finder", + callback: () => new FuzzyNoteAdder(this).open(), + hotkeys: [], + }); + + this.addCommand({ + id: "block-add-iw-queue", + name: "Add block to queue.", + checkCallback: (checking: boolean) => { + if (checking) { + return this.files.getActiveNoteFile() != null; + } + new ReviewBlockModal(this).open(); + }, + hotkeys: [], + }); + + this.addCommand({ + id: "add-links-within-note", + name: "Add links within note to queue.", + checkCallback: (checking: boolean) => { + if (checking) { + return this.files.getActiveNoteFile() != null; + } + + let file = this.files.getActiveNoteFile(); + if (file) { + let links = this.links.getLinksIn(file); + if (links && links.length) + new BulkAdderModal(this, this.queue.queuePath, links).open(); + else { + LogTo.Console("No links in the current file.", true); + } + } else { + LogTo.Console("Failed to get the active note.", true); + } + }, + hotkeys: [], + }); + + // + // Queue Loading + + this.addCommand({ + id: "load-iw-queue", + name: "Load a queue.", + callback: () => { + new QueueLoadModal(this).open(); + }, + hotkeys: [], + }); + } + + createStatusBar() { + this.statusBar = new StatusBar(this.addStatusBarItem(), this); + this.statusBar.initStatusBar(); + } + + subscribeToEvents() { + this.app.workspace.onLayoutReady(() => { + this.addSearchButton(); + }); + + this.registerEvent( + this.app.workspace.on("file-menu", (menu, file, source: string) => { + if (file === null) { + return; + } + + if (file instanceof TFile && file.extension === "md") { + menu.addItem((item) => { + item + .setTitle(`Add File to IW Queue`) + .setIcon("sheets-in-box") + .onClick((evt) => { + new ReviewFileModal(this, file.path).open(); + }); + }); + } else if (file instanceof TFolder) { + menu.addItem((item) => { + item + .setTitle(`Add Folder to IW Queue`) + .setIcon("sheets-in-box") + .onClick((evt) => { + let files = this.app.vault + .getMarkdownFiles() + .filter((f) => this.files.isDescendantOf(f, file)) + .map((f) => f.path); + + if (files) { + new BulkAdderModal(this, this.queue.queuePath, files).open(); + } else LogTo.Console("Folder contains no files!", true); + }); + }); + } + }) + ); + } + + async removeSearchButton() { + let searchView = await this.getSearchLeafView(); + let btn = (searchView)?.addToQueueButton; + if (btn) { + btn.buttonEl?.remove(); + btn = null; + } + } + + async onunload() { + LogTo.Console("Disabled and unloaded."); + await this.removeSearchButton(); + } +} diff --git a/src/markdown.ts b/src/markdown.ts index 30da99c..5fe3155 100644 --- a/src/markdown.ts +++ b/src/markdown.ts @@ -1,201 +1,203 @@ -import { DateUtils } from "./helpers/date-utils" -import { LinkEx } from "./helpers/link-utils" -import { PriorityUtils } from "./helpers/priority-utils" -import { Scheduler, SimpleScheduler, AFactorScheduler } from "./scheduler" -import IW from "./main" -import { GrayMatterFile } from 'gray-matter' - +import { DateUtils } from "./helpers/date-utils"; +import { LinkEx } from "./helpers/link-utils"; +import { PriorityUtils } from "./helpers/priority-utils"; +import { Scheduler, SimpleScheduler, AFactorScheduler } from "./scheduler"; +import IW from "./main"; +import { GrayMatterFile } from "gray-matter"; export class MarkdownTable { - - plugin: IW - scheduler: Scheduler - private header = -`| Link | Priority | Notes | Interval | Next Rep | -|------|----------|-------|---------|----------|` - rows: MarkdownTableRow[] = []; - - // TODO: just pass the gray matter object, replace text with contents. - constructor(plugin: IW, frontMatter?: GrayMatterFile, text?: string) { - this.plugin = plugin; - this.scheduler = this.createScheduler(frontMatter); - if (text) { - text = text.trim(); - let split = text.split("\n"); - let idx = this.findYamlEnd(split); - if (idx !== -1) - // line after yaml + header - this.rows = this.parseRows(split.slice(idx + 1 + 2)); - } - } - - hasRowWithLink(link: string) { - link = LinkEx.removeBrackets(link); - return (this.rows.some(r => r.link === link)); - } - - schedule(rep: MarkdownTableRow) { - this.scheduler.schedule(this, rep); - } - - findYamlEnd(split: string[]) { - let ct = 0; - let idx = split.findIndex((value) => { - if (value === "---") { - if (ct === 1) { - return true; - } - ct += 1; - return false; - }}); - - return idx; - } - - private createScheduler(frontMatter: GrayMatterFile): Scheduler { - let scheduler: Scheduler - - // Default - if (this.plugin.settings.defaultQueueType === "afactor") { - scheduler = new AFactorScheduler(); - } - else if (this.plugin.settings.defaultQueueType === "simple"){ - scheduler = new SimpleScheduler(); - } - - // Specified in YAML - if (frontMatter) { - let schedulerName = frontMatter.data["scheduler"]; - if (schedulerName && schedulerName === "simple"){ - scheduler = new SimpleScheduler(); - } - else if (schedulerName && schedulerName === "afactor") { - let afactor = Number(frontMatter.data["afactor"]); - let interval = Number(frontMatter.data["interval"]); - scheduler = new AFactorScheduler(afactor, interval); - } - } - return scheduler; - } - - parseRows(arr: string[]): MarkdownTableRow[] { - return arr.map(v => this.parseRow(v)) - } - - parseRow(text: string): MarkdownTableRow { - let arr = text.substr(1, text.length - 1).split("|").map(r => r.trim()) - return new MarkdownTableRow(arr[0], Number(arr[1]), arr[2], Number(arr[3]), new Date(arr[4])); - } - - hasReps() { - return this.rows.length > 0; - } - - currentRep() { - this.sortReps(); - return this.rows[0] - } - - nextRep() { - this.sortReps(); - return this.rows[1]; - } - - removeCurrentRep() { - this.sortReps(); - let removed; - if (this.rows.length === 1) { - removed = this.rows.pop(); - } - else if (this.rows.length > 1) { - removed = this.rows[0]; - this.rows = this.rows.slice(1); + plugin: IW; + scheduler: Scheduler; + private header = `| Link | Priority | Notes | Interval | Next Rep | +|------|----------|-------|---------|----------|`; + rows: MarkdownTableRow[] = []; + + // TODO: just pass the gray matter object, replace text with contents. + constructor(plugin: IW, frontMatter?: GrayMatterFile, text?: string) { + this.plugin = plugin; + this.scheduler = this.createScheduler(frontMatter); + if (text) { + text = text.trim(); + let split = text.split("\n"); + let idx = this.findYamlEnd(split); + if (idx !== -1) + // line after yaml + header + this.rows = this.parseRows(split.slice(idx + 1 + 2)); + } + } + + hasRowWithLink(link: string) { + link = LinkEx.removeBrackets(link); + return this.rows.some((r) => r.link === link); + } + + schedule(rep: MarkdownTableRow) { + this.scheduler.schedule(this, rep); + } + + findYamlEnd(split: string[]) { + let ct = 0; + let idx = split.findIndex((value) => { + if (value === "---") { + if (ct === 1) { + return true; } - return removed; - } - - sortReps() { - if (this.scheduler instanceof SimpleScheduler) { - this.sortByPriority(); - } - else if (this.scheduler instanceof AFactorScheduler) { - this.sortByPriority(); - this.sortByDue(); - } - } - - getReps() { - return this.rows; - } - - private sortByDue() { - this.rows.sort((a, b) => { - if (a.isDue() && !b.isDue()) - return -1; - if (a.isDue() && b.isDue()) - return 0; - if (!a.isDue() && b.isDue()) - return 1; - }); - } - - private sortByPriority() { - this.rows.sort((a, b) => { - let fst = +(a.priority); - let snd = +(b.priority); - if (fst > snd) - return 1; - else if (fst == snd) - return 0; - else if (fst < snd) - return -1; - }); - } - - addRow(row: MarkdownTableRow) { - this.rows.push(row); - } - - sort(compareFn: (a: MarkdownTableRow, b: MarkdownTableRow) => number){ - if (this.rows) - this.rows = this.rows.sort(compareFn); - } - - toString() { - let table = this.scheduler.toString() + "\n"; - table += this.header; - if (this.rows) { - table += "\n" + this.rows.join("\n"); - } - return table.trim(); - } + ct += 1; + return false; + } + }); + + return idx; + } + + private createScheduler(frontMatter: GrayMatterFile): Scheduler { + let scheduler: Scheduler; + + // Default + if (this.plugin.settings.defaultQueueType === "afactor") { + scheduler = new AFactorScheduler(); + } else if (this.plugin.settings.defaultQueueType === "simple") { + scheduler = new SimpleScheduler(); + } + + // Specified in YAML + if (frontMatter) { + let schedulerName = frontMatter.data["scheduler"]; + if (schedulerName && schedulerName === "simple") { + scheduler = new SimpleScheduler(); + } else if (schedulerName && schedulerName === "afactor") { + let afactor = Number(frontMatter.data["afactor"]); + let interval = Number(frontMatter.data["interval"]); + scheduler = new AFactorScheduler(afactor, interval); + } + } + return scheduler; + } + + parseRows(arr: string[]): MarkdownTableRow[] { + return arr.map((v) => this.parseRow(v)); + } + + parseRow(text: string): MarkdownTableRow { + let arr = text + .substr(1, text.length - 1) + .split("|") + .map((r) => r.trim()); + return new MarkdownTableRow( + arr[0], + Number(arr[1]), + arr[2], + Number(arr[3]), + new Date(arr[4]) + ); + } + + hasReps() { + return this.rows.length > 0; + } + + currentRep() { + this.sortReps(); + return this.rows[0]; + } + + nextRep() { + this.sortReps(); + return this.rows[1]; + } + + removeCurrentRep() { + this.sortReps(); + let removed; + if (this.rows.length === 1) { + removed = this.rows.pop(); + } else if (this.rows.length > 1) { + removed = this.rows[0]; + this.rows = this.rows.slice(1); + } + return removed; + } + + sortReps() { + if (this.scheduler instanceof SimpleScheduler) { + this.sortByPriority(); + } else if (this.scheduler instanceof AFactorScheduler) { + this.sortByPriority(); + this.sortByDue(); + } + } + + getReps() { + return this.rows; + } + + private sortByDue() { + this.rows.sort((a, b) => { + if (a.isDue() && !b.isDue()) return -1; + if (a.isDue() && b.isDue()) return 0; + if (!a.isDue() && b.isDue()) return 1; + }); + } + + private sortByPriority() { + this.rows.sort((a, b) => { + let fst = +a.priority; + let snd = +b.priority; + if (fst > snd) return 1; + else if (fst == snd) return 0; + else if (fst < snd) return -1; + }); + } + + addRow(row: MarkdownTableRow) { + this.rows.push(row); + } + + sort(compareFn: (a: MarkdownTableRow, b: MarkdownTableRow) => number) { + if (this.rows) this.rows = this.rows.sort(compareFn); + } + + toString() { + let table = this.scheduler.toString() + "\n"; + table += this.header; + if (this.rows) { + table += "\n" + this.rows.join("\n"); + } + return table.trim(); + } } export class MarkdownTableRow { - - link: string - priority: number - notes: string - interval: number - nextRepDate: Date - - constructor(link: string, priority: number, notes: string, interval: number = 1, nextRepDate: Date = new Date("1970-01-01")){ - this.link = LinkEx.removeBrackets(link); - this.priority = PriorityUtils.isValid(priority) ? priority : 30; - this.notes = notes.replace(/(\r\n|\n|\r|\|)/gm, ""); - this.interval = interval > 0 ? interval : 1; - this.nextRepDate = DateUtils.isValid(nextRepDate) ? nextRepDate : new Date("1970-01-01"); - } - - isDue(): boolean { - if (new Date(Date.now()) >= this.nextRepDate) - return true; - return false; - } - - toString() { - let date = DateUtils.formatDate(this.nextRepDate); - let link = LinkEx.addBrackets(this.link); - return `| ${link} | ${this.priority} | ${this.notes} | ${this.interval} | ${date} |`; - } + link: string; + priority: number; + notes: string; + interval: number; + nextRepDate: Date; + + constructor( + link: string, + priority: number, + notes: string, + interval: number = 1, + nextRepDate: Date = new Date("1970-01-01") + ) { + this.link = LinkEx.removeBrackets(link); + this.priority = PriorityUtils.isValid(priority) ? priority : 30; + this.notes = notes.replace(/(\r\n|\n|\r|\|)/gm, ""); + this.interval = interval > 0 ? interval : 1; + this.nextRepDate = DateUtils.isValid(nextRepDate) + ? nextRepDate + : new Date("1970-01-01"); + } + + isDue(): boolean { + if (new Date(Date.now()) >= this.nextRepDate) return true; + return false; + } + + toString() { + let date = DateUtils.formatDate(this.nextRepDate); + let link = LinkEx.addBrackets(this.link); + return `| ${link} | ${this.priority} | ${this.notes} | ${this.interval} | ${date} |`; + } } diff --git a/src/queue.ts b/src/queue.ts index d61ccca..01c4767 100644 --- a/src/queue.ts +++ b/src/queue.ts @@ -1,200 +1,217 @@ -import { MarkdownTable, MarkdownTableRow } from "./markdown" -import { TFile } from "obsidian" -import { LogTo } from "./logger" -import IW from "./main" -import matter from 'gray-matter'; -import { GrayMatterFile } from 'gray-matter' +import { MarkdownTable, MarkdownTableRow } from "./markdown"; +import { TFile } from "obsidian"; +import { LogTo } from "./logger"; +import IW from "./main"; +import matter from "gray-matter"; +import { GrayMatterFile } from "gray-matter"; export class Queue { + queuePath: string; + plugin: IW; - queuePath: string - plugin: IW - - constructor(plugin: IW, filePath: string) { - this.plugin = plugin - this.queuePath = filePath; + constructor(plugin: IW, filePath: string) { + this.plugin = plugin; + this.queuePath = filePath; + } + + async createTableIfNotExists() { + let data = new MarkdownTable(this.plugin).toString(); + await this.plugin.files.createIfNotExists(this.queuePath, data); + } + + async goToQueue(newLeaf: boolean) { + await this.createTableIfNotExists(); + await this.plugin.files.goTo(this.queuePath, newLeaf); + } + + async dismissCurrent() { + let table = await this.loadTable(); + if (!table || !table.hasReps()) { + LogTo.Debug("No repetitions!", true); + return; } - async createTableIfNotExists() { - let data = new MarkdownTable(this.plugin).toString(); - await this.plugin.files.createIfNotExists(this.queuePath, data); + let curRep = table.currentRep(); + if (!curRep.isDue()) { + LogTo.Debug("No due repetition to dismiss.", true); + return; } - async goToQueue(newLeaf: boolean) { - await this.createTableIfNotExists(); - await this.plugin.files.goTo(this.queuePath, newLeaf); + table.removeCurrentRep(); + LogTo.Console("Dismissed repetition: " + curRep.link, true); + await this.writeQueueTable(table); + } + + async loadTable(): Promise { + let text: string = await this.readQueue(); + if (!text) { + LogTo.Debug("Failed to load queue table.", true); + return; } - async dismissCurrent() { - let table = await this.loadTable(); - if (!table || !table.hasReps()){ - LogTo.Debug("No repetitions!", true); - return; - } - - let curRep = table.currentRep(); - if (!curRep.isDue()) { - LogTo.Debug("No due repetition to dismiss.", true); - return - } - - table.removeCurrentRep(); - LogTo.Console("Dismissed repetition: " + curRep.link, true); - await this.writeQueueTable(table); + let fm = this.getFrontmatterString(text); + let table = new MarkdownTable(this.plugin, fm, text); + table.sortReps(); + return table; + } + + getFrontmatterString(text: string): GrayMatterFile { + return matter(text); + } + + async goToCurrentRep() { + let table = await this.loadTable(); + if (!table || !table.hasReps()) { + LogTo.Console("No more repetitions!", true); + return; } - async loadTable(): Promise { - let text: string = await this.readQueue(); - if (!text) { - LogTo.Debug("Failed to load queue table.", true); - return; - } - - let fm = this.getFrontmatterString(text); - let table = new MarkdownTable(this.plugin, fm, text); - table.sortReps(); - return table; + let currentRep = table.currentRep(); + if (currentRep.isDue()) { + await this.loadRep(currentRep); + } else { + LogTo.Console("No more repetitions!", true); } + } - getFrontmatterString(text: string): GrayMatterFile { - return matter(text); + async nextRepetition() { + let table = await this.loadTable(); + if (!table || !table.hasReps()) { + LogTo.Console("No more repetitions!", true); + return; } - async goToCurrentRep() { - let table = await this.loadTable(); - if (!table || !table.hasReps()) { - LogTo.Console("No more repetitions!", true); - return; - } - - let currentRep = table.currentRep() - if (currentRep.isDue()) { - await this.loadRep(currentRep); - } - else { - LogTo.Console("No more repetitions!", true); - } + let currentRep = table.currentRep(); + let nextRep = table.nextRep(); + + let repToLoad; + + if (currentRep && nextRep) { + table.removeCurrentRep(); + repToLoad = nextRep; + } else { + table.removeCurrentRep(); + repToLoad = currentRep; } - async nextRepetition() { - let table = await this.loadTable(); - if (!table || !table.hasReps()) { - LogTo.Console("No more repetitions!", true); - return; - } - - let currentRep = table.currentRep(); - let nextRep = table.nextRep(); - - let repToLoad; - - if (currentRep && nextRep) { - table.removeCurrentRep(); - repToLoad = nextRep - } - else { - table.removeCurrentRep(); - repToLoad = currentRep; - } - - table.schedule(currentRep); - - if (repToLoad.isDue()){ - await this.loadRep(repToLoad); - } - else{ - LogTo.Debug("No more repetitions!", true); - } - - await this.writeQueueTable(table); + table.schedule(currentRep); + + if (repToLoad.isDue()) { + await this.loadRep(repToLoad); + } else { + LogTo.Debug("No more repetitions!", true); } - private async loadRep(repToLoad: MarkdownTableRow){ - if (!repToLoad){ - LogTo.Console("Failed to load repetition.", true); - return; - } + await this.writeQueueTable(table); + } - this.plugin.statusBar.updateCurrentRep(repToLoad); - LogTo.Console("Loading repetition: " + repToLoad.link, true); - await this.plugin.app.workspace.openLinkText(repToLoad.link, '', false, { active: true }); + private async loadRep(repToLoad: MarkdownTableRow) { + if (!repToLoad) { + LogTo.Console("Failed to load repetition.", true); + return; } - async addNotesToQueue(...rows: MarkdownTableRow[]) { + this.plugin.statusBar.updateCurrentRep(repToLoad); + LogTo.Console("Loading repetition: " + repToLoad.link, true); + await this.plugin.app.workspace.openLinkText(repToLoad.link, "", false, { + active: true, + }); + } - await this.createTableIfNotExists(); - let table = await this.loadTable(); + async addNotesToQueue(...rows: MarkdownTableRow[]) { + await this.createTableIfNotExists(); + let table = await this.loadTable(); - for (let row of rows) { - if (table.hasRowWithLink(row.link)){ - LogTo.Console(`Skipping ${row.link} because it is already in your queue!`); - continue; - } + for (let row of rows) { + if (table.hasRowWithLink(row.link)) { + LogTo.Console( + `Skipping ${row.link} because it is already in your queue!` + ); + continue; + } - if (row.link.contains("|")) { - LogTo.Console(`Skipping ${row.link} because it contains a pipe character.`) - continue; - } + if (row.link.contains("|")) { + LogTo.Console( + `Skipping ${row.link} because it contains a pipe character.` + ); + continue; + } - table.addRow(row); - LogTo.Console("Added note to queue: " + row.link, true); - } + table.addRow(row); + LogTo.Console("Added note to queue: " + row.link, true); + } - await this.writeQueueTable(table); + await this.writeQueueTable(table); + } + + async addBlockToQueue( + priority: number, + notes: string, + date: Date, + block: string, + activeNoteFile: TFile + ) { + await this.createTableIfNotExists(); + let table = await this.loadTable(); + LogTo.Debug("Add block to queue"); + let link = this.plugin.app.metadataCache.fileToLinktext( + activeNoteFile, + "", + true + ); + let lineBlockId = this.plugin.blocks.getBlock(block, activeNoteFile); + + if (lineBlockId === "") { + // The line is not already a block + console.debug("This line is not currently a block. Adding a block ID."); + lineBlockId = this.plugin.blocks.createBlockHash(); + let lineWithBlock = block + " ^" + lineBlockId; + let oldText = await this.plugin.app.vault.read(activeNoteFile); + let newNoteText = oldText.replace(block, lineWithBlock); + await this.plugin.app.vault.modify(activeNoteFile, newNoteText); } - async addBlockToQueue(priority: number, notes: string, date: Date, block: string, activeNoteFile: TFile) { - await this.createTableIfNotExists(); - let table = await this.loadTable(); - LogTo.Debug("Add block to queue") - let link = this.plugin.app.metadataCache.fileToLinktext(activeNoteFile, activeNoteFile.path, true); - let lineBlockId = this.plugin.blocks.getBlock(block, activeNoteFile); - - if (lineBlockId === "") { // The line is not already a block - console.debug("This line is not currently a block. Adding a block ID."); - lineBlockId = this.plugin.blocks.createBlockHash(); - let lineWithBlock = block + " ^" + lineBlockId; - let oldText = await this.plugin.app.vault.read(activeNoteFile) - let newNoteText = oldText.replace(block, lineWithBlock); - await this.plugin.app.vault.modify(activeNoteFile, newNoteText); - } - - link = link + "#^" + lineBlockId; - - if (table.hasRowWithLink(link)){ - LogTo.Console("Already in your queue!", true); - return; - } - - - if (link.contains("|")) { - LogTo.Console(`Failed to add ${link} because it contains a pipe character.`, true) - return; - } - - table.addRow(new MarkdownTableRow(link, priority, notes, 1, date)); - LogTo.Console("Added block to queue: " + link, true); - await this.writeQueueTable(table); + link = link + "#^" + lineBlockId; + + if (table.hasRowWithLink(link)) { + LogTo.Console("Already in your queue!", true); + return; } - getQueueAsTFile() { - return this.plugin.app.vault.getAbstractFileByPath(this.queuePath) as TFile; + if (link.contains("|")) { + LogTo.Console( + `Failed to add ${link} because it contains a pipe character.`, + true + ); + return; } + table.addRow(new MarkdownTableRow(link, priority, notes, 1, date)); + LogTo.Console("Added block to queue: " + link, true); + await this.writeQueueTable(table); + } + + getQueueAsTFile() { + return this.plugin.files.getTFile(this.queuePath); + } + async writeQueueTable(table: MarkdownTable): Promise { - let queue = this.getQueueAsTFile() - let data = table.toString(); - table.sortReps(); - await this.plugin.app.vault.modify(queue, data); + let queue = this.getQueueAsTFile(); + if (queue) { + let data = table.toString(); + table.sortReps(); + await this.plugin.app.vault.modify(queue, data); + } else { + LogTo.Console("Failed to write queue because queue file was null.", true); + } } async readQueue(): Promise { - let queue = this.getQueueAsTFile(); - try { - return await this.plugin.app.vault.read(queue); - } - catch (Exception) { - return; - } + let queue = this.getQueueAsTFile(); + try { + return await this.plugin.app.vault.read(queue); + } catch (Exception) { + return; + } } } diff --git a/src/scheduler.ts b/src/scheduler.ts index a824fbd..3659ed6 100644 --- a/src/scheduler.ts +++ b/src/scheduler.ts @@ -1,77 +1,75 @@ -import { MarkdownTable, MarkdownTableRow } from "./markdown" -import { DateUtils } from "./helpers/date-utils" +import { MarkdownTable, MarkdownTableRow } from "./markdown"; +import { DateUtils } from "./helpers/date-utils"; export abstract class Scheduler { - // defaultPriorityMin: number - // defaultPriorityMax: number - name: string - constructor(name: string){ - this.name = name; - } + // defaultPriorityMin: number + // defaultPriorityMax: number + name: string; + constructor(name: string) { + this.name = name; + } - abstract schedule(table: MarkdownTable, row: MarkdownTableRow): void + abstract schedule(table: MarkdownTable, row: MarkdownTableRow): void; } export class SimpleScheduler extends Scheduler { + constructor() { + super("simple"); + } - constructor() { - super("simple"); - } - - roundOff(num: number, places: number) { - const x = Math.pow(10,places); - return Math.round(num * x) / x; - } + roundOff(num: number, places: number) { + const x = Math.pow(10, places); + return Math.round(num * x) / x; + } - schedule(table: MarkdownTable, row: MarkdownTableRow) { - table.addRow(row); - // spread rows between 0 and 100 priority - let step = 99.9 / table.rows.length; - let curPri = step; - for (let row of table.rows) { - row.priority = this.roundOff(curPri, 2); - curPri += step; - } + schedule(table: MarkdownTable, row: MarkdownTableRow) { + table.addRow(row); + // spread rows between 0 and 100 priority + let step = 99.9 / table.rows.length; + let curPri = step; + for (let row of table.rows) { + row.priority = this.roundOff(curPri, 2); + curPri += step; } + } - toString() { - return `--- + toString() { + return `--- scheduler: "${this.name}" ---`; - } + } } export class AFactorScheduler extends Scheduler { + afactor: number; + interval: number; - afactor: number - interval: number + // TODO: + constructor(afactor: number = 2, interval: number = 1) { + super("afactor"); + this.afactor = this.isValidAFactor(afactor) ? afactor : 2; + this.interval = this.isValidInterval(interval) ? interval : 1; + } - // TODO: - constructor(afactor: number = 2, interval: number = 1) { - super("afactor"); - this.afactor = this.isValidAFactor(afactor) ? afactor : 2; - this.interval = this.isValidInterval(interval) ? interval : 1; - } + schedule(table: MarkdownTable, row: MarkdownTableRow) { + row.nextRepDate = DateUtils.addDays(new Date(Date.now()), row.interval); + row.interval = this.afactor * row.interval; + table.addRow(row); + } - schedule(table: MarkdownTable, row: MarkdownTableRow) { - row.nextRepDate = DateUtils.addDays(new Date(Date.now()), row.interval); - row.interval = this.afactor * row.interval; - table.addRow(row); - } + isValidAFactor(afactor: number) { + return !isNaN(afactor) && afactor >= 0; + } - isValidAFactor(afactor: number) { - return (!isNaN(afactor) && afactor >= 0); - } + isValidInterval(interval: number) { + return !isNaN(interval) && interval >= 0; + } - isValidInterval(interval: number) { - return (!isNaN(interval) && interval >= 0); - } - - toString() { - return `--- + toString() { + return `--- scheduler: "${this.name}" afactor: ${this.afactor} interval: ${this.interval} ---`; - } + } } diff --git a/src/settings.ts b/src/settings.ts index f946e29..e84b122 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -1,17 +1,17 @@ export interface IWSettings { - defaultPriorityMin: number - defaultPriorityMax: number - queueFilePath: string - queueFolderPath: string - defaultQueueType: string - skipAddNoteWindow: boolean + defaultPriorityMin: number; + defaultPriorityMax: number; + queueFileName: string; + queueFolderPath: string; + defaultQueueType: string; + skipAddNoteWindow: boolean; } -export class DefaultSettings implements IWSettings { - defaultPriorityMin = 10; - defaultPriorityMax = 50; - queueFolderPath = "IW-Queues" - queueFilePath = "IW-Queue.md"; - defaultQueueType = "afactor"; - skipAddNoteWindow = false; -} +export const DefaultSettings: IWSettings = { + defaultPriorityMin: 10, + defaultPriorityMax: 50, + queueFolderPath: "IW-Queues", + queueFileName: "IW-Queue.md", + defaultQueueType: "afactor", + skipAddNoteWindow: false, +}; diff --git a/src/views/bulk-adding.ts b/src/views/bulk-adding.ts index 4e9eabb..cb0aaa1 100644 --- a/src/views/bulk-adding.ts +++ b/src/views/bulk-adding.ts @@ -1,218 +1,237 @@ -import { normalizePath, TFolder, TFile, SliderComponent, Notice, TextComponent, ButtonComponent } from "obsidian" -import { PriorityUtils } from "../helpers/priority-utils" -import { ModalBase } from "./modal-base" -import IW from "../main" -import { Queue } from "../queue" -import { HashSet } from "../hashset" -import { FileSuggest } from "./file-suggest" -import { DateUtils } from "../helpers/date-utils" -import { throttle } from "../helpers/functools" -import { MarkdownTableRow } from "../markdown" -import { LogTo } from "../logger" +import { + normalizePath, + TFolder, + TFile, + SliderComponent, + Notice, + TextComponent, + ButtonComponent, + debounce, +} from "obsidian"; +import { PriorityUtils } from "../helpers/priority-utils"; +import { ModalBase } from "./modal-base"; +import IW from "../main"; +import { Queue } from "../queue"; +import { FileSuggest } from "./file-suggest"; +import { DateUtils } from "../helpers/date-utils"; +import { throttle } from "../helpers/functools"; +import { MarkdownTableRow } from "../markdown"; +import { LogTo } from "../logger"; export class BulkAdderModal extends ModalBase { + queuePath: string; + + inputFolderField: TextComponent; + noteCountDiv: HTMLDivElement; + + // + // Queue + + inputQueueField: TextComponent; + + // + // Priorities + + inputPriorityMin: SliderComponent; + inputPriorityMax: SliderComponent; + + // + // First Rep + + inputFirstRepMin: TextComponent; + inputFirstRepMax: TextComponent; + + linkPaths: string[]; + outstanding: Set = new Set(); + toAdd: string[] = []; + + constructor(plugin: IW, queuePath: string, linkPaths: string[]) { + super(plugin); + this.linkPaths = linkPaths; + this.queuePath = queuePath; + } + + async updateOutstanding() { + let queuePath = normalizePath(this.getQueuePath()); + let outstanding = new Set(); + if (await this.plugin.app.vault.adapter.exists(queuePath)) { + let queue = new Queue(this.plugin, queuePath); + let table = await queue.loadTable(); + let alreadyAdded = table + .getReps() + .map((r) => normalizePath(r.link + ".md")); + for (let added of alreadyAdded) { + outstanding.add(added); + } + } + this.outstanding = outstanding; + } - queuePath: string + async updateToAdd() { + await this.updateOutstanding(); + this.toAdd = this.linkPaths + .filter((link) => !this.outstanding.has(link)) + .map((link) => normalizePath(link)); + this.noteCountDiv.innerText = + "Notes (excluding duplicates): " + this.toAdd.length; + } - inputFolderField: TextComponent - noteCountDiv: HTMLDivElement + getQueuePath() { + let queue = this.inputQueueField.getValue(); + if (!queue.endsWith(".md")) queue += ".md"; - // - // Queue + return normalizePath( + [this.plugin.settings.queueFolderPath, queue].join("/") + ); + } - inputQueueField: TextComponent + async onOpen() { + let { contentEl } = this; - // - // Priorities + contentEl.createEl("h3", { text: "Bulk Add Notes to Queue" }); - inputPriorityMin: SliderComponent - inputPriorityMax: SliderComponent + // + // Queue - // - // First Rep + contentEl.appendText("Queue: "); + this.inputQueueField = new TextComponent(contentEl) + .setPlaceholder("Example: queue.md") + .setValue(this.plugin.settings.queueFileName) + .onChange( + debounce( + (value: string) => { + this.updateToAdd(); + }, + 500, + true + ) + ); + let folderFunc = () => + this.plugin.app.vault.getAbstractFileByPath( + this.plugin.settings.queueFolderPath + ) as TFolder; + new FileSuggest(this.plugin, this.inputQueueField.inputEl, folderFunc); + contentEl.createEl("br"); - inputFirstRepMin: TextComponent - inputFirstRepMax: TextComponent + // + // Note Count - linkPaths: string[] - outstanding: HashSet = new HashSet() - toAdd: string[] = [] + this.noteCountDiv = contentEl.createDiv(); + await this.updateToAdd(); - constructor(plugin: IW, queuePath: string, linkPaths: string[]){ - super(plugin); - this.linkPaths = linkPaths; - this.queuePath = queuePath; - } + // + // Priorities - async updateOutstanding() { - let queuePath = normalizePath(this.getQueuePath()); - let outstanding = new HashSet(); - if (await this.plugin.app.vault.adapter.exists(queuePath)) { - let queue = new Queue(this.plugin, queuePath); - let table = await queue.loadTable(); - let alreadyAdded = table.getReps().map(r => normalizePath(r.link + ".md")); - for (let added of alreadyAdded) { - outstanding.add(added); - } + // Min + + this.contentEl.appendText("Min Priority: "); + this.inputPriorityMin = new SliderComponent(contentEl) + .setLimits(0, 100, 1) + .setDynamicTooltip() + .onChange((value) => { + if (this.inputPriorityMax) { + let max = this.inputPriorityMax.getValue(); + if (value > max) this.inputPriorityMax.setValue(value); } - this.outstanding = outstanding; - } + }) + .setValue(0); + this.contentEl.createEl("br"); + + // Max + + this.contentEl.appendText("Max Priority: "); + this.inputPriorityMax = new SliderComponent(contentEl) + .setLimits(0, 100, 1) + .setDynamicTooltip() + .onChange((value) => { + if (this.inputPriorityMin) { + let min = this.inputPriorityMin.getValue(); + if (value < min) this.inputPriorityMin.setValue(value); + } + }) + .setValue(100); + this.contentEl.createEl("br"); - async updateToAdd() { - await this.updateOutstanding(); - this.toAdd = this.linkPaths - .filter(link => !this.outstanding.has(link)) - .map(link => normalizePath(link)) - this.noteCountDiv.innerText = "Notes (excluding duplicates): " + this.toAdd.length; - } + // + // First Reps - getQueuePath() { - let queue = this.inputQueueField.getValue(); - if (!queue.endsWith(".md")) - queue += ".md" + this.contentEl.appendText("Earliest Rep Date: "); + this.inputFirstRepMin = new TextComponent(contentEl).setValue("1970-01-01"); + this.contentEl.createEl("br"); - return normalizePath([this.plugin.settings.queueFolderPath, queue].join('/')); - } + this.contentEl.appendText("Latest Rep Date: "); + this.inputFirstRepMax = new TextComponent(contentEl).setValue("1970-01-01"); + this.contentEl.createEl("br"); - async onOpen(){ - let { contentEl } = this; - - contentEl.createEl("h3", {"text": "Bulk Add Notes to Queue"}); - - // - // Queue - - contentEl.appendText("Queue: "); - this.inputQueueField = new TextComponent(contentEl) - .setPlaceholder("Example: queue.md") - .setValue(this.plugin.settings.queueFilePath) - .onChange(throttle((value: string) => { - this.updateToAdd(); - }, 500)) - let folderFunc = () => this.plugin.app.vault.getAbstractFileByPath(this.plugin.settings.queueFolderPath) as TFolder; - new FileSuggest(this.plugin, this.inputQueueField.inputEl, folderFunc) - contentEl.createEl("br"); - - // - // Note Count - - this.noteCountDiv = contentEl.createDiv(); - await this.updateToAdd(); - - // - // Priorities - - // Min - - this.contentEl.appendText("Min Priority: "); - this.inputPriorityMin = new SliderComponent(contentEl) - .setLimits(0, 100, 1) - .setDynamicTooltip() - .onChange((value) => { - if (this.inputPriorityMax) { - let max = this.inputPriorityMax.getValue(); - if (value > max) - this.inputPriorityMax.setValue(value); - } - }) - .setValue(0); - this.contentEl.createEl("br"); - - // Max - - this.contentEl.appendText("Max Priority: "); - this.inputPriorityMax = new SliderComponent(contentEl) - .setLimits(0, 100, 1) - .setDynamicTooltip() - .onChange((value) => { - if (this.inputPriorityMin) { - let min = this.inputPriorityMin.getValue(); - if (value < min) - this.inputPriorityMin.setValue(value); - } - }) - .setValue(100); - this.contentEl.createEl("br"); - - // - // First Reps - - this.contentEl.appendText("Earliest Rep Date: "); - this.inputFirstRepMin = new TextComponent(contentEl) - .setValue("1970-01-01"); - this.contentEl.createEl("br"); - - this.contentEl.appendText("Latest Rep Date: "); - this.inputFirstRepMax = new TextComponent(contentEl) - .setValue("1970-01-01"); - this.contentEl.createEl("br"); - - // - // Events - - contentEl.addEventListener("keydown", (ev) => { - if (ev.key === "Enter") { - this.addNotes(); - } - }) - - // - // Button - - let inputButton = new ButtonComponent(contentEl) - .setButtonText("Add to IW Queue") - .onClick(async () => { - await this.addNotes(); - this.close(); - return; - }); - } + // + // Events - datesAreValid(d1: Date, d2: Date){ - return (DateUtils.isValid(d1) && DateUtils.isValid(d2) && (d1 <= d2)) - } + contentEl.addEventListener("keydown", (ev) => { + if (ev.key === "Enter") { + this.addNotes(); + } + }); - prioritiesAreValid(p1: number, p2: number) { - return PriorityUtils.isValid(p1) && PriorityUtils.isValid(p2) && (p1 < p2) + // + // Button + + let inputButton = new ButtonComponent(contentEl) + .setButtonText("Add to IW Queue") + .onClick(async () => { + await this.addNotes(); + this.close(); + return; + }); + } + + datesAreValid(d1: Date, d2: Date) { + return DateUtils.isValid(d1) && DateUtils.isValid(d2) && d1 <= d2; + } + + prioritiesAreValid(p1: number, p2: number) { + return PriorityUtils.isValid(p1) && PriorityUtils.isValid(p2) && p1 < p2; + } + + roundOff(num: number, places: number) { + const x = Math.pow(10, places); + return Math.round(num * x) / x; + } + + async addNotes() { + let priMin = Number(this.inputPriorityMin.getValue()); + let priMax = Number(this.inputPriorityMax.getValue()); + let dateMin = this.parseDate(this.inputFirstRepMin.getValue()); + let dateMax = this.parseDate(this.inputFirstRepMax.getValue()); + + if ( + !this.prioritiesAreValid(priMin, priMax) || + !this.datesAreValid(dateMin, dateMax) + ) { + new Notice("Failed: invalid data!"); + this.close(); + return; } - - roundOff(num: number, places: number) { - const x = Math.pow(10,places); - return Math.round(num * x) / x; + let priStep = (priMax - priMin) / this.toAdd.length; + let curPriority = priMin; + let curDate = dateMin; + let dateDiff = DateUtils.dateDifference(dateMin, dateMax); + let numToAdd = this.toAdd.length > 0 ? this.toAdd.length : 1; + let dateStep = dateDiff / numToAdd; + let curStep = dateStep; + + let queue = new Queue(this.plugin, this.getQueuePath()); + let rows: MarkdownTableRow[] = []; + LogTo.Console("To add: " + this.toAdd); + for (let note of this.toAdd) { + let file = this.plugin.app.vault.getAbstractFileByPath(note) as TFile; + let link = this.plugin.files.toLinkText(file); + rows.push(new MarkdownTableRow(link, curPriority, "", 1, curDate)); + + curPriority = this.roundOff(curPriority + priStep, 2); + curDate = DateUtils.addDays(new Date(dateMin), curStep); + curStep += dateStep; } - async addNotes() { - let priMin = Number(this.inputPriorityMin.getValue()); - let priMax = Number(this.inputPriorityMax.getValue()); - let dateMin = this.parseDate(this.inputFirstRepMin.getValue()); - let dateMax = this.parseDate(this.inputFirstRepMax.getValue()); - - if (!this.prioritiesAreValid(priMin, priMax) || !this.datesAreValid(dateMin, dateMax)) { - new Notice("Failed: invalid data!"); - this.close(); - return; - } - let priStep = (priMax - priMin) / this.toAdd.length; - let curPriority = priMin; - let curDate = dateMin; - let dateDiff = DateUtils.dateDifference(dateMin, dateMax); - let numToAdd = this.toAdd.length > 0 ? this.toAdd.length : 1; - let dateStep = dateDiff / numToAdd; - let curStep = dateStep; - - let queue = new Queue(this.plugin, this.getQueuePath()); - let rows: MarkdownTableRow[] = []; - LogTo.Console("To add: " + this.toAdd); - for (let note of this.toAdd) { - let file = this.plugin.app.vault.getAbstractFileByPath(note) as TFile; - let link = this.plugin.files.toLinkText(file); - rows.push(new MarkdownTableRow(link, curPriority, "", 1, curDate)); - - curPriority = this.roundOff(curPriority + priStep, 2); - curDate = DateUtils.addDays(new Date(dateMin), curStep); - curStep += dateStep; - } - - await queue.addNotesToQueue(...rows); - } + await queue.addNotesToQueue(...rows); + } } diff --git a/src/views/file-suggest.ts b/src/views/file-suggest.ts index 501b9e6..15291cc 100644 --- a/src/views/file-suggest.ts +++ b/src/views/file-suggest.ts @@ -1,17 +1,20 @@ import { App, TAbstractFile, TFile, TFolder } from "obsidian"; import { TextInputSuggest } from "./suggest"; -import IW from "../main" +import IW from "../main"; export class FileSuggest extends TextInputSuggest { + folder: () => TFolder; + plugin: IW; - folder: () => TFolder - plugin: IW - - constructor(plugin: IW, inputEl: HTMLInputElement, folderFunc: () => TFolder){ - super(plugin.app, inputEl) - this.plugin = plugin; - this.folder = folderFunc; - } + constructor( + plugin: IW, + inputEl: HTMLInputElement, + folderFunc: () => TFolder + ) { + super(plugin.app, inputEl); + this.plugin = plugin; + this.folder = folderFunc; + } getSuggestions(inputStr: string): TFile[] { const abstractFiles = this.app.vault.getAllLoadedFiles(); diff --git a/src/views/fuzzy-note-adder.ts b/src/views/fuzzy-note-adder.ts index 191c7e9..f8d2f6d 100644 --- a/src/views/fuzzy-note-adder.ts +++ b/src/views/fuzzy-note-adder.ts @@ -1,25 +1,24 @@ -import { FuzzySuggestModal } from "obsidian" -import IW from "../main" -import { ReviewFileModal } from "./modals" +import { FuzzySuggestModal } from "obsidian"; +import IW from "../main"; +import { ReviewFileModal } from "./modals"; export class FuzzyNoteAdder extends FuzzySuggestModal { + plugin: IW; - plugin: IW; + constructor(plugin: IW) { + super(plugin.app); + this.plugin = plugin; + } - constructor(plugin: IW) { - super(plugin.app); - this.plugin = plugin; - } + onChooseItem(item: string, evt: MouseEvent | KeyboardEvent) { + new ReviewFileModal(this.plugin, item).open(); + } - onChooseItem(item: string, evt: MouseEvent | KeyboardEvent) { - new ReviewFileModal(this.plugin, item).open(); - } + getItems(): string[] { + return this.plugin.app.vault.getMarkdownFiles().map((file) => file.path); + } - getItems(): string[] { - return this.plugin.app.vault.getMarkdownFiles().map(file => file.path) - } - - getItemText(item: string) { - return item; - } + getItemText(item: string) { + return item; + } } diff --git a/src/views/modal-base.ts b/src/views/modal-base.ts index b41515a..1b8924e 100644 --- a/src/views/modal-base.ts +++ b/src/views/modal-base.ts @@ -1,47 +1,45 @@ -import { Modal } from "obsidian" -import { DateUtils } from "../helpers/date-utils" -import IW from "../main" +import { Modal } from "obsidian"; +import { DateUtils } from "../helpers/date-utils"; +import IW from "../main"; export abstract class ModalBase extends Modal { - - protected plugin: IW - - constructor(plugin: IW){ - super(plugin.app); - this.plugin = plugin; + protected plugin: IW; + + constructor(plugin: IW) { + super(plugin.app); + this.plugin = plugin; + } + + onClose() { + let { contentEl } = this; + contentEl.empty(); + } + + private parseDateAsDate(dateString: string): Date { + return new Date(dateString); + } + + private parseDateAsNatural(dateString: string): Date { + let naturalLanguageDates = (this.plugin.app).plugins.getPlugin( + "nldates-obsidian" + ); // Get the Natural Language Dates plugin. + if (!naturalLanguageDates) { + return; } - onClose() { - let { contentEl } = this; - contentEl.empty(); - } - - private parseDateAsDate(dateString: string): Date { - return new Date(dateString); - } + let nlDateResult = naturalLanguageDates.parseDate(dateString); + if (nlDateResult && nlDateResult.date) return nlDateResult.date; - private parseDateAsNatural(dateString: string): Date { - let naturalLanguageDates = (this.plugin.app).plugins.getPlugin('nldates-obsidian'); // Get the Natural Language Dates plugin. - if (!naturalLanguageDates) { - return; - } + return; + } - let nlDateResult = naturalLanguageDates.parseDate(dateString); - if (nlDateResult && nlDateResult.date) - return nlDateResult.date; + parseDate(dateString: string): Date { + let d1 = this.parseDateAsDate(dateString); + if (DateUtils.isValid(d1)) return d1; - return; - } + let d2 = this.parseDateAsNatural(dateString); + if (DateUtils.isValid(d2)) return d2; - parseDate(dateString: string): Date { - let d1 = this.parseDateAsDate(dateString); - if (DateUtils.isValid(d1)) - return d1; - - let d2 = this.parseDateAsNatural(dateString); - if (DateUtils.isValid(d2)) - return d2; - - return new Date("1970-01-01"); - } + return new Date("1970-01-01"); + } } diff --git a/src/views/modals.ts b/src/views/modals.ts index a593123..08a120a 100644 --- a/src/views/modals.ts +++ b/src/views/modals.ts @@ -1,214 +1,240 @@ -import { normalizePath, TFolder, MarkdownView, TFile, SliderComponent, TextComponent, ButtonComponent } from "obsidian" -import IW from "../main" -import { ModalBase } from "./modal-base" -import { LogTo } from "../logger" -import { FileSuggest } from "./file-suggest" -import { Queue } from "../queue" -import { PriorityUtils } from "../helpers/priority-utils" -import { MarkdownTableRow } from "../markdown" +import { + normalizePath, + TFolder, + MarkdownView, + TFile, + SliderComponent, + TextComponent, + ButtonComponent, +} from "obsidian"; +import IW from "../main"; +import { ModalBase } from "./modal-base"; +import { LogTo } from "../logger"; +import { FileSuggest } from "./file-suggest"; +import { Queue } from "../queue"; +import { PriorityUtils } from "../helpers/priority-utils"; +import { MarkdownTableRow } from "../markdown"; abstract class ReviewModal extends ModalBase { - - title: string - inputSlider: SliderComponent - inputNoteField: TextComponent - inputFirstRep: TextComponent - inputQueueField: TextComponent - - constructor(plugin: IW, title: string){ - super(plugin); - this.title = title; - } - - onOpen(){ - let { contentEl } = this; - - contentEl.createEl('h2', {text: this.title}); - - // - // Queue - - contentEl.appendText("Queue: "); - this.inputQueueField = new TextComponent(contentEl) - .setPlaceholder("Example: queue.md") - .setValue(this.plugin.settings.queueFilePath) - let folderFunc = () => this.plugin.app.vault.getAbstractFileByPath(this.plugin.settings.queueFolderPath) as TFolder; - new FileSuggest(this.plugin, this.inputQueueField.inputEl, folderFunc) - contentEl.createEl("br"); - - // - // First Rep Date - - contentEl.appendText("First Rep Date: ") - this.inputFirstRep = new TextComponent(contentEl) - .setPlaceholder("Date") - .setValue("1970-01-01"); - contentEl.createEl("br"); - - this.inputFirstRep.inputEl.focus(); - this.inputFirstRep.inputEl.select(); - - // - // Priority - - let pMin = this.plugin.settings.defaultPriorityMin; - let pMax = this.plugin.settings.defaultPriorityMax; - contentEl.appendText("Priority: "); - this.inputSlider = new SliderComponent(contentEl) - .setLimits(0, 100, 1) - .setValue(PriorityUtils.getPriorityBetween(pMin, pMax)) - .setDynamicTooltip(); - contentEl.createEl("br"); - - // - // Notes - - contentEl.appendText("Notes: "); - this.inputNoteField = new TextComponent(contentEl) - .setPlaceholder("Notes"); - contentEl.createEl("br"); - - // - // Button - - contentEl.createEl("br"); - let inputButton = new ButtonComponent(contentEl) - .setButtonText("Add to Queue") - .onClick(async () => { - await this.addToOutstanding(); - this.close() - }); - - this.subscribeToEvents(); - } - - subscribeToEvents() { - this.contentEl.addEventListener('keydown', async (ev) => { - if (ev.key === "PageUp"){ - let curValue = this.inputSlider.getValue(); - if (curValue < 95) - this.inputSlider.setValue(curValue + 5); - else - this.inputSlider.setValue(100); - } - else if (ev.key === "PageDown"){ - let curValue = this.inputSlider.getValue(); - if (curValue > 5) - this.inputSlider.setValue(curValue - 5); - else - this.inputSlider.setValue(0); - } - else if (ev.key === 'Enter') { - await this.addToOutstanding() - this.close(); - } - - }); - } - - getPriority(): number { - return this.inputSlider.getValue(); - } - - getNotes() { - return this.inputNoteField.getValue(); - } - - getQueuePath() { - let queue = this.inputQueueField.getValue(); - if (!queue.endsWith(".md")) - queue += ".md" - - return normalizePath([this.plugin.settings.queueFolderPath, queue].join('/')); - } - - abstract addToOutstanding(): Promise; + title: string; + inputSlider: SliderComponent; + inputNoteField: TextComponent; + inputFirstRep: TextComponent; + inputQueueField: TextComponent; + + constructor(plugin: IW, title: string) { + super(plugin); + this.title = title; + } + + onOpen() { + let { contentEl } = this; + + contentEl.createEl("h2", { text: this.title }); + + // + // Queue + + contentEl.appendText("Queue: "); + this.inputQueueField = new TextComponent(contentEl) + .setPlaceholder("Example: queue.md") + .setValue(this.plugin.settings.queueFileName); + let folderFunc = () => + this.plugin.app.vault.getAbstractFileByPath( + this.plugin.settings.queueFolderPath + ) as TFolder; + new FileSuggest(this.plugin, this.inputQueueField.inputEl, folderFunc); + contentEl.createEl("br"); + + // + // First Rep Date + + contentEl.appendText("First Rep Date: "); + this.inputFirstRep = new TextComponent(contentEl) + .setPlaceholder("Date") + .setValue("1970-01-01"); + contentEl.createEl("br"); + + this.inputFirstRep.inputEl.focus(); + this.inputFirstRep.inputEl.select(); + + // + // Priority + + let pMin = this.plugin.settings.defaultPriorityMin; + let pMax = this.plugin.settings.defaultPriorityMax; + contentEl.appendText("Priority: "); + this.inputSlider = new SliderComponent(contentEl) + .setLimits(0, 100, 1) + .setValue(PriorityUtils.getPriorityBetween(pMin, pMax)) + .setDynamicTooltip(); + contentEl.createEl("br"); + + // + // Notes + + contentEl.appendText("Notes: "); + this.inputNoteField = new TextComponent(contentEl).setPlaceholder("Notes"); + contentEl.createEl("br"); + + // + // Button + + contentEl.createEl("br"); + let inputButton = new ButtonComponent(contentEl) + .setButtonText("Add to Queue") + .onClick(async () => { + await this.addToOutstanding(); + this.close(); + }); + + this.subscribeToEvents(); + } + + subscribeToEvents() { + this.contentEl.addEventListener("keydown", async (ev) => { + if (ev.key === "PageUp") { + let curValue = this.inputSlider.getValue(); + if (curValue < 95) this.inputSlider.setValue(curValue + 5); + else this.inputSlider.setValue(100); + } else if (ev.key === "PageDown") { + let curValue = this.inputSlider.getValue(); + if (curValue > 5) this.inputSlider.setValue(curValue - 5); + else this.inputSlider.setValue(0); + } else if (ev.key === "Enter") { + await this.addToOutstanding(); + this.close(); + } + }); + } + + getPriority(): number { + return this.inputSlider.getValue(); + } + + getNotes() { + return this.inputNoteField.getValue(); + } + + getQueuePath() { + let queue = this.inputQueueField.getValue(); + if (!queue.endsWith(".md")) queue += ".md"; + + return normalizePath( + [this.plugin.settings.queueFolderPath, queue].join("/") + ); + } + + abstract addToOutstanding(): Promise; } export class ReviewNoteModal extends ReviewModal { - - constructor(plugin: IW) { - super(plugin, "Add Note to Outstanding?"); - } - - onOpen() { - super.onOpen(); - } - - async addToOutstanding() { - let date = this.parseDate(this.inputFirstRep.getValue()); - if (!date) { - LogTo.Console("Failed to parse initial repetition date!"); - return; - } - - let queue = new Queue(this.plugin, this.getQueuePath()); - let file = this.plugin.files.getActiveNoteFile(); - let link = this.plugin.files.toLinkText(file); - let row = new MarkdownTableRow(link, this.getPriority(), this.getNotes(), 1, date) - await queue.addNotesToQueue(row); - } + constructor(plugin: IW) { + super(plugin, "Add Note to Outstanding?"); + } + + onOpen() { + super.onOpen(); + } + + async addToOutstanding() { + let date = this.parseDate(this.inputFirstRep.getValue()); + if (!date) { + LogTo.Console("Failed to parse initial repetition date!"); + return; + } + + let queue = new Queue(this.plugin, this.getQueuePath()); + let file = this.plugin.files.getActiveNoteFile(); + if (!file) { + LogTo.Console("Failed to add to outstanding.", true); + return; + } + let link = this.plugin.files.toLinkText(file); + let row = new MarkdownTableRow( + link, + this.getPriority(), + this.getNotes(), + 1, + date + ); + await queue.addNotesToQueue(row); + } } export class ReviewFileModal extends ReviewModal { - - filePath: string - - constructor(plugin: IW, filePath: string) { - super(plugin, "Add File to Outstanding?"); - this.filePath = filePath; - } - - onOpen() { - super.onOpen(); - } - - async addToOutstanding() { - let date = this.parseDate(this.inputFirstRep.getValue()); - if (!date) { - LogTo.Console("Failed to parse initial repetition date!"); - return; - } - - let queue = new Queue(this.plugin, this.getQueuePath()); - let file = this.plugin.app.vault.getAbstractFileByPath(this.filePath) as TFile; - if (!file){ - LogTo.Console("Failed to add to outstanding because file was null", true); - return; - } - let link = this.plugin.files.toLinkText(file); - let row = new MarkdownTableRow(link, this.getPriority(), this.getNotes(), 1, date) - await queue.addNotesToQueue(row); - } + filePath: string; + + constructor(plugin: IW, filePath: string) { + super(plugin, "Add File to Outstanding?"); + this.filePath = filePath; + } + + onOpen() { + super.onOpen(); + } + + async addToOutstanding() { + let date = this.parseDate(this.inputFirstRep.getValue()); + if (!date) { + LogTo.Console("Failed to parse initial repetition date!"); + return; + } + + let queue = new Queue(this.plugin, this.getQueuePath()); + let file = this.plugin.files.getTFile(this.filePath); + if (!file) { + LogTo.Console("Failed to add to outstanding because file was null", true); + return; + } + let link = this.plugin.files.toLinkText(file); + let row = new MarkdownTableRow( + link, + this.getPriority(), + this.getNotes(), + 1, + date + ); + await queue.addNotesToQueue(row); + } } export class ReviewBlockModal extends ReviewModal { - - constructor(plugin: IW){ - super(plugin, "Add Block to Outstanding?"); - } - - onOpen(){ - super.onOpen(); - } - - // TODO: Change to just sending the line no? - getCurrentLineText(): string { - let editor = (this.app.workspace.activeLeaf.view as MarkdownView).editor; - let cursor = editor.getCursor(); - let lineNo = cursor.line; - return editor.getLine(lineNo); - } - - async addToOutstanding() { - let date = this.parseDate(this.inputFirstRep.getValue()); - if (!date) { - LogTo.Console("Failed to parse initial repetition date!"); - return; - } - - let queue = new Queue(this.plugin, this.getQueuePath()); - let file = this.plugin.files.getActiveNoteFile(); - await queue.addBlockToQueue(this.getPriority(), this.getNotes(), date, this.getCurrentLineText(), file); - } + constructor(plugin: IW) { + super(plugin, "Add Block to Outstanding?"); + } + + onOpen() { + super.onOpen(); + } + + // TODO: Change to just sending the line no? + getCurrentLineText(): string { + let editor = (this.app.workspace.activeLeaf.view as MarkdownView).editor; + let cursor = editor.getCursor(); + let lineNo = cursor.line; + return editor.getLine(lineNo); + } + + async addToOutstanding() { + let date = this.parseDate(this.inputFirstRep.getValue()); + if (!date) { + LogTo.Console("Failed to parse initial repetition date!"); + return; + } + + let queue = new Queue(this.plugin, this.getQueuePath()); + let file = this.plugin.files.getActiveNoteFile(); + if (!file) { + LogTo.Console("Failed to add to outstanding.", true); + return; + } + await queue.addBlockToQueue( + this.getPriority(), + this.getNotes(), + date, + this.getCurrentLineText(), + file + ); + } } diff --git a/src/views/queue-modal.ts b/src/views/queue-modal.ts index f9698e2..69b5808 100644 --- a/src/views/queue-modal.ts +++ b/src/views/queue-modal.ts @@ -1,36 +1,38 @@ -import { normalizePath, FuzzySuggestModal, TFolder } from "obsidian" -import IW from "../main" +import { normalizePath, FuzzySuggestModal, TFolder } from "obsidian"; +import IW from "../main"; export class QueueLoadModal extends FuzzySuggestModal { - - plugin: IW; - - constructor(plugin: IW) { - super(plugin.app); - this.plugin = plugin; - } - - onChooseItem(item: string, evt: MouseEvent | KeyboardEvent) { - let path = [this.plugin.settings.queueFolderPath, item].join('/'); - this.plugin.loadQueue(path); + plugin: IW; + + constructor(plugin: IW) { + super(plugin.app); + this.plugin = plugin; + } + + onChooseItem(item: string, evt: MouseEvent | KeyboardEvent) { + let path = [this.plugin.settings.queueFolderPath, item].join("/"); + this.plugin.loadQueue(path); + } + + getItems(): string[] { + let folder = this.plugin.app.vault.getAbstractFileByPath( + normalizePath(this.plugin.settings.queueFolderPath) + ) as TFolder; + if (folder) { + let files = this.plugin.app.vault + .getMarkdownFiles() + .filter((file) => this.plugin.files.isDescendantOf(file, folder)) + .map((file) => file.name); + + if (!files.some((f) => f === this.plugin.settings.queueFileName)) + files.push(this.plugin.settings.queueFileName); + return files; } - getItems(): string[] { - let folder = this.plugin.app.vault.getAbstractFileByPath(normalizePath(this.plugin.settings.queueFolderPath)) as TFolder; - if (folder) { - let files = this.plugin.app.vault.getMarkdownFiles() - .filter(file => this.plugin.files.isDescendantOf(file, folder)) - .map(file => file.name) + return [this.plugin.settings.queueFileName]; + } - if (!files.some(f => f === this.plugin.settings.queueFilePath)) - files.push(this.plugin.settings.queueFilePath); - return files; - } - - return [this.plugin.settings.queueFilePath]; - } - - getItemText(item: string) { - return item; - } + getItemText(item: string) { + return item; + } } diff --git a/src/views/settings-tab.ts b/src/views/settings-tab.ts index a2d6e60..1e5ec97 100644 --- a/src/views/settings-tab.ts +++ b/src/views/settings-tab.ts @@ -1,13 +1,19 @@ -import { TFolder, SliderComponent, normalizePath, PluginSettingTab, App, Setting } from "obsidian" -import IW from "../main" -import { FileSuggest, FolderSuggest } from "./file-suggest" -import { PriorityUtils } from "../helpers/priority-utils" +import { + TFolder, + SliderComponent, + normalizePath, + PluginSettingTab, + App, + Setting, +} from "obsidian"; +import IW from "../main"; +import { FileSuggest, FolderSuggest } from "./file-suggest"; +import { PriorityUtils } from "../helpers/priority-utils"; export class IWSettingsTab extends PluginSettingTab { - plugin: IW; - inputPriorityMin: SliderComponent - inputPriorityMax: SliderComponent + inputPriorityMin: SliderComponent; + inputPriorityMax: SliderComponent; constructor(app: App, plugin: IW) { super(app, plugin); @@ -15,128 +21,136 @@ export class IWSettingsTab extends PluginSettingTab { } display(): void { - const { containerEl } = this; - const settings = this.plugin.settings; - containerEl.empty(); + const { containerEl } = this; + const settings = this.plugin.settings; + containerEl.empty(); + + containerEl.createEl("h3", { text: "Incremental Writing Settings" }); - containerEl.createEl('h3', {text: 'Incremental Writing Settings'}); + // + // Queue Folder - // - // Queue Folder - - new Setting(containerEl) + new Setting(containerEl) .setName("Queue Folder") - .setDesc("The path to the folder where new incremental writing queues should be created. Relative to the vault root.") + .setDesc( + "The path to the folder where new incremental writing queues should be created. Relative to the vault root." + ) .addText((text) => { - text.setPlaceholder("Example: folder1/folder2") - new FolderSuggest(this.app, text.inputEl); - text.setValue(String(settings.queueFolderPath)).onChange((value) => { - settings.queueFolderPath = normalizePath(String(value)); - this.plugin.saveData(settings); - }); - }) - - // - // Default Queue - - new Setting(containerEl) + text.setPlaceholder("Example: folder1/folder2"); + new FolderSuggest(this.app, text.inputEl); + text.setValue(String(settings.queueFolderPath)).onChange((value) => { + settings.queueFolderPath = normalizePath(String(value)); + this.plugin.saveData(settings); + }); + }); + + // + // Default Queue + + new Setting(containerEl) .setName("Default Queue") - .setDesc("The name of the default incremental writing queue file. Relative to the queue folder.") + .setDesc( + "The name of the default incremental writing queue file. Relative to the queue folder." + ) .addText((text) => { + new FileSuggest( + this.plugin, + text.inputEl, + () => + this.app.vault.getAbstractFileByPath( + settings.queueFolderPath + ) as TFolder + ); + text.setPlaceholder("Example: queue.md"); + text.setValue(String(settings.queueFileName)).onChange((value) => { + let str = String(value); + if (!str) return; + let file = normalizePath(String(value)); + if (!file.endsWith(".md")) file += ".md"; + settings.queueFileName = file; + this.plugin.saveData(settings); + }); + }); - new FileSuggest(this.plugin, text.inputEl, () => this.app.vault.getAbstractFileByPath(settings.queueFolderPath) as TFolder); - text.setPlaceholder("Example: queue.md") - text.setValue(String(settings.queueFilePath)).onChange((value) => { - let str = String(value); - if (!str) - return; - let file = normalizePath(String(value)); - if (!file.endsWith(".md")) - file += ".md"; - settings.queueFilePath = file; - this.plugin.saveData(settings); - }) - }) - - // - // Default Queue Type - - new Setting(containerEl) - .setName("Default Scheduler") - .setDesc("The default scheduler to use for newly created queues.") - .addDropdown((comp) => { - comp.addOption("afactor", "A-Factor Scheduler") - comp.addOption("simple", "Simple Scheduler") - comp.setValue(String(settings.defaultQueueType)).onChange((value) => { - settings.defaultQueueType = String(value); - this.plugin.saveData(settings); - }); + // + // Default Queue Type + + new Setting(containerEl) + .setName("Default Scheduler") + .setDesc("The default scheduler to use for newly created queues.") + .addDropdown((comp) => { + comp.addOption("afactor", "A-Factor Scheduler"); + comp.addOption("simple", "Simple Scheduler"); + comp.setValue(String(settings.defaultQueueType)).onChange((value) => { + settings.defaultQueueType = String(value); + this.plugin.saveData(settings); }); + }); - // - // Skip New Note Dialog + // + // Skip New Note Dialog - // new Setting(containerEl) - // .setName("Skip Add Note Dialog?") - // .setDesc("Skip the add note dialog and use the defaults?") - // .addToggle((comp) => { - // comp.setValue(Boolean(settings.skipAddNoteWindow)).onChange((value) => { - // settings.skipAddNoteWindow = Boolean(value); - // this.plugin.saveData(settings); - // }) - // }) + // new Setting(containerEl) + // .setName("Skip Add Note Dialog?") + // .setDesc("Skip the add note dialog and use the defaults?") + // .addToggle((comp) => { + // comp.setValue(Boolean(settings.skipAddNoteWindow)).onChange((value) => { + // settings.skipAddNoteWindow = Boolean(value); + // this.plugin.saveData(settings); + // }) + // }) - // - // Priority + // + // Priority - // Min + // Min - new Setting(containerEl) + new Setting(containerEl) .setName("Default Minimum Priority") .setDesc("Default minimum priority for new repetitions.") .addSlider((comp) => { - this.inputPriorityMin = comp; - comp.setDynamicTooltip(); - comp.setValue(Number(settings.defaultPriorityMin)).onChange((value) => { - if (this.inputPriorityMax) { - let num = Number(value); - if (!PriorityUtils.isValid(num)){ - return; - } - - if (num > this.inputPriorityMax.getValue()) { - this.inputPriorityMax.setValue(num); - } - - settings.defaultPriorityMin = num; - this.plugin.saveData(settings); - } - }); + this.inputPriorityMin = comp; + comp.setDynamicTooltip(); + comp.setValue(Number(settings.defaultPriorityMin)).onChange((value) => { + if (this.inputPriorityMax) { + let num = Number(value); + if (!PriorityUtils.isValid(num)) { + return; + } + + if (num > this.inputPriorityMax.getValue()) { + this.inputPriorityMax.setValue(num); + } + + settings.defaultPriorityMin = num; + this.plugin.saveData(settings); + } + }); }); - // Max + // Max - new Setting(containerEl) + new Setting(containerEl) .setName("Default Maximum Priority") .setDesc("Default maximum priority for new repetitions.") .addSlider((comp) => { - this.inputPriorityMax = comp; - comp.setDynamicTooltip(); - comp.setValue(Number(settings.defaultPriorityMax)).onChange((value) => { - if (this.inputPriorityMin) { - let num = Number(value); - if (!PriorityUtils.isValid(num)){ - return; - } - - if (num < this.inputPriorityMin.getValue()) { - this.inputPriorityMin.setValue(num); - } - - settings.defaultPriorityMax = num; - this.plugin.saveData(settings); - } - }); + this.inputPriorityMax = comp; + comp.setDynamicTooltip(); + comp.setValue(Number(settings.defaultPriorityMax)).onChange((value) => { + if (this.inputPriorityMin) { + let num = Number(value); + if (!PriorityUtils.isValid(num)) { + return; + } + + if (num < this.inputPriorityMin.getValue()) { + this.inputPriorityMin.setValue(num); + } + + settings.defaultPriorityMax = num; + this.plugin.saveData(settings); + } + }); }); } } diff --git a/src/views/status-bar.ts b/src/views/status-bar.ts index ae9a0bf..cbf51aa 100644 --- a/src/views/status-bar.ts +++ b/src/views/status-bar.ts @@ -1,54 +1,58 @@ -import { MarkdownTableRow } from "../markdown" -import IW from "../main" -import { TFile } from "obsidian" +import { MarkdownTableRow } from "../markdown"; +import IW from "../main"; +import { TFile } from "obsidian"; export class StatusBar { + statusBarAdded: boolean; + statusBar: HTMLElement; + statusBarText: HTMLSpanElement; - statusBarAdded: boolean; - statusBar: HTMLElement - statusBarText: HTMLSpanElement; + repText: HTMLSpanElement; + queueText: HTMLSpanElement; - repText: HTMLSpanElement; - queueText: HTMLSpanElement; + plugin: IW; - plugin: IW + constructor(statusBar: HTMLElement, plugin: IW) { + this.statusBar = statusBar; + this.plugin = plugin; + } - constructor(statusBar:HTMLElement, plugin: IW) { - this.statusBar = statusBar; - this.plugin = plugin; + initStatusBar() { + if (this.statusBarAdded) { + return; } - initStatusBar() { - if(this.statusBarAdded) { - return; - } - - let status = this.statusBar.createEl('div', { prepend: true }); - this.statusBarText = status.createEl('span', { cls: ['status-bar-item-segment'] }); - this.repText = status.createEl('span', { cls: ['status-bar-item-segment'] }); - this.queueText = status.createEl('span', { cls: ['status-bar-item-segment'] }); - this.statusBarAdded = true; + let status = this.statusBar.createEl("div", { prepend: true }); + this.statusBarText = status.createEl("span", { + cls: ["status-bar-item-segment"], + }); + this.repText = status.createEl("span", { + cls: ["status-bar-item-segment"], + }); + this.queueText = status.createEl("span", { + cls: ["status-bar-item-segment"], + }); + this.statusBarAdded = true; + } + + updateCurrentQueue(queue: string) { + if (queue) { + let name = queue.split("/")[1]; + if (name.endsWith(".md")) name = name.substr(0, name.length - 3); + this.queueText.innerText = "IW Queue: " + name; } - - updateCurrentQueue(queue: string) { - if (queue){ - let name = queue.split('/')[1]; - if (name.endsWith(".md")) - name = name.substr(0, name.length - 3); - this.queueText.innerText = "IW Queue: " + name; - } + } + + updateCurrentRep(row: MarkdownTableRow) { + if (row) { + let link = row.link; + let file = this.plugin.files.getTFile(link + ".md"); + if (file) { + this.repText.innerText = "IW Rep: " + file.basename; + return; + } } - updateCurrentRep(row: MarkdownTableRow) { - if (row){ - let link = row.link; - let file = this.plugin.app.vault.getAbstractFileByPath(link + ".md") as TFile; - if (file){ - this.repText.innerText = "IW Rep: " + file.basename; - return; - } - } - - this.repText.innerText = "Current Rep: None." - } + this.repText.innerText = "Current Rep: None."; + } } diff --git a/src/views/suggest.ts b/src/views/suggest.ts index 93a977b..a8cd1c8 100644 --- a/src/views/suggest.ts +++ b/src/views/suggest.ts @@ -2,8 +2,7 @@ import { App, ISuggestOwner, Scope } from "obsidian"; import { createPopper, Instance as PopperInstance } from "@popperjs/core"; const wrapAround = (value: number, size: number): number => { - return ((value % size) + size) % size; - + return ((value % size) + size) % size; }; class Suggest { diff --git a/tsconfig.json b/tsconfig.json index 2db9545..ab624fa 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,23 +1,16 @@ { - "compilerOptions": { - "baseUrl": ".", - "inlineSourceMap": true, - "inlineSources": true, - "esModuleInterop": true, - "module": "ESNext", - "target": "ES2018", - "allowJs": true, - "noImplicitAny": true, - "moduleResolution": "node", - "importHelpers": true, - "lib": [ - "dom", - "es5", - "scripthost", - "es2015" - ] - }, - "include": [ - "**/*.ts" - ] - } + "compilerOptions": { + "baseUrl": ".", + "inlineSourceMap": true, + "inlineSources": true, + "esModuleInterop": true, + "module": "ESNext", + "target": "ES2018", + "allowJs": true, + "noImplicitAny": true, + "moduleResolution": "node", + "importHelpers": true, + "lib": ["dom", "es5", "scripthost", "es2015"] + }, + "include": ["**/*.ts"] +}