From cd5f4c97c95908d7f0429945d6b9ba589c24014c Mon Sep 17 00:00:00 2001 From: "Kritagya Bhattarai (CalfMoon)" Date: Mon, 30 Mar 2026 23:46:08 +0545 Subject: [PATCH 1/3] refactor: modularize settings file --- src/main.ts | 4 +- src/settings.ts | 165 ----------------------------- src/{ => settings}/file-suggest.ts | 0 src/settings/index.ts | 26 +++++ src/settings/manual.ts | 111 +++++++++++++++++++ src/settings/programetical.ts | 85 +++++++++++++++ 6 files changed, 224 insertions(+), 167 deletions(-) delete mode 100644 src/settings.ts rename src/{ => settings}/file-suggest.ts (100%) create mode 100644 src/settings/index.ts create mode 100644 src/settings/manual.ts create mode 100644 src/settings/programetical.ts diff --git a/src/main.ts b/src/main.ts index 6dcc154..cd210f9 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,7 +1,7 @@ import { Plugin } from "obsidian"; -import { ObsidianNode, NodeFactorSettings, DEFAULT_SETTINGS } from "./types"; -import NodeFactorSettingTab from "./settings"; +import { ObsidianNode, NodeFactorSettings, DEFAULT_SETTINGS } from "types"; +import NodeFactorSettingTab from "settings"; export default class NodeFactor extends Plugin { settings: NodeFactorSettings; diff --git a/src/settings.ts b/src/settings.ts deleted file mode 100644 index 8353120..0000000 --- a/src/settings.ts +++ /dev/null @@ -1,165 +0,0 @@ -import { - App, - ButtonComponent, - Notice, - PluginSettingTab, - SearchComponent, - Setting, - SliderComponent, -} from "obsidian"; - -import NodeFactor from "./main"; -import FileSuggest from "./file-suggest"; -import { FileData } from "./types"; - -export default class NodeFactorSettingTab extends PluginSettingTab { - plugin: NodeFactor; - - constructor(app: App, plugin: NodeFactor) { - super(app, plugin); - this.plugin = plugin; - } - - display(): void { - const { containerEl } = this; - containerEl.empty(); - - new Setting(containerEl) - .setName("Programatically set size") - .setHeading(); - - new Setting(containerEl) - .setName("Forward link weight multiplier") - .setDesc("Multiplier for forward links weight (0 to disable).") - .addSlider((slider) => { - slider - .setLimits(0, 20, 1) - .setDynamicTooltip() - .setValue(this.plugin.settings.fwdMultiplier) - .onChange(async (value) => { - this.plugin.settings.fwdMultiplier = value; - await this.plugin.saveSettings(); - this.plugin.recalculateSize(); - }); - }); - - new Setting(containerEl) - .setName("Travel forward tree") - .setDesc( - "Travel forward and add all other nodes to determine final node size.", - ) - .addToggle((toggle) => { - toggle - .setValue(this.plugin.settings.fwdTree) - .onChange(async (value) => { - this.plugin.settings.fwdTree = value; - await this.plugin.saveSettings(); - this.plugin.recalculateSize(); - }); - }); - - new Setting(containerEl) - .setName("Backward link weight multiplier") - .setDesc("Multiplier for backward links weight (0 to disable).") - .addSlider((slider) => { - slider - .setLimits(0, 20, 1) - .setDynamicTooltip() - .setValue(this.plugin.settings.bwdMultiplier) - .onChange(async (value) => { - this.plugin.settings.bwdMultiplier = value; - await this.plugin.saveSettings(); - this.plugin.recalculateSize(); - }); - }); - - new Setting(containerEl) - .setName("Character per weight") - .setDesc( - "Add 1 weight to node size per no of given character (0 to disable).", - ) - .addSlider((slider) => { - slider - .setLimits(0, 5000, 100) - .setDynamicTooltip() - .setValue(this.plugin.settings.lettersPerWt) - .onChange(async (value) => { - this.plugin.settings.lettersPerWt = value; - await this.plugin.saveSettings(); - this.plugin.recalculateSize(); - }); - }); - - new Setting(containerEl).setName("Manually set size").setHeading(); - - let selectedWeight: SliderComponent; - let selectedFile: SearchComponent; - let submitButton: ButtonComponent; - new Setting(containerEl) - .setName("Add new weight") - .setDesc("Weight added here overrides everything else.") - .addSearch((search) => { - new FileSuggest(this.app, search.inputEl); - selectedFile = search; - search - .setPlaceholder("Enter file name") - .onChange(async (value) => { - submitButton.setDisabled(value.length === 0); - }); - }) - .addSlider((slider) => { - selectedWeight = slider; - slider.setLimits(0, 100, 5).setDynamicTooltip().setValue(0); - }) - .addButton((button) => { - submitButton = button; - button - .setDisabled(true) - .setButtonText("Add") - .setTooltip("Click to add") - .onClick(async () => { - const enteredFileData: FileData = { - id: selectedFile.getValue(), - weight: selectedWeight.getValue(), - }; - selectedWeight.setValue(0); - selectedFile.setValue(""); - - const fileExists = this.plugin.settings.manual.find( - (foundFile) => foundFile.id == enteredFileData.id, - ); - - if (!fileExists) { - new Notice(`That file's size has already been entered, - remove it first to change weight.`); - return; - } - - this.plugin.settings.manual.push(enteredFileData); - await this.plugin.saveSettings(); - new Notice("Manual size added"); - - // Rerender display - this.display(); - this.plugin.recalculateSize(); - }); - }); - - // Display all manually added weights - this.plugin.settings.manual.forEach((value: FileData) => { - new Setting(containerEl) - .setName(value.id) - .setDesc(`Weight: ${String(value.weight)}`) - .addButton((button) => { - button - .setIcon("trash") - .setTooltip("Remove manually added size") - .onClick(async () => { - this.plugin.settings.manual.remove(value); - await this.plugin.saveSettings(); - this.display(); - }); - }); - }); - } -} diff --git a/src/file-suggest.ts b/src/settings/file-suggest.ts similarity index 100% rename from src/file-suggest.ts rename to src/settings/file-suggest.ts diff --git a/src/settings/index.ts b/src/settings/index.ts new file mode 100644 index 0000000..e23efaa --- /dev/null +++ b/src/settings/index.ts @@ -0,0 +1,26 @@ +import { App, PluginSettingTab } from "obsidian"; + +import NodeFactor from "main"; + +import ManualSetting from "./manual"; +import ProgrameticalSetting from "./programetical"; + +export default class NodeFactorSettingTab extends PluginSettingTab { + private plugin: NodeFactor; + + constructor(app: App, plugin: NodeFactor) { + super(app, plugin); + this.plugin = plugin; + } + + display(): void { + const { plugin, containerEl, app } = this; + containerEl.empty(); + + new ProgrameticalSetting(plugin, containerEl).display(); + + new ManualSetting(app, plugin, containerEl, () => + this.display(), + ).display(); + } +} diff --git a/src/settings/manual.ts b/src/settings/manual.ts new file mode 100644 index 0000000..4471b25 --- /dev/null +++ b/src/settings/manual.ts @@ -0,0 +1,111 @@ +import { + App, + ButtonComponent, + Notice, + SearchComponent, + Setting, + SliderComponent, +} from "obsidian"; + +import NodeFactor from "main"; +import { FileData } from "types"; + +import FileSuggest from "./file-suggest"; + +export default class ManualSetting { + private app: App; + private plugin: NodeFactor; + private containerEl: HTMLElement; + private refreshDisplay: () => void; + + constructor( + app: App, + plugin: NodeFactor, + containerEl: HTMLElement, + refreshDisplay: () => void, + ) { + this.app = app; + this.plugin = plugin; + this.containerEl = containerEl; + this.refreshDisplay = refreshDisplay; + } + + display(): void { + new Setting(this.containerEl).setName("Manually set size").setHeading(); + + let selectedWeight: SliderComponent; + let selectedFile: SearchComponent; + let submitButton: ButtonComponent; + + const addWt = new Setting(this.containerEl) + .setName("Add new weight") + .setDesc("Weight added here overrides everything else."); + + addWt.addSearch((search) => { + new FileSuggest(this.app, search.inputEl); + selectedFile = search; + search.setPlaceholder("Enter file name"); + search.onChange(async (value) => { + submitButton.setDisabled(value.length === 0); + }); + }); + + addWt.addSlider((slider) => { + selectedWeight = slider; + slider.setLimits(0, 100, 5); + slider.setDynamicTooltip(); + slider.setValue(0); + }); + + addWt.addButton((button) => { + submitButton = button; + button.setDisabled(true); + button.setButtonText("Add"); + button.setTooltip("Click to add new manual size"); + + button.onClick(async () => { + const enteredFileData: FileData = { + id: selectedFile.getValue(), + weight: selectedWeight.getValue(), + }; + selectedWeight.setValue(0); + selectedFile.setValue(""); + + const fileExists = this.plugin.settings.manual.find( + (foundFile) => foundFile.id == enteredFileData.id, + ); + + if (!fileExists) { + new Notice(`That file's size has already been entered, + remove it first to change weight.`); + return; + } + + this.plugin.settings.manual.push(enteredFileData); + await this.plugin.saveSettings(); + new Notice("New size added manually"); + + this.refreshDisplay(); + this.plugin.recalculateSize(); + }); + }); + + // Display all manually added weights & option to remove them + this.plugin.settings.manual.forEach((value: FileData) => { + const manualDisplay = new Setting(this.containerEl) + .setName(value.id) + .setDesc(`Weight: ${String(value.weight)}`); + + manualDisplay.addButton((button) => { + button.setIcon("trash"); + button.setTooltip("Remove manually added size"); + + button.onClick(async () => { + this.plugin.settings.manual.remove(value); + await this.plugin.saveSettings(); + this.refreshDisplay(); + }); + }); + }); + } +} diff --git a/src/settings/programetical.ts b/src/settings/programetical.ts new file mode 100644 index 0000000..2c0ffd2 --- /dev/null +++ b/src/settings/programetical.ts @@ -0,0 +1,85 @@ +import { Setting } from "obsidian"; + +import NodeFactor from "main"; + +export default class ProgrameticalSetting { + private plugin: NodeFactor; + private containerEl: HTMLElement; + + constructor(plugin: NodeFactor, containerEl: HTMLElement) { + this.plugin = plugin; + this.containerEl = containerEl; + } + + display(): void { + new Setting(this.containerEl) + .setName("Programatically set size") + .setHeading(); + + const fwdLinkWt = new Setting(this.containerEl) + .setName("Forward link weight multiplier") + .setDesc("Multiplier for forward links weight (0 to disable)."); + + fwdLinkWt.addSlider((slider) => { + slider.setLimits(0, 20, 1); + slider.setDynamicTooltip(); + slider.setValue(this.plugin.settings.fwdMultiplier); + + slider.onChange(async (value) => { + this.plugin.settings.fwdMultiplier = value; + await this.plugin.saveSettings(); + this.plugin.recalculateSize(); + }); + }); + + const travelFwdTree = new Setting(this.containerEl) + .setName("Travel forward tree") + .setDesc( + "Travel forward and add all other nodes to determine final node size.", + ); + + travelFwdTree.addToggle((toggle) => { + toggle.setValue(this.plugin.settings.fwdTree); + + toggle.onChange(async (value) => { + this.plugin.settings.fwdTree = value; + await this.plugin.saveSettings(); + this.plugin.recalculateSize(); + }); + }); + + const bwdLinkWt = new Setting(this.containerEl) + .setName("Backward link weight multiplier") + .setDesc("Multiplier for backward links weight (0 to disable)."); + + bwdLinkWt.addSlider((slider) => { + slider.setLimits(0, 20, 1); + slider.setDynamicTooltip(); + slider.setValue(this.plugin.settings.bwdMultiplier); + + slider.onChange(async (value) => { + this.plugin.settings.bwdMultiplier = value; + await this.plugin.saveSettings(); + this.plugin.recalculateSize(); + }); + }); + + const charWt = new Setting(this.containerEl) + .setName("Character per weight") + .setDesc( + "Add 1 weight to node size per no of given character (0 to disable).", + ); + + charWt.addSlider((slider) => { + slider.setLimits(0, 5000, 100); + slider.setDynamicTooltip(); + slider.setValue(this.plugin.settings.lettersPerWt); + + slider.onChange(async (value) => { + this.plugin.settings.lettersPerWt = value; + await this.plugin.saveSettings(); + this.plugin.recalculateSize(); + }); + }); + } +} From a36f1c9ed0e822a112ce39e8fc5d3beff7eecfe4 Mon Sep 17 00:00:00 2001 From: "Kritagya Bhattarai (CalfMoon)" Date: Tue, 31 Mar 2026 00:42:56 +0545 Subject: [PATCH 2/3] refactor: move calculation functions to new class --- src/calculator.ts | 67 +++++++++++++++++++++++++++++++++++++++++++++++ src/main.ts | 59 +++-------------------------------------- 2 files changed, 71 insertions(+), 55 deletions(-) create mode 100644 src/calculator.ts diff --git a/src/calculator.ts b/src/calculator.ts new file mode 100644 index 0000000..2d984cd --- /dev/null +++ b/src/calculator.ts @@ -0,0 +1,67 @@ +import { App } from "obsidian"; + +import { NodeFactorSettings, ObsidianNode } from "types"; + +export default class Calculations { + private app: App; + private settings: NodeFactorSettings; + + constructor(app: App, settings: NodeFactorSettings) { + this.app = app; + this.settings = settings; + } + + calcNodeWeight(node: ObsidianNode): number { + const settings = this.settings; + let weight = 0; + + const manualFileData = settings.manual.find( + (manualFileData) => manualFileData.id == node.id, + ); + if (manualFileData != null) { + return manualFileData.weight; + } + + weight += Object.keys(node.reverse).length * settings.bwdMultiplier; + if (settings.fwdTree) { + weight += + this.fwdNodeTreeSize(node, new Set()) * settings.fwdMultiplier; + } else { + weight += Object.keys(node.forward).length * settings.fwdMultiplier; + } + + if (settings.lettersPerWt != 0) { + weight += this.letterCount(node) / settings.lettersPerWt; + } + + return Math.round(weight); + } + + private letterCount(node: ObsidianNode): number { + const file = this.app.vault.getFileByPath(node.id); + if (file == null || file.extension != "md") return 0; + + return file.stat.size; + } + + private fwdNodeTreeSize( + node: ObsidianNode, + antiLoopSet: Set, + ): number { + let size = 0; + antiLoopSet.add(node.id); + + Object.entries(node.forward).forEach(([key, value]) => { + // @ts-ignore + const childNode: ObsidianNode = value.target; + + // Prevents looping if A -> B -> C -> D -> B + if (!antiLoopSet.has(key)) { + size++; + const childSize = this.fwdNodeTreeSize(childNode, antiLoopSet); + size += childSize; + } + }); + return size; + } +} diff --git a/src/main.ts b/src/main.ts index cd210f9..d389e01 100644 --- a/src/main.ts +++ b/src/main.ts @@ -2,6 +2,7 @@ import { Plugin } from "obsidian"; import { ObsidianNode, NodeFactorSettings, DEFAULT_SETTINGS } from "types"; import NodeFactorSettingTab from "settings"; +import Calculator from "calculator"; export default class NodeFactor extends Plugin { settings: NodeFactorSettings; @@ -56,12 +57,14 @@ export default class NodeFactor extends Plugin { // if graph view is initially opened when opening obsidian clearTimeout(this.timeoutId); this.timeoutId = setTimeout(() => { + const calculator = new Calculator(this.app, this.settings); + nodes.forEach((node, _i) => { let weight = 0; if (this.sizeCache.get(node.id) != undefined) { weight = this.sizeCache.get(node.id) as number; } else { - weight = this.calcNodeWeight(node); + calculator.calcNodeWeight(node); this.sizeCache.set(node.id, weight); } node.weight = weight; @@ -69,60 +72,6 @@ export default class NodeFactor extends Plugin { }, 500); } - private calcNodeWeight(node: ObsidianNode): number { - const settings = this.settings; - let weight = 0; - - const manualFileData = settings.manual.find( - (manualFileData) => manualFileData.id == node.id, - ); - if (manualFileData != null) { - return manualFileData.weight; - } - - weight += Object.keys(node.reverse).length * settings.bwdMultiplier; - if (settings.fwdTree) { - weight += - this.fwdNodeTreeSize(node, new Set()) * settings.fwdMultiplier; - } else { - weight += Object.keys(node.forward).length * settings.fwdMultiplier; - } - - if (settings.lettersPerWt != 0) { - weight += this.letterCount(node) / settings.lettersPerWt; - } - - return Math.round(weight); - } - - private letterCount(node: ObsidianNode): number { - const file = this.app.vault.getFileByPath(node.id); - if (file == null || file.extension != "md") return 0; - - return file.stat.size; - } - - private fwdNodeTreeSize( - node: ObsidianNode, - antiLoopSet: Set, - ): number { - let size = 0; - antiLoopSet.add(node.id); - - Object.entries(node.forward).forEach(([key, value]) => { - // @ts-ignore - const childNode: ObsidianNode = value.target; - - // Prevents looping if A -> B -> C -> D -> B - if (!antiLoopSet.has(key)) { - size++; - const childSize = this.fwdNodeTreeSize(childNode, antiLoopSet); - size += childSize; - } - }); - return size; - } - recalculateSize() { this.sizeCache.clear(); this.updateGraph(); From dbdf7d2a908ac141ea83dae189d70b4d590f42cf Mon Sep 17 00:00:00 2001 From: "Kritagya Bhattarai (CalfMoon)" Date: Tue, 31 Mar 2026 11:22:04 +0545 Subject: [PATCH 3/3] fix(calc): add assignment of value after calculations --- src/main.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.ts b/src/main.ts index d389e01..81c8d3a 100644 --- a/src/main.ts +++ b/src/main.ts @@ -64,7 +64,7 @@ export default class NodeFactor extends Plugin { if (this.sizeCache.get(node.id) != undefined) { weight = this.sizeCache.get(node.id) as number; } else { - calculator.calcNodeWeight(node); + weight = calculator.calcNodeWeight(node); this.sizeCache.set(node.id, weight); } node.weight = weight;