/* THIS IS A GENERATED/BUNDLED FILE BY ESBUILD if you want to view the source, please visit the github repository of this plugin */ var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); var __decorateClass = (decorators, target, key, kind) => { var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target; for (var i = decorators.length - 1, decorator; i >= 0; i--) if (decorator = decorators[i]) result = (kind ? decorator(target, key, result) : decorator(result)) || result; if (kind && result) __defProp(target, key, result); return result; }; // src/main.ts var main_exports = {}; __export(main_exports, { default: () => LovelyMindmap }); module.exports = __toCommonJS(main_exports); var import_obsidian2 = require("obsidian"); // src/tool/index.ts function debounce(delay = 100) { let lastTime = 0; let timer; return function(target, propertyKey, descriptor) { const originalMethod = descriptor.value; descriptor.value = function(...args) { const now = Date.now(); clearTimeout(timer); if (now - lastTime < delay) { return; } timer = setTimeout(() => { originalMethod.apply(this, args); lastTime = 0; }, delay); lastTime = now; }; return descriptor; }; } function calcDistance(a, b) { return Math.sqrt( (a[0] - b[0]) ** 2 + (a[1] - b[1]) ** 2 ); } function findClosestNodeByBbox(pos, nodes) { return nodes.reduce((prev, cur, idx) => { const a = [cur.bbox.minX, cur.bbox.minY]; const b = [cur.bbox.maxX, cur.bbox.minY]; const c = [cur.bbox.minX, cur.bbox.maxY]; const d = [cur.bbox.maxX, cur.bbox.maxY]; const distance = Math.min( calcDistance(pos, a), calcDistance(pos, b), calcDistance(pos, c), calcDistance(pos, d) ); if (idx === 0) { return { node: cur, distance }; } return distance < prev.distance ? { node: cur, distance } : prev; }, { node: {}, distance: 0 }); } function uuid() { const first = Math.floor(Math.random() * 9 + 1); const rest = String(Math.random()).slice(2, 10); const random9 = first + rest; return string10To64(Date.now()) + string10To64(random9); } function string10To64(str) { const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; const radix = chars.length; let num = typeof str === "string" ? parseInt(str) : str; const res = []; do { const mod = num % radix; res.push(chars[mod]); num = (num - mod) / radix; } while (num > 0); return res.join(""); } // node_modules/autobind-decorator/lib/esm/index.js function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof2(obj2) { return typeof obj2; }; } else { _typeof = function _typeof2(obj2) { return obj2 && typeof Symbol === "function" && obj2.constructor === Symbol && obj2 !== Symbol.prototype ? "symbol" : typeof obj2; }; } return _typeof(obj); } function boundMethod(target, key, descriptor) { var fn = descriptor.value; if (typeof fn !== "function") { throw new TypeError("@boundMethod decorator can only be applied to methods not: ".concat(_typeof(fn))); } var definingProperty = false; return { configurable: true, get: function get() { if (definingProperty || this === target.prototype || this.hasOwnProperty(key) || typeof fn !== "function") { return fn; } var boundFn = fn.bind(this); definingProperty = true; Object.defineProperty(this, key, { configurable: true, get: function get2() { return boundFn; }, set: function set(value) { fn = value; delete this[key]; } }); definingProperty = false; return boundFn; }, set: function set(value) { fn = value; } }; } function boundClass(target) { var keys; if (typeof Reflect !== "undefined" && typeof Reflect.ownKeys === "function") { keys = Reflect.ownKeys(target.prototype); } else { keys = Object.getOwnPropertyNames(target.prototype); if (typeof Object.getOwnPropertySymbols === "function") { keys = keys.concat(Object.getOwnPropertySymbols(target.prototype)); } } keys.forEach(function(key) { if (key === "constructor") { return; } var descriptor = Object.getOwnPropertyDescriptor(target.prototype, key); if (typeof descriptor.value === "function") { Object.defineProperty(target.prototype, key, boundMethod(target, key, descriptor)); } }); return target; } function autobind() { if (arguments.length === 1) { return boundClass.apply(void 0, arguments); } return boundMethod.apply(void 0, arguments); } // src/module/node.ts var Node = class { constructor(main) { this.main = main; } getNavigationNode() { const node = this.getSingleSelection(); if (!node || !node.isFocused || node.isEditing) return null; return node; } getCreationNode() { const node = this.getSingleSelection(); if (!node || !node.isFocused || !node.isEditing) return null; return node; } getSelection() { return this.main.canvas.selection; } getSingleSelection() { const selections = this.main.canvas.selection; if (selections.size === 0 || selections.size > 1) { return null; } return selections.values().next().value; } getFromNodes(node) { const fromNodeFilter = (edge) => edge.to.node.id === node.id; return this.main.canvas.getEdgesForNode(node).filter(fromNodeFilter).map((edge) => edge.from.node); } getToNodes(node) { const toNodeFilter = (edge) => edge.from.node.id === node.id; return this.main.canvas.getEdgesForNode(node).filter(toNodeFilter).map((edge) => edge.to.node); } getSibNodes(target) { const fromNodes = this.getFromNodes(target); const toNodes = this.getToNodes(fromNodes[0]); return toNodes.filter((node) => node.id !== target.id); } createChildren() { const selection = this.getNavigationNode(); if (!selection) return; const { x, y, width, height } = selection; const rightSideNodeFilter = (node) => { var _a, _b, _c; return ((_a = node == null ? void 0 : node.to) == null ? void 0 : _a.side) === "left" && selection.id !== ((_c = (_b = node == null ? void 0 : node.to) == null ? void 0 : _b.node) == null ? void 0 : _c.id); }; const sibNodes = this.main.canvas.getEdgesForNode(selection).filter(rightSideNodeFilter).map((node) => node.to.node); const nextNodeY = Math.max(...sibNodes.map((node) => node.y)) + this.main.setting.EPSILON; const childNode = this.main.canvas.createTextNode({ pos: { x: x + width + 200, y: nextNodeY }, size: { height, width }, text: "", focus: false, save: true }); const data = this.main.canvas.getData(); this.main.canvas.importData({ "edges": [ ...data.edges, { "id": uuid(), "fromNode": selection.id, "fromSide": "right", "toNode": childNode.id, "toSide": "left" } ], "nodes": data.nodes }); this.main.layout.useSide(selection, sibNodes.concat(childNode)); this.main.view.zoomToNode(childNode); } createSibNode(_, context) { const selection = this.getNavigationNode(); if (!selection) return; const { x, y, width, height } = selection; const { EPSILON } = this.main.setting; const isPressedShift = context.modifiers === "Shift"; const fromNode = this.main.node.getFromNodes(selection)[0]; const toNodes = this.main.node.getToNodes(fromNode); const willInsertedNode = this.main.canvas.createTextNode({ pos: { x, y: isPressedShift ? y - EPSILON : y + EPSILON }, size: { height, width }, text: "", focus: false, save: true }); const data = this.main.canvas.getData(); this.main.canvas.importData({ "edges": [ ...data.edges, { "id": uuid(), "fromNode": fromNode.id, "fromSide": "right", "toNode": willInsertedNode.id, "toSide": "left" } ], "nodes": data.nodes }); this.main.layout.useSide(fromNode, toNodes.concat(willInsertedNode)); this.main.view.zoomToNode(willInsertedNode); } }; __decorateClass([ debounce() ], Node.prototype, "createChildren", 1); __decorateClass([ debounce() ], Node.prototype, "createSibNode", 1); Node = __decorateClass([ autobind ], Node); // src/module/keymap.ts var Keymap = class { constructor(main) { this.hotkeys = []; this.main = main; this.node = main.node; } async help() { if (this.main.view.isCreating()) return; console.log("this:\n", this); console.log("app:\n", this.main.app); console.log("canvas:\n", this.main.canvas); console.log("selections:\n", this.main.canvas.selection.values().next()); } nodeNavigation(_, context) { const { key } = context; const selection = this.node.getSingleSelection(); if (!selection || selection.isEditing) { return; } const { OFFSET_WEIGHT } = this.main.setting; const data = this.main.canvas.getViewportNodes(); const offsetX = (a, b) => Math.abs(b.x - a.x); const offsetY = (a, b) => Math.abs(b.y - a.y); const endpointOffset = (a, b) => Math.min( Math.abs(b.y - a.y + 2 / a.height), Math.abs(b.y + b.height - a.y - 2 / a.height), Math.abs(b.x - a.x + 2 / a.width), Math.abs(b.x + b.width - a.x + 2 / a.width) ); const calcDistance2 = (a, b) => key === "ArrowLeft" || key === "ArrowRight" ? offsetX(a, b) + endpointOffset(a, b) ** OFFSET_WEIGHT : offsetY(a, b) + endpointOffset(a, b) ** OFFSET_WEIGHT; const isSameDirection = (node) => { const notSelf = node.id !== selection.id; const strategies = { ArrowRight: notSelf && node.x > selection.x + selection.width, ArrowLeft: notSelf && node.x + node.width < selection.x, ArrowUp: notSelf && node.y + node.height < selection.y, ArrowDown: notSelf && node.y > selection.y + selection.height }; return strategies[key]; }; const midpoints = data.filter(isSameDirection).map((node) => ({ node, offsetX: offsetX(selection, node), offsetY: offsetY(selection, node), endpointOffset: endpointOffset(selection, node), distance: calcDistance2(selection, node) })).sort((a, b) => a.distance - b.distance); if (midpoints.length > 0) { this.main.view.zoomToNode(midpoints[0].node); } } blurNode() { if (this.main.view.isCreating()) { this.main.view.creation2Navigation(); return; } if (this.main.view.isNavigating()) { this.main.view.useTouch(); return; } } focusNode() { if (this.main.view.isTouching()) { this.main.view.touch2Navigation(); return; } const navigationNode = this.main.node.getNavigationNode(); if (!!navigationNode) { this.main.view.useCreation(navigationNode); return; } } register(modifiers, key, func) { return this.main.app.scope.register(modifiers, key, func); } registerAll() { this.hotkeys.push( this.register([], "f", this.focusNode), this.register([], "Tab", this.main.node.createChildren), this.register([], "enter", this.main.node.createSibNode), this.register(["Shift"], "enter", this.main.node.createSibNode), this.register(["Alt"], "arrowLeft", this.nodeNavigation), this.register(["Alt"], "arrowRight", this.nodeNavigation), this.register(["Alt"], "arrowUp", this.nodeNavigation), this.register(["Alt"], "arrowDown", this.nodeNavigation) // this.register([], 'h', this.help) ); } unregisterAll() { this.hotkeys.forEach((key) => this.main.app.scope.unregister(key)); } }; __decorateClass([ debounce() ], Keymap.prototype, "help", 1); Keymap = __decorateClass([ autobind ], Keymap); // src/module/view.ts var View = class { constructor(main) { this.main = main; } isTouching() { return this.main.node.getSelection().size === 0; } isNavigating() { const node = this.main.node.getSingleSelection(); if (!node) return false; return node.isFocused && !node.isEditing; } isCreating() { const node = this.main.node.getSingleSelection(); if (!node) return false; return node.isFocused && node.isEditing; } useTouch() { this.main.canvas.deselectAll(); } useCreation(node) { setTimeout( () => node.startEditing(), this.main.setting.MACRO_TASK_DELAY ); } creation2Navigation() { const selection = this.main.node.getSingleSelection(); if (!selection || !this.isCreating()) return; selection.blur(); selection.focus(); } touch2Navigation() { const viewportBBox = this.main.canvas.getViewportBBox(); const centerPoint = [ (viewportBBox.minX + viewportBBox.maxX) / 2, (viewportBBox.minY + viewportBBox.maxY) / 2 ]; const viewportNodes = this.main.canvas.getViewportNodes(); const res = findClosestNodeByBbox(centerPoint, viewportNodes); this.zoomToNode(res.node); } zoomToNode(node) { this.main.canvas.selectOnly(node); this.main.canvas.zoomToSelection(); if (this.main.config.autoFocus) { this.useCreation(node); } } }; // src/module/setting.ts var import_obsidian = require("obsidian"); var DEFAULT_SETTINGS = { autoFocus: false }; var Setting = class extends import_obsidian.PluginSettingTab { constructor(main) { super(main.app, main); this.ROW_GAP = 20; this.COLUMN_GAP = 200; this.autoFocus = false; this.MACRO_TASK_DELAY = 50; this.EPSILON = 1; this.OFFSET_WEIGHT = 1.1; this.main = main; console.log("setting"); } display() { const { containerEl } = this; containerEl.empty(); containerEl.createEl("h3", { text: "\u{1F6A7}\u{1F6A7}\u{1F6A7}" }); containerEl.createEl("h3", { text: "The page is under development" }); containerEl.createEl("h3", { text: "Most settings are out-of-the-box" }); this.addAutoFocus(); } addAutoFocus() { new import_obsidian.Setting(this.containerEl).setName("autoFocus").setDesc("auto focus node when create new node").addToggle( (component) => component.setValue(this.main.config.autoFocus).onChange(async (open) => { this.main.config.autoFocus = open; await this.main.saveData(this.main.config); }) ); } async loadSettings() { this.main.config = { ...DEFAULT_SETTINGS, ...await this.main.loadData() }; } }; // src/module/layout.ts var Layout = class { constructor(main) { this.main = main; } useSide(parent, child) { const { ROW_GAP, COLUMN_GAP } = this.main.setting; const bbox = child.reduce((prev, node, idx) => { return idx > 0 ? { height: prev.height + node.height + ROW_GAP, heightNodes: prev.heightNodes.concat(node.height) } : { height: prev.height + node.height, heightNodes: prev.heightNodes.concat(node.height) }; }, { height: 0, heightNodes: [] }); const top = parent.y + parent.height * 0.5 - bbox.height * 0.5; const getSum = (arr) => arr.reduce((sum, cur) => sum + cur, 0); child.sort((a, b) => a.y - b.y).forEach((node, i) => { node.moveTo({ x: parent.width + parent.x + COLUMN_GAP, y: top + ROW_GAP * i + getSum(bbox.heightNodes.slice(0, i)) }); }); } useSurround() { } }; // src/main.ts var LovelyMindmap = class extends import_obsidian2.Plugin { constructor(app2, manifest) { super(app2, manifest); this.canvas = null; this.intervalTimer = /* @__PURE__ */ new Map(); this.node = new Node(this); this.keymap = new Keymap(this); this.view = new View(this); this.setting = new Setting(this); this.layout = new Layout(this); } createCanvasInstance() { const timer = setInterval(() => { var _a, _b; this.canvas = (_b = (_a = app.workspace.getLeavesOfType("canvas").first()) == null ? void 0 : _a.view) == null ? void 0 : _b.canvas; if (!!this.canvas) { clearInterval(this.intervalTimer.get("canvas")); } }, 1e3); if (!this.intervalTimer.get("canvas")) { this.intervalTimer.set("canvas", timer); } } async onload() { await this.setting.loadSettings(); this.addSettingTab(new Setting(this)); this.keymap.registerAll(); this.createCanvasInstance(); this.addCommand({ id: "blurNode", name: "Blur node", hotkeys: [ { modifiers: ["Mod"], key: "Escape" } ], checkCallback: () => this.keymap.blurNode() }); } onunload() { this.keymap.unregisterAll(); this.intervalTimer.forEach(clearInterval); } };