/* THIS IS A GENERATED/BUNDLED FILE BY ESBUILD if you want to view the source, please visit the github repository of this plugin */ var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __commonJS = (cb, mod) => function __require() { return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; }; 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 __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // node_modules/jsonify/lib/parse.js var require_parse = __commonJS({ "node_modules/jsonify/lib/parse.js"(exports, module2) { "use strict"; var at; var ch; var escapee = { '"': '"', "\\": "\\", "/": "/", b: "\b", f: "\f", n: "\n", r: "\r", t: " " }; var text; function error(m) { throw { name: "SyntaxError", message: m, at, text }; } function next(c) { if (c && c !== ch) { error("Expected '" + c + "' instead of '" + ch + "'"); } ch = text.charAt(at); at += 1; return ch; } function number() { var num; var str = ""; if (ch === "-") { str = "-"; next("-"); } while (ch >= "0" && ch <= "9") { str += ch; next(); } if (ch === ".") { str += "."; while (next() && ch >= "0" && ch <= "9") { str += ch; } } if (ch === "e" || ch === "E") { str += ch; next(); if (ch === "-" || ch === "+") { str += ch; next(); } while (ch >= "0" && ch <= "9") { str += ch; next(); } } num = Number(str); if (!isFinite(num)) { error("Bad number"); } return num; } function string() { var hex; var i; var str = ""; var uffff; if (ch === '"') { while (next()) { if (ch === '"') { next(); return str; } else if (ch === "\\") { next(); if (ch === "u") { uffff = 0; for (i = 0; i < 4; i += 1) { hex = parseInt(next(), 16); if (!isFinite(hex)) { break; } uffff = uffff * 16 + hex; } str += String.fromCharCode(uffff); } else if (typeof escapee[ch] === "string") { str += escapee[ch]; } else { break; } } else { str += ch; } } } error("Bad string"); } function white() { while (ch && ch <= " ") { next(); } } function word() { switch (ch) { case "t": next("t"); next("r"); next("u"); next("e"); return true; case "f": next("f"); next("a"); next("l"); next("s"); next("e"); return false; case "n": next("n"); next("u"); next("l"); next("l"); return null; default: error("Unexpected '" + ch + "'"); } } function array() { var arr = []; if (ch === "[") { next("["); white(); if (ch === "]") { next("]"); return arr; } while (ch) { arr.push(value()); white(); if (ch === "]") { next("]"); return arr; } next(","); white(); } } error("Bad array"); } function object() { var key; var obj = {}; if (ch === "{") { next("{"); white(); if (ch === "}") { next("}"); return obj; } while (ch) { key = string(); white(); next(":"); if (Object.prototype.hasOwnProperty.call(obj, key)) { error('Duplicate key "' + key + '"'); } obj[key] = value(); white(); if (ch === "}") { next("}"); return obj; } next(","); white(); } } error("Bad object"); } function value() { white(); switch (ch) { case "{": return object(); case "[": return array(); case '"': return string(); case "-": return number(); default: return ch >= "0" && ch <= "9" ? number() : word(); } } module2.exports = function(source, reviver) { var result; text = source; at = 0; ch = " "; result = value(); white(); if (ch) { error("Syntax error"); } return typeof reviver === "function" ? function walk(holder, key) { var k; var v; var val = holder[key]; if (val && typeof val === "object") { for (k in value) { if (Object.prototype.hasOwnProperty.call(val, k)) { v = walk(val, k); if (typeof v === "undefined") { delete val[k]; } else { val[k] = v; } } } } return reviver.call(holder, key, val); }({ "": result }, "") : result; }; } }); // node_modules/jsonify/lib/stringify.js var require_stringify = __commonJS({ "node_modules/jsonify/lib/stringify.js"(exports, module2) { "use strict"; var escapable = /[\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g; var gap; var indent; var meta = { // table of character substitutions "\b": "\\b", " ": "\\t", "\n": "\\n", "\f": "\\f", "\r": "\\r", '"': '\\"', "\\": "\\\\" }; var rep; function quote(string) { escapable.lastIndex = 0; return escapable.test(string) ? '"' + string.replace(escapable, function(a) { var c = meta[a]; return typeof c === "string" ? c : "\\u" + ("0000" + a.charCodeAt(0).toString(16)).slice(-4); }) + '"' : '"' + string + '"'; } function str(key, holder) { var i; var k; var v; var length; var mind = gap; var partial; var value = holder[key]; if (value && typeof value === "object" && typeof value.toJSON === "function") { value = value.toJSON(key); } if (typeof rep === "function") { value = rep.call(holder, key, value); } switch (typeof value) { case "string": return quote(value); case "number": return isFinite(value) ? String(value) : "null"; case "boolean": case "null": return String(value); case "object": if (!value) { return "null"; } gap += indent; partial = []; if (Object.prototype.toString.apply(value) === "[object Array]") { length = value.length; for (i = 0; i < length; i += 1) { partial[i] = str(i, value) || "null"; } v = partial.length === 0 ? "[]" : gap ? "[\n" + gap + partial.join(",\n" + gap) + "\n" + mind + "]" : "[" + partial.join(",") + "]"; gap = mind; return v; } if (rep && typeof rep === "object") { length = rep.length; for (i = 0; i < length; i += 1) { k = rep[i]; if (typeof k === "string") { v = str(k, value); if (v) { partial.push(quote(k) + (gap ? ": " : ":") + v); } } } } else { for (k in value) { if (Object.prototype.hasOwnProperty.call(value, k)) { v = str(k, value); if (v) { partial.push(quote(k) + (gap ? ": " : ":") + v); } } } } v = partial.length === 0 ? "{}" : gap ? "{\n" + gap + partial.join(",\n" + gap) + "\n" + mind + "}" : "{" + partial.join(",") + "}"; gap = mind; return v; default: } } module2.exports = function(value, replacer, space) { var i; gap = ""; indent = ""; if (typeof space === "number") { for (i = 0; i < space; i += 1) { indent += " "; } } else if (typeof space === "string") { indent = space; } rep = replacer; if (replacer && typeof replacer !== "function" && (typeof replacer !== "object" || typeof replacer.length !== "number")) { throw new Error("JSON.stringify"); } return str("", { "": value }); }; } }); // node_modules/jsonify/index.js var require_jsonify = __commonJS({ "node_modules/jsonify/index.js"(exports) { "use strict"; exports.parse = require_parse(); exports.stringify = require_stringify(); } }); // node_modules/isarray/index.js var require_isarray = __commonJS({ "node_modules/isarray/index.js"(exports, module2) { var toString = {}.toString; module2.exports = Array.isArray || function(arr) { return toString.call(arr) == "[object Array]"; }; } }); // node_modules/object-keys/isArguments.js var require_isArguments = __commonJS({ "node_modules/object-keys/isArguments.js"(exports, module2) { "use strict"; var toStr = Object.prototype.toString; module2.exports = function isArguments(value) { var str = toStr.call(value); var isArgs = str === "[object Arguments]"; if (!isArgs) { isArgs = str !== "[object Array]" && value !== null && typeof value === "object" && typeof value.length === "number" && value.length >= 0 && toStr.call(value.callee) === "[object Function]"; } return isArgs; }; } }); // node_modules/object-keys/implementation.js var require_implementation = __commonJS({ "node_modules/object-keys/implementation.js"(exports, module2) { "use strict"; var keysShim; if (!Object.keys) { has = Object.prototype.hasOwnProperty; toStr = Object.prototype.toString; isArgs = require_isArguments(); isEnumerable = Object.prototype.propertyIsEnumerable; hasDontEnumBug = !isEnumerable.call({ toString: null }, "toString"); hasProtoEnumBug = isEnumerable.call(function() { }, "prototype"); dontEnums = [ "toString", "toLocaleString", "valueOf", "hasOwnProperty", "isPrototypeOf", "propertyIsEnumerable", "constructor" ]; equalsConstructorPrototype = function(o) { var ctor = o.constructor; return ctor && ctor.prototype === o; }; excludedKeys = { $applicationCache: true, $console: true, $external: true, $frame: true, $frameElement: true, $frames: true, $innerHeight: true, $innerWidth: true, $onmozfullscreenchange: true, $onmozfullscreenerror: true, $outerHeight: true, $outerWidth: true, $pageXOffset: true, $pageYOffset: true, $parent: true, $scrollLeft: true, $scrollTop: true, $scrollX: true, $scrollY: true, $self: true, $webkitIndexedDB: true, $webkitStorageInfo: true, $window: true }; hasAutomationEqualityBug = function() { if (typeof window === "undefined") { return false; } for (var k in window) { try { if (!excludedKeys["$" + k] && has.call(window, k) && window[k] !== null && typeof window[k] === "object") { try { equalsConstructorPrototype(window[k]); } catch (e) { return true; } } } catch (e) { return true; } } return false; }(); equalsConstructorPrototypeIfNotBuggy = function(o) { if (typeof window === "undefined" || !hasAutomationEqualityBug) { return equalsConstructorPrototype(o); } try { return equalsConstructorPrototype(o); } catch (e) { return false; } }; keysShim = function keys(object) { var isObject = object !== null && typeof object === "object"; var isFunction = toStr.call(object) === "[object Function]"; var isArguments = isArgs(object); var isString = isObject && toStr.call(object) === "[object String]"; var theKeys = []; if (!isObject && !isFunction && !isArguments) { throw new TypeError("Object.keys called on a non-object"); } var skipProto = hasProtoEnumBug && isFunction; if (isString && object.length > 0 && !has.call(object, 0)) { for (var i = 0; i < object.length; ++i) { theKeys.push(String(i)); } } if (isArguments && object.length > 0) { for (var j = 0; j < object.length; ++j) { theKeys.push(String(j)); } } else { for (var name in object) { if (!(skipProto && name === "prototype") && has.call(object, name)) { theKeys.push(String(name)); } } } if (hasDontEnumBug) { var skipConstructor = equalsConstructorPrototypeIfNotBuggy(object); for (var k = 0; k < dontEnums.length; ++k) { if (!(skipConstructor && dontEnums[k] === "constructor") && has.call(object, dontEnums[k])) { theKeys.push(dontEnums[k]); } } } return theKeys; }; } var has; var toStr; var isArgs; var isEnumerable; var hasDontEnumBug; var hasProtoEnumBug; var dontEnums; var equalsConstructorPrototype; var excludedKeys; var hasAutomationEqualityBug; var equalsConstructorPrototypeIfNotBuggy; module2.exports = keysShim; } }); // node_modules/object-keys/index.js var require_object_keys = __commonJS({ "node_modules/object-keys/index.js"(exports, module2) { "use strict"; var slice = Array.prototype.slice; var isArgs = require_isArguments(); var origKeys = Object.keys; var keysShim = origKeys ? function keys(o) { return origKeys(o); } : require_implementation(); var originalKeys = Object.keys; keysShim.shim = function shimObjectKeys() { if (Object.keys) { var keysWorksWithArguments = function() { var args = Object.keys(arguments); return args && args.length === arguments.length; }(1, 2); if (!keysWorksWithArguments) { Object.keys = function keys(object) { if (isArgs(object)) { return originalKeys(slice.call(object)); } return originalKeys(object); }; } } else { Object.keys = keysShim; } return Object.keys || keysShim; }; module2.exports = keysShim; } }); // node_modules/es-object-atoms/index.js var require_es_object_atoms = __commonJS({ "node_modules/es-object-atoms/index.js"(exports, module2) { "use strict"; module2.exports = Object; } }); // node_modules/es-errors/index.js var require_es_errors = __commonJS({ "node_modules/es-errors/index.js"(exports, module2) { "use strict"; module2.exports = Error; } }); // node_modules/es-errors/eval.js var require_eval = __commonJS({ "node_modules/es-errors/eval.js"(exports, module2) { "use strict"; module2.exports = EvalError; } }); // node_modules/es-errors/range.js var require_range = __commonJS({ "node_modules/es-errors/range.js"(exports, module2) { "use strict"; module2.exports = RangeError; } }); // node_modules/es-errors/ref.js var require_ref = __commonJS({ "node_modules/es-errors/ref.js"(exports, module2) { "use strict"; module2.exports = ReferenceError; } }); // node_modules/es-errors/syntax.js var require_syntax = __commonJS({ "node_modules/es-errors/syntax.js"(exports, module2) { "use strict"; module2.exports = SyntaxError; } }); // node_modules/es-errors/type.js var require_type = __commonJS({ "node_modules/es-errors/type.js"(exports, module2) { "use strict"; module2.exports = TypeError; } }); // node_modules/es-errors/uri.js var require_uri = __commonJS({ "node_modules/es-errors/uri.js"(exports, module2) { "use strict"; module2.exports = URIError; } }); // node_modules/math-intrinsics/abs.js var require_abs = __commonJS({ "node_modules/math-intrinsics/abs.js"(exports, module2) { "use strict"; module2.exports = Math.abs; } }); // node_modules/math-intrinsics/floor.js var require_floor = __commonJS({ "node_modules/math-intrinsics/floor.js"(exports, module2) { "use strict"; module2.exports = Math.floor; } }); // node_modules/math-intrinsics/max.js var require_max = __commonJS({ "node_modules/math-intrinsics/max.js"(exports, module2) { "use strict"; module2.exports = Math.max; } }); // node_modules/math-intrinsics/min.js var require_min = __commonJS({ "node_modules/math-intrinsics/min.js"(exports, module2) { "use strict"; module2.exports = Math.min; } }); // node_modules/math-intrinsics/pow.js var require_pow = __commonJS({ "node_modules/math-intrinsics/pow.js"(exports, module2) { "use strict"; module2.exports = Math.pow; } }); // node_modules/math-intrinsics/round.js var require_round = __commonJS({ "node_modules/math-intrinsics/round.js"(exports, module2) { "use strict"; module2.exports = Math.round; } }); // node_modules/math-intrinsics/isNaN.js var require_isNaN = __commonJS({ "node_modules/math-intrinsics/isNaN.js"(exports, module2) { "use strict"; module2.exports = Number.isNaN || function isNaN2(a) { return a !== a; }; } }); // node_modules/math-intrinsics/sign.js var require_sign = __commonJS({ "node_modules/math-intrinsics/sign.js"(exports, module2) { "use strict"; var $isNaN = require_isNaN(); module2.exports = function sign(number) { if ($isNaN(number) || number === 0) { return number; } return number < 0 ? -1 : 1; }; } }); // node_modules/gopd/gOPD.js var require_gOPD = __commonJS({ "node_modules/gopd/gOPD.js"(exports, module2) { "use strict"; module2.exports = Object.getOwnPropertyDescriptor; } }); // node_modules/gopd/index.js var require_gopd = __commonJS({ "node_modules/gopd/index.js"(exports, module2) { "use strict"; var $gOPD = require_gOPD(); if ($gOPD) { try { $gOPD([], "length"); } catch (e) { $gOPD = null; } } module2.exports = $gOPD; } }); // node_modules/es-define-property/index.js var require_es_define_property = __commonJS({ "node_modules/es-define-property/index.js"(exports, module2) { "use strict"; var $defineProperty = Object.defineProperty || false; if ($defineProperty) { try { $defineProperty({}, "a", { value: 1 }); } catch (e) { $defineProperty = false; } } module2.exports = $defineProperty; } }); // node_modules/has-symbols/shams.js var require_shams = __commonJS({ "node_modules/has-symbols/shams.js"(exports, module2) { "use strict"; module2.exports = function hasSymbols() { if (typeof Symbol !== "function" || typeof Object.getOwnPropertySymbols !== "function") { return false; } if (typeof Symbol.iterator === "symbol") { return true; } var obj = {}; var sym = Symbol("test"); var symObj = Object(sym); if (typeof sym === "string") { return false; } if (Object.prototype.toString.call(sym) !== "[object Symbol]") { return false; } if (Object.prototype.toString.call(symObj) !== "[object Symbol]") { return false; } var symVal = 42; obj[sym] = symVal; for (var _ in obj) { return false; } if (typeof Object.keys === "function" && Object.keys(obj).length !== 0) { return false; } if (typeof Object.getOwnPropertyNames === "function" && Object.getOwnPropertyNames(obj).length !== 0) { return false; } var syms = Object.getOwnPropertySymbols(obj); if (syms.length !== 1 || syms[0] !== sym) { return false; } if (!Object.prototype.propertyIsEnumerable.call(obj, sym)) { return false; } if (typeof Object.getOwnPropertyDescriptor === "function") { var descriptor = ( /** @type {PropertyDescriptor} */ Object.getOwnPropertyDescriptor(obj, sym) ); if (descriptor.value !== symVal || descriptor.enumerable !== true) { return false; } } return true; }; } }); // node_modules/has-symbols/index.js var require_has_symbols = __commonJS({ "node_modules/has-symbols/index.js"(exports, module2) { "use strict"; var origSymbol = typeof Symbol !== "undefined" && Symbol; var hasSymbolSham = require_shams(); module2.exports = function hasNativeSymbols() { if (typeof origSymbol !== "function") { return false; } if (typeof Symbol !== "function") { return false; } if (typeof origSymbol("foo") !== "symbol") { return false; } if (typeof Symbol("bar") !== "symbol") { return false; } return hasSymbolSham(); }; } }); // node_modules/get-proto/Reflect.getPrototypeOf.js var require_Reflect_getPrototypeOf = __commonJS({ "node_modules/get-proto/Reflect.getPrototypeOf.js"(exports, module2) { "use strict"; module2.exports = typeof Reflect !== "undefined" && Reflect.getPrototypeOf || null; } }); // node_modules/get-proto/Object.getPrototypeOf.js var require_Object_getPrototypeOf = __commonJS({ "node_modules/get-proto/Object.getPrototypeOf.js"(exports, module2) { "use strict"; var $Object = require_es_object_atoms(); module2.exports = $Object.getPrototypeOf || null; } }); // node_modules/function-bind/implementation.js var require_implementation2 = __commonJS({ "node_modules/function-bind/implementation.js"(exports, module2) { "use strict"; var ERROR_MESSAGE = "Function.prototype.bind called on incompatible "; var toStr = Object.prototype.toString; var max = Math.max; var funcType = "[object Function]"; var concatty = function concatty2(a, b) { var arr = []; for (var i = 0; i < a.length; i += 1) { arr[i] = a[i]; } for (var j = 0; j < b.length; j += 1) { arr[j + a.length] = b[j]; } return arr; }; var slicy = function slicy2(arrLike, offset) { var arr = []; for (var i = offset || 0, j = 0; i < arrLike.length; i += 1, j += 1) { arr[j] = arrLike[i]; } return arr; }; var joiny = function(arr, joiner) { var str = ""; for (var i = 0; i < arr.length; i += 1) { str += arr[i]; if (i + 1 < arr.length) { str += joiner; } } return str; }; module2.exports = function bind(that) { var target = this; if (typeof target !== "function" || toStr.apply(target) !== funcType) { throw new TypeError(ERROR_MESSAGE + target); } var args = slicy(arguments, 1); var bound; var binder = function() { if (this instanceof bound) { var result = target.apply( this, concatty(args, arguments) ); if (Object(result) === result) { return result; } return this; } return target.apply( that, concatty(args, arguments) ); }; var boundLength = max(0, target.length - args.length); var boundArgs = []; for (var i = 0; i < boundLength; i++) { boundArgs[i] = "$" + i; } bound = Function("binder", "return function (" + joiny(boundArgs, ",") + "){ return binder.apply(this,arguments); }")(binder); if (target.prototype) { var Empty = function Empty2() { }; Empty.prototype = target.prototype; bound.prototype = new Empty(); Empty.prototype = null; } return bound; }; } }); // node_modules/function-bind/index.js var require_function_bind = __commonJS({ "node_modules/function-bind/index.js"(exports, module2) { "use strict"; var implementation = require_implementation2(); module2.exports = Function.prototype.bind || implementation; } }); // node_modules/call-bind-apply-helpers/functionCall.js var require_functionCall = __commonJS({ "node_modules/call-bind-apply-helpers/functionCall.js"(exports, module2) { "use strict"; module2.exports = Function.prototype.call; } }); // node_modules/call-bind-apply-helpers/functionApply.js var require_functionApply = __commonJS({ "node_modules/call-bind-apply-helpers/functionApply.js"(exports, module2) { "use strict"; module2.exports = Function.prototype.apply; } }); // node_modules/call-bind-apply-helpers/reflectApply.js var require_reflectApply = __commonJS({ "node_modules/call-bind-apply-helpers/reflectApply.js"(exports, module2) { "use strict"; module2.exports = typeof Reflect !== "undefined" && Reflect && Reflect.apply; } }); // node_modules/call-bind-apply-helpers/actualApply.js var require_actualApply = __commonJS({ "node_modules/call-bind-apply-helpers/actualApply.js"(exports, module2) { "use strict"; var bind = require_function_bind(); var $apply = require_functionApply(); var $call = require_functionCall(); var $reflectApply = require_reflectApply(); module2.exports = $reflectApply || bind.call($call, $apply); } }); // node_modules/call-bind-apply-helpers/index.js var require_call_bind_apply_helpers = __commonJS({ "node_modules/call-bind-apply-helpers/index.js"(exports, module2) { "use strict"; var bind = require_function_bind(); var $TypeError = require_type(); var $call = require_functionCall(); var $actualApply = require_actualApply(); module2.exports = function callBindBasic(args) { if (args.length < 1 || typeof args[0] !== "function") { throw new $TypeError("a function is required"); } return $actualApply(bind, $call, args); }; } }); // node_modules/dunder-proto/get.js var require_get = __commonJS({ "node_modules/dunder-proto/get.js"(exports, module2) { "use strict"; var callBind = require_call_bind_apply_helpers(); var gOPD = require_gopd(); var hasProtoAccessor; try { hasProtoAccessor = /** @type {{ __proto__?: typeof Array.prototype }} */ [].__proto__ === Array.prototype; } catch (e) { if (!e || typeof e !== "object" || !("code" in e) || e.code !== "ERR_PROTO_ACCESS") { throw e; } } var desc = !!hasProtoAccessor && gOPD && gOPD( Object.prototype, /** @type {keyof typeof Object.prototype} */ "__proto__" ); var $Object = Object; var $getPrototypeOf = $Object.getPrototypeOf; module2.exports = desc && typeof desc.get === "function" ? callBind([desc.get]) : typeof $getPrototypeOf === "function" ? ( /** @type {import('./get')} */ function getDunder(value) { return $getPrototypeOf(value == null ? value : $Object(value)); } ) : false; } }); // node_modules/get-proto/index.js var require_get_proto = __commonJS({ "node_modules/get-proto/index.js"(exports, module2) { "use strict"; var reflectGetProto = require_Reflect_getPrototypeOf(); var originalGetProto = require_Object_getPrototypeOf(); var getDunderProto = require_get(); module2.exports = reflectGetProto ? function getProto(O) { return reflectGetProto(O); } : originalGetProto ? function getProto(O) { if (!O || typeof O !== "object" && typeof O !== "function") { throw new TypeError("getProto: not an object"); } return originalGetProto(O); } : getDunderProto ? function getProto(O) { return getDunderProto(O); } : null; } }); // node_modules/hasown/index.js var require_hasown = __commonJS({ "node_modules/hasown/index.js"(exports, module2) { "use strict"; var call = Function.prototype.call; var $hasOwn = Object.prototype.hasOwnProperty; var bind = require_function_bind(); module2.exports = bind.call(call, $hasOwn); } }); // node_modules/get-intrinsic/index.js var require_get_intrinsic = __commonJS({ "node_modules/get-intrinsic/index.js"(exports, module2) { "use strict"; var undefined2; var $Object = require_es_object_atoms(); var $Error = require_es_errors(); var $EvalError = require_eval(); var $RangeError = require_range(); var $ReferenceError = require_ref(); var $SyntaxError = require_syntax(); var $TypeError = require_type(); var $URIError = require_uri(); var abs = require_abs(); var floor = require_floor(); var max = require_max(); var min = require_min(); var pow = require_pow(); var round = require_round(); var sign = require_sign(); var $Function = Function; var getEvalledConstructor = function(expressionSyntax) { try { return $Function('"use strict"; return (' + expressionSyntax + ").constructor;")(); } catch (e) { } }; var $gOPD = require_gopd(); var $defineProperty = require_es_define_property(); var throwTypeError = function() { throw new $TypeError(); }; var ThrowTypeError = $gOPD ? function() { try { arguments.callee; return throwTypeError; } catch (calleeThrows) { try { return $gOPD(arguments, "callee").get; } catch (gOPDthrows) { return throwTypeError; } } }() : throwTypeError; var hasSymbols = require_has_symbols()(); var getProto = require_get_proto(); var $ObjectGPO = require_Object_getPrototypeOf(); var $ReflectGPO = require_Reflect_getPrototypeOf(); var $apply = require_functionApply(); var $call = require_functionCall(); var needsEval = {}; var TypedArray = typeof Uint8Array === "undefined" || !getProto ? undefined2 : getProto(Uint8Array); var INTRINSICS = { __proto__: null, "%AggregateError%": typeof AggregateError === "undefined" ? undefined2 : AggregateError, "%Array%": Array, "%ArrayBuffer%": typeof ArrayBuffer === "undefined" ? undefined2 : ArrayBuffer, "%ArrayIteratorPrototype%": hasSymbols && getProto ? getProto([][Symbol.iterator]()) : undefined2, "%AsyncFromSyncIteratorPrototype%": undefined2, "%AsyncFunction%": needsEval, "%AsyncGenerator%": needsEval, "%AsyncGeneratorFunction%": needsEval, "%AsyncIteratorPrototype%": needsEval, "%Atomics%": typeof Atomics === "undefined" ? undefined2 : Atomics, "%BigInt%": typeof BigInt === "undefined" ? undefined2 : BigInt, "%BigInt64Array%": typeof BigInt64Array === "undefined" ? undefined2 : BigInt64Array, "%BigUint64Array%": typeof BigUint64Array === "undefined" ? undefined2 : BigUint64Array, "%Boolean%": Boolean, "%DataView%": typeof DataView === "undefined" ? undefined2 : DataView, "%Date%": Date, "%decodeURI%": decodeURI, "%decodeURIComponent%": decodeURIComponent, "%encodeURI%": encodeURI, "%encodeURIComponent%": encodeURIComponent, "%Error%": $Error, "%eval%": eval, // eslint-disable-line no-eval "%EvalError%": $EvalError, "%Float32Array%": typeof Float32Array === "undefined" ? undefined2 : Float32Array, "%Float64Array%": typeof Float64Array === "undefined" ? undefined2 : Float64Array, "%FinalizationRegistry%": typeof FinalizationRegistry === "undefined" ? undefined2 : FinalizationRegistry, "%Function%": $Function, "%GeneratorFunction%": needsEval, "%Int8Array%": typeof Int8Array === "undefined" ? undefined2 : Int8Array, "%Int16Array%": typeof Int16Array === "undefined" ? undefined2 : Int16Array, "%Int32Array%": typeof Int32Array === "undefined" ? undefined2 : Int32Array, "%isFinite%": isFinite, "%isNaN%": isNaN, "%IteratorPrototype%": hasSymbols && getProto ? getProto(getProto([][Symbol.iterator]())) : undefined2, "%JSON%": typeof JSON === "object" ? JSON : undefined2, "%Map%": typeof Map === "undefined" ? undefined2 : Map, "%MapIteratorPrototype%": typeof Map === "undefined" || !hasSymbols || !getProto ? undefined2 : getProto((/* @__PURE__ */ new Map())[Symbol.iterator]()), "%Math%": Math, "%Number%": Number, "%Object%": $Object, "%Object.getOwnPropertyDescriptor%": $gOPD, "%parseFloat%": parseFloat, "%parseInt%": parseInt, "%Promise%": typeof Promise === "undefined" ? undefined2 : Promise, "%Proxy%": typeof Proxy === "undefined" ? undefined2 : Proxy, "%RangeError%": $RangeError, "%ReferenceError%": $ReferenceError, "%Reflect%": typeof Reflect === "undefined" ? undefined2 : Reflect, "%RegExp%": RegExp, "%Set%": typeof Set === "undefined" ? undefined2 : Set, "%SetIteratorPrototype%": typeof Set === "undefined" || !hasSymbols || !getProto ? undefined2 : getProto((/* @__PURE__ */ new Set())[Symbol.iterator]()), "%SharedArrayBuffer%": typeof SharedArrayBuffer === "undefined" ? undefined2 : SharedArrayBuffer, "%String%": String, "%StringIteratorPrototype%": hasSymbols && getProto ? getProto(""[Symbol.iterator]()) : undefined2, "%Symbol%": hasSymbols ? Symbol : undefined2, "%SyntaxError%": $SyntaxError, "%ThrowTypeError%": ThrowTypeError, "%TypedArray%": TypedArray, "%TypeError%": $TypeError, "%Uint8Array%": typeof Uint8Array === "undefined" ? undefined2 : Uint8Array, "%Uint8ClampedArray%": typeof Uint8ClampedArray === "undefined" ? undefined2 : Uint8ClampedArray, "%Uint16Array%": typeof Uint16Array === "undefined" ? undefined2 : Uint16Array, "%Uint32Array%": typeof Uint32Array === "undefined" ? undefined2 : Uint32Array, "%URIError%": $URIError, "%WeakMap%": typeof WeakMap === "undefined" ? undefined2 : WeakMap, "%WeakRef%": typeof WeakRef === "undefined" ? undefined2 : WeakRef, "%WeakSet%": typeof WeakSet === "undefined" ? undefined2 : WeakSet, "%Function.prototype.call%": $call, "%Function.prototype.apply%": $apply, "%Object.defineProperty%": $defineProperty, "%Object.getPrototypeOf%": $ObjectGPO, "%Math.abs%": abs, "%Math.floor%": floor, "%Math.max%": max, "%Math.min%": min, "%Math.pow%": pow, "%Math.round%": round, "%Math.sign%": sign, "%Reflect.getPrototypeOf%": $ReflectGPO }; if (getProto) { try { null.error; } catch (e) { errorProto = getProto(getProto(e)); INTRINSICS["%Error.prototype%"] = errorProto; } } var errorProto; var doEval = function doEval2(name) { var value; if (name === "%AsyncFunction%") { value = getEvalledConstructor("async function () {}"); } else if (name === "%GeneratorFunction%") { value = getEvalledConstructor("function* () {}"); } else if (name === "%AsyncGeneratorFunction%") { value = getEvalledConstructor("async function* () {}"); } else if (name === "%AsyncGenerator%") { var fn = doEval2("%AsyncGeneratorFunction%"); if (fn) { value = fn.prototype; } } else if (name === "%AsyncIteratorPrototype%") { var gen = doEval2("%AsyncGenerator%"); if (gen && getProto) { value = getProto(gen.prototype); } } INTRINSICS[name] = value; return value; }; var LEGACY_ALIASES = { __proto__: null, "%ArrayBufferPrototype%": ["ArrayBuffer", "prototype"], "%ArrayPrototype%": ["Array", "prototype"], "%ArrayProto_entries%": ["Array", "prototype", "entries"], "%ArrayProto_forEach%": ["Array", "prototype", "forEach"], "%ArrayProto_keys%": ["Array", "prototype", "keys"], "%ArrayProto_values%": ["Array", "prototype", "values"], "%AsyncFunctionPrototype%": ["AsyncFunction", "prototype"], "%AsyncGenerator%": ["AsyncGeneratorFunction", "prototype"], "%AsyncGeneratorPrototype%": ["AsyncGeneratorFunction", "prototype", "prototype"], "%BooleanPrototype%": ["Boolean", "prototype"], "%DataViewPrototype%": ["DataView", "prototype"], "%DatePrototype%": ["Date", "prototype"], "%ErrorPrototype%": ["Error", "prototype"], "%EvalErrorPrototype%": ["EvalError", "prototype"], "%Float32ArrayPrototype%": ["Float32Array", "prototype"], "%Float64ArrayPrototype%": ["Float64Array", "prototype"], "%FunctionPrototype%": ["Function", "prototype"], "%Generator%": ["GeneratorFunction", "prototype"], "%GeneratorPrototype%": ["GeneratorFunction", "prototype", "prototype"], "%Int8ArrayPrototype%": ["Int8Array", "prototype"], "%Int16ArrayPrototype%": ["Int16Array", "prototype"], "%Int32ArrayPrototype%": ["Int32Array", "prototype"], "%JSONParse%": ["JSON", "parse"], "%JSONStringify%": ["JSON", "stringify"], "%MapPrototype%": ["Map", "prototype"], "%NumberPrototype%": ["Number", "prototype"], "%ObjectPrototype%": ["Object", "prototype"], "%ObjProto_toString%": ["Object", "prototype", "toString"], "%ObjProto_valueOf%": ["Object", "prototype", "valueOf"], "%PromisePrototype%": ["Promise", "prototype"], "%PromiseProto_then%": ["Promise", "prototype", "then"], "%Promise_all%": ["Promise", "all"], "%Promise_reject%": ["Promise", "reject"], "%Promise_resolve%": ["Promise", "resolve"], "%RangeErrorPrototype%": ["RangeError", "prototype"], "%ReferenceErrorPrototype%": ["ReferenceError", "prototype"], "%RegExpPrototype%": ["RegExp", "prototype"], "%SetPrototype%": ["Set", "prototype"], "%SharedArrayBufferPrototype%": ["SharedArrayBuffer", "prototype"], "%StringPrototype%": ["String", "prototype"], "%SymbolPrototype%": ["Symbol", "prototype"], "%SyntaxErrorPrototype%": ["SyntaxError", "prototype"], "%TypedArrayPrototype%": ["TypedArray", "prototype"], "%TypeErrorPrototype%": ["TypeError", "prototype"], "%Uint8ArrayPrototype%": ["Uint8Array", "prototype"], "%Uint8ClampedArrayPrototype%": ["Uint8ClampedArray", "prototype"], "%Uint16ArrayPrototype%": ["Uint16Array", "prototype"], "%Uint32ArrayPrototype%": ["Uint32Array", "prototype"], "%URIErrorPrototype%": ["URIError", "prototype"], "%WeakMapPrototype%": ["WeakMap", "prototype"], "%WeakSetPrototype%": ["WeakSet", "prototype"] }; var bind = require_function_bind(); var hasOwn = require_hasown(); var $concat = bind.call($call, Array.prototype.concat); var $spliceApply = bind.call($apply, Array.prototype.splice); var $replace = bind.call($call, String.prototype.replace); var $strSlice = bind.call($call, String.prototype.slice); var $exec = bind.call($call, RegExp.prototype.exec); var rePropName = /[^%.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|%$))/g; var reEscapeChar = /\\(\\)?/g; var stringToPath = function stringToPath2(string) { var first = $strSlice(string, 0, 1); var last = $strSlice(string, -1); if (first === "%" && last !== "%") { throw new $SyntaxError("invalid intrinsic syntax, expected closing `%`"); } else if (last === "%" && first !== "%") { throw new $SyntaxError("invalid intrinsic syntax, expected opening `%`"); } var result = []; $replace(string, rePropName, function(match, number, quote, subString) { result[result.length] = quote ? $replace(subString, reEscapeChar, "$1") : number || match; }); return result; }; var getBaseIntrinsic = function getBaseIntrinsic2(name, allowMissing) { var intrinsicName = name; var alias; if (hasOwn(LEGACY_ALIASES, intrinsicName)) { alias = LEGACY_ALIASES[intrinsicName]; intrinsicName = "%" + alias[0] + "%"; } if (hasOwn(INTRINSICS, intrinsicName)) { var value = INTRINSICS[intrinsicName]; if (value === needsEval) { value = doEval(intrinsicName); } if (typeof value === "undefined" && !allowMissing) { throw new $TypeError("intrinsic " + name + " exists, but is not available. Please file an issue!"); } return { alias, name: intrinsicName, value }; } throw new $SyntaxError("intrinsic " + name + " does not exist!"); }; module2.exports = function GetIntrinsic(name, allowMissing) { if (typeof name !== "string" || name.length === 0) { throw new $TypeError("intrinsic name must be a non-empty string"); } if (arguments.length > 1 && typeof allowMissing !== "boolean") { throw new $TypeError('"allowMissing" argument must be a boolean'); } if ($exec(/^%?[^%]*%?$/, name) === null) { throw new $SyntaxError("`%` may not be present anywhere but at the beginning and end of the intrinsic name"); } var parts = stringToPath(name); var intrinsicBaseName = parts.length > 0 ? parts[0] : ""; var intrinsic = getBaseIntrinsic("%" + intrinsicBaseName + "%", allowMissing); var intrinsicRealName = intrinsic.name; var value = intrinsic.value; var skipFurtherCaching = false; var alias = intrinsic.alias; if (alias) { intrinsicBaseName = alias[0]; $spliceApply(parts, $concat([0, 1], alias)); } for (var i = 1, isOwn = true; i < parts.length; i += 1) { var part = parts[i]; var first = $strSlice(part, 0, 1); var last = $strSlice(part, -1); if ((first === '"' || first === "'" || first === "`" || (last === '"' || last === "'" || last === "`")) && first !== last) { throw new $SyntaxError("property names with quotes must have matching quotes"); } if (part === "constructor" || !isOwn) { skipFurtherCaching = true; } intrinsicBaseName += "." + part; intrinsicRealName = "%" + intrinsicBaseName + "%"; if (hasOwn(INTRINSICS, intrinsicRealName)) { value = INTRINSICS[intrinsicRealName]; } else if (value != null) { if (!(part in value)) { if (!allowMissing) { throw new $TypeError("base intrinsic for " + name + " exists, but the property is not available."); } return void undefined2; } if ($gOPD && i + 1 >= parts.length) { var desc = $gOPD(value, part); isOwn = !!desc; if (isOwn && "get" in desc && !("originalValue" in desc.get)) { value = desc.get; } else { value = value[part]; } } else { isOwn = hasOwn(value, part); value = value[part]; } if (isOwn && !skipFurtherCaching) { INTRINSICS[intrinsicRealName] = value; } } } return value; }; } }); // node_modules/define-data-property/index.js var require_define_data_property = __commonJS({ "node_modules/define-data-property/index.js"(exports, module2) { "use strict"; var $defineProperty = require_es_define_property(); var $SyntaxError = require_syntax(); var $TypeError = require_type(); var gopd = require_gopd(); module2.exports = function defineDataProperty(obj, property, value) { if (!obj || typeof obj !== "object" && typeof obj !== "function") { throw new $TypeError("`obj` must be an object or a function`"); } if (typeof property !== "string" && typeof property !== "symbol") { throw new $TypeError("`property` must be a string or a symbol`"); } if (arguments.length > 3 && typeof arguments[3] !== "boolean" && arguments[3] !== null) { throw new $TypeError("`nonEnumerable`, if provided, must be a boolean or null"); } if (arguments.length > 4 && typeof arguments[4] !== "boolean" && arguments[4] !== null) { throw new $TypeError("`nonWritable`, if provided, must be a boolean or null"); } if (arguments.length > 5 && typeof arguments[5] !== "boolean" && arguments[5] !== null) { throw new $TypeError("`nonConfigurable`, if provided, must be a boolean or null"); } if (arguments.length > 6 && typeof arguments[6] !== "boolean") { throw new $TypeError("`loose`, if provided, must be a boolean"); } var nonEnumerable = arguments.length > 3 ? arguments[3] : null; var nonWritable = arguments.length > 4 ? arguments[4] : null; var nonConfigurable = arguments.length > 5 ? arguments[5] : null; var loose = arguments.length > 6 ? arguments[6] : false; var desc = !!gopd && gopd(obj, property); if ($defineProperty) { $defineProperty(obj, property, { configurable: nonConfigurable === null && desc ? desc.configurable : !nonConfigurable, enumerable: nonEnumerable === null && desc ? desc.enumerable : !nonEnumerable, value, writable: nonWritable === null && desc ? desc.writable : !nonWritable }); } else if (loose || !nonEnumerable && !nonWritable && !nonConfigurable) { obj[property] = value; } else { throw new $SyntaxError("This environment does not support defining a property as non-configurable, non-writable, or non-enumerable."); } }; } }); // node_modules/has-property-descriptors/index.js var require_has_property_descriptors = __commonJS({ "node_modules/has-property-descriptors/index.js"(exports, module2) { "use strict"; var $defineProperty = require_es_define_property(); var hasPropertyDescriptors = function hasPropertyDescriptors2() { return !!$defineProperty; }; hasPropertyDescriptors.hasArrayLengthDefineBug = function hasArrayLengthDefineBug() { if (!$defineProperty) { return null; } try { return $defineProperty([], "length", { value: 1 }).length !== 1; } catch (e) { return true; } }; module2.exports = hasPropertyDescriptors; } }); // node_modules/set-function-length/index.js var require_set_function_length = __commonJS({ "node_modules/set-function-length/index.js"(exports, module2) { "use strict"; var GetIntrinsic = require_get_intrinsic(); var define = require_define_data_property(); var hasDescriptors = require_has_property_descriptors()(); var gOPD = require_gopd(); var $TypeError = require_type(); var $floor = GetIntrinsic("%Math.floor%"); module2.exports = function setFunctionLength(fn, length) { if (typeof fn !== "function") { throw new $TypeError("`fn` is not a function"); } if (typeof length !== "number" || length < 0 || length > 4294967295 || $floor(length) !== length) { throw new $TypeError("`length` must be a positive 32-bit integer"); } var loose = arguments.length > 2 && !!arguments[2]; var functionLengthIsConfigurable = true; var functionLengthIsWritable = true; if ("length" in fn && gOPD) { var desc = gOPD(fn, "length"); if (desc && !desc.configurable) { functionLengthIsConfigurable = false; } if (desc && !desc.writable) { functionLengthIsWritable = false; } } if (functionLengthIsConfigurable || functionLengthIsWritable || !loose) { if (hasDescriptors) { define( /** @type {Parameters[0]} */ fn, "length", length, true, true ); } else { define( /** @type {Parameters[0]} */ fn, "length", length ); } } return fn; }; } }); // node_modules/call-bind-apply-helpers/applyBind.js var require_applyBind = __commonJS({ "node_modules/call-bind-apply-helpers/applyBind.js"(exports, module2) { "use strict"; var bind = require_function_bind(); var $apply = require_functionApply(); var actualApply = require_actualApply(); module2.exports = function applyBind() { return actualApply(bind, $apply, arguments); }; } }); // node_modules/call-bind/index.js var require_call_bind = __commonJS({ "node_modules/call-bind/index.js"(exports, module2) { "use strict"; var setFunctionLength = require_set_function_length(); var $defineProperty = require_es_define_property(); var callBindBasic = require_call_bind_apply_helpers(); var applyBind = require_applyBind(); module2.exports = function callBind(originalFunction) { var func = callBindBasic(arguments); var adjustedLength = originalFunction.length - (arguments.length - 1); return setFunctionLength( func, 1 + (adjustedLength > 0 ? adjustedLength : 0), true ); }; if ($defineProperty) { $defineProperty(module2.exports, "apply", { value: applyBind }); } else { module2.exports.apply = applyBind; } } }); // node_modules/call-bound/index.js var require_call_bound = __commonJS({ "node_modules/call-bound/index.js"(exports, module2) { "use strict"; var GetIntrinsic = require_get_intrinsic(); var callBindBasic = require_call_bind_apply_helpers(); var $indexOf = callBindBasic([GetIntrinsic("%String.prototype.indexOf%")]); module2.exports = function callBoundIntrinsic(name, allowMissing) { var intrinsic = ( /** @type {Parameters[0][0]} */ GetIntrinsic(name, !!allowMissing) ); if (typeof intrinsic === "function" && $indexOf(name, ".prototype.") > -1) { return callBindBasic([intrinsic]); } return intrinsic; }; } }); // node_modules/json-stable-stringify/index.js var require_json_stable_stringify = __commonJS({ "node_modules/json-stable-stringify/index.js"(exports, module2) { "use strict"; var jsonStringify = (typeof JSON !== "undefined" ? JSON : require_jsonify()).stringify; var isArray = require_isarray(); var objectKeys = require_object_keys(); var callBind = require_call_bind(); var callBound = require_call_bound(); var $join = callBound("Array.prototype.join"); var $indexOf = callBound("Array.prototype.indexOf"); var $splice = callBound("Array.prototype.splice"); var $sort = callBound("Array.prototype.sort"); var strRepeat = function repeat(n, char) { var str = ""; for (var i = 0; i < n; i += 1) { str += char; } return str; }; var defaultReplacer = function(_parent, _key, value) { return value; }; module2.exports = function stableStringify(obj) { var opts = arguments.length > 1 ? arguments[1] : void 0; var space = opts && opts.space || ""; if (typeof space === "number") { space = strRepeat(space, " "); } var cycles = !!opts && typeof opts.cycles === "boolean" && opts.cycles; var replacer = opts && opts.replacer ? callBind(opts.replacer) : defaultReplacer; var cmpOpt = typeof opts === "function" ? opts : opts && opts.cmp; var cmp = cmpOpt && function(node) { var get = ( /** @type {NonNullable} */ cmpOpt.length > 2 && /** @type {import('.').Getter['get']} */ function get2(k) { return node[k]; } ); return function(a, b) { return ( /** @type {NonNullable} */ cmpOpt( { key: a, value: node[a] }, { key: b, value: node[b] }, // @ts-expect-error TS doesn't understand the optimization used here get ? ( /** @type {import('.').Getter} */ { __proto__: null, get } ) : void 0 ) ); }; }; var seen = []; return ( /** @type {(parent: import('.').Node, key: string | number, node: unknown, level: number) => string | undefined} */ function stringify(parent, key, node, level) { var indent = space ? "\n" + strRepeat(level, space) : ""; var colonSeparator = space ? ": " : ":"; if (node && /** @type {{ toJSON?: unknown }} */ node.toJSON && typeof /** @type {{ toJSON?: unknown }} */ node.toJSON === "function") { node = /** @type {{ toJSON: Function }} */ node.toJSON(); } node = replacer(parent, key, node); if (node === void 0) { return; } if (typeof node !== "object" || node === null) { return jsonStringify(node); } if (isArray(node)) { var out = []; for (var i = 0; i < node.length; i++) { var item = stringify(node, i, node[i], level + 1) || jsonStringify(null); out[out.length] = indent + space + item; } return "[" + $join(out, ",") + indent + "]"; } if ($indexOf(seen, node) !== -1) { if (cycles) { return jsonStringify("__cycle__"); } throw new TypeError("Converting circular structure to JSON"); } else { seen[seen.length] = /** @type {import('.').NonArrayNode} */ node; } var keys = $sort(objectKeys(node), cmp && cmp( /** @type {import('.').NonArrayNode} */ node )); var out = []; for (var i = 0; i < keys.length; i++) { var key = keys[i]; var value = stringify( /** @type {import('.').Node} */ node, key, /** @type {import('.').NonArrayNode} */ node[key], level + 1 ); if (!value) { continue; } var keyValue = jsonStringify(key) + colonSeparator + value; out[out.length] = indent + space + keyValue; } $splice(seen, $indexOf(seen, node), 1); return "{" + $join(out, ",") + indent + "}"; }({ "": obj }, "", obj, 0) ); }; } }); // src/main.ts var main_exports = {}; __export(main_exports, { default: () => AdvancedCanvasPlugin }); module.exports = __toCommonJS(main_exports); var import_obsidian18 = require("obsidian"); // src/utils/icons-helper.ts var import_obsidian = require("obsidian"); var CUSTOM_ICONS = { "shape-pill": ``, "shape-parallelogram": ``, "shape-predefined-process": ` `, "shape-document": ``, "shape-database": ` `, "border-solid": ``, "border-dashed": ``, "border-dotted": ``, "path-solid": ``, "path-dotted": ``, "path-short-dashed": ``, "path-long-dashed": ``, "arrow-triangle": ``, "arrow-triangle-outline": ``, "arrow-thin-triangle": ``, "arrow-halved-triangle": ``, "arrow-diamond": ``, "arrow-diamond-outline": ``, "arrow-circle": ``, "arrow-circle-outline": ``, "pathfinding-method-bezier": ``, "pathfinding-method-square": `` }; var IconsHelper = class { static addIcons() { for (const [id, svg] of Object.entries(CUSTOM_ICONS)) { (0, import_obsidian.addIcon)(id, svg); } } }; // src/utils/debug-helper.ts var DebugHelper = class { constructor(plugin) { this.logging = true; this.nodeAddedCount = 0; this.nodeChangedCount = 0; this.edgeAddedCount = 0; this.edgeChangedCount = 0; this.plugin = plugin; this.plugin.registerEvent(this.plugin.app.workspace.on( "advanced-canvas:canvas-changed", (_canvas) => { this.nodeAddedCount = 0; this.nodeChangedCount = 0; this.edgeAddedCount = 0; this.edgeChangedCount = 0; } )); this.plugin.registerEvent(this.plugin.app.workspace.on( "advanced-canvas:node-added", (_canvas, _node) => { if (this.logging) console.count("\u{1F7E2} NodeAdded"); this.nodeAddedCount++; } )); this.plugin.registerEvent(this.plugin.app.workspace.on( "advanced-canvas:node-changed", (_canvas, _node) => { if (this.logging) console.count("\u{1F7E1} NodeChanged"); this.nodeChangedCount++; } )); this.plugin.registerEvent(this.plugin.app.workspace.on( "advanced-canvas:edge-added", (_canvas, _edge) => { if (this.logging) console.count("\u{1F7E2} EdgeAdded"); this.edgeAddedCount++; } )); this.plugin.registerEvent(this.plugin.app.workspace.on( "advanced-canvas:edge-changed", (_canvas, _edge) => { if (this.logging) console.count("\u{1F7E1} EdgeChanged"); this.edgeChangedCount++; } )); } resetEfficiency() { this.nodeAddedCount = 0; this.nodeChangedCount = 0; this.edgeAddedCount = 0; this.edgeChangedCount = 0; } logEfficiency() { const canvas = this.plugin.getCurrentCanvas(); if (!canvas) return; console.log("NodeAdded Efficiency:", this.nodeAddedCount / canvas.nodes.size); console.log("NodeChanged Efficiency:", this.nodeChangedCount / canvas.nodes.size); console.log("EdgeAdded Efficiency:", this.edgeAddedCount / canvas.edges.size); console.log("EdgeChanged Efficiency:", this.edgeChangedCount / canvas.edges.size); } static markBBox(canvas, bbox, duration = -1) { const node = canvas.createTextNode({ pos: { x: bbox.minX, y: bbox.minY }, size: { width: bbox.maxX - bbox.minX, height: bbox.maxY - bbox.minY }, text: "", focus: false }); node.setData({ ...node.getData(), id: "debug-bbox", color: "1", styleAttributes: { border: "invisible" } }); if (duration >= 0) { setTimeout(() => { canvas.removeNode(node); }, duration); } } }; // src/settings.ts var import_obsidian2 = require("obsidian"); // src/utils/text-helper.ts var TextHelper = class { static toCamelCase(str) { return str.replace(/-./g, (x) => x[1].toUpperCase()); } }; // src/canvas-extensions/advanced-styles/style-config.ts function styleAttributeValidator(json) { var _a; const hasKey = json.key !== void 0; const hasLabel = json.label !== void 0; const hasOptions = Array.isArray(json.options); if (!hasKey) console.error('Style attribute is missing the "key" property'); if (!hasLabel) console.error('Style attribute is missing the "label" property'); if (!hasOptions) console.error('Style attribute is missing the "options" property or it is not an array'); json.key = TextHelper.toCamelCase(json.key); let optionsValid = true; let hasDefault = false; for (const option of json.options) { const hasIcon = option.icon !== void 0; const hasLabel2 = option.label !== void 0; const hasValue = option.value !== void 0; if (!hasIcon) console.error(`Style attribute option (${(_a = option.value) != null ? _a : option.label}) is missing the "icon" property`); if (!hasLabel2) console.error(`Style attribute option (${option.value}) is missing the "label" property`); if (!hasValue) console.error(`Style attribute option (${option.label}) is missing the "value" property`); if (!hasIcon || !hasLabel2 || !hasValue) optionsValid = false; if (option.value === null) hasDefault = true; } if (!hasDefault) console.error('Style attribute is missing a default option (option with a "value" of null)'); const isValid = hasKey && hasLabel && hasOptions && optionsValid && hasDefault; return isValid ? json : null; } var BUILTIN_NODE_STYLE_ATTRIBUTES = [ { key: "textAlign", label: "Text Alignment", nodeTypes: ["text"], options: [ { icon: "align-left", label: "Left", value: null }, { icon: "align-center", label: "Center", value: "center" }, { icon: "align-right", label: "Right", value: "right" } ] }, { key: "shape", label: "Shape", nodeTypes: ["text"], options: [ { icon: "rectangle-horizontal", label: "Round Rectangle", value: null }, { icon: "shape-pill", label: "Pill", value: "pill" }, { icon: "diamond", label: "Diamond", value: "diamond" }, { icon: "shape-parallelogram", label: "Parallelogram", value: "parallelogram" }, { icon: "circle", label: "Circle", value: "circle" }, { icon: "shape-predefined-process", label: "Predefined Process", value: "predefined-process" }, { icon: "shape-document", label: "Document", value: "document" }, { icon: "shape-database", label: "Database", value: "database" } ] }, { key: "border", label: "Border", options: [ { icon: "border-solid", label: "Solid", value: null }, { icon: "border-dashed", label: "Dashed", value: "dashed" }, { icon: "border-dotted", label: "Dotted", value: "dotted" }, { icon: "eye-off", label: "Invisible", value: "invisible" } ] } ]; var BUILTIN_EDGE_STYLE_ATTRIBUTES = [ { key: "path", label: "Path Style", options: [ { icon: "path-solid", label: "Solid", value: null }, { icon: "path-dotted", label: "Dotted", value: "dotted" }, { icon: "path-short-dashed", label: "Short Dashed", value: "short-dashed" }, { icon: "path-long-dashed", label: "Long Dashed", value: "long-dashed" } ] }, { key: "arrow", label: "Arrow Style", options: [ { icon: "arrow-triangle", label: "Triangle", value: null }, { icon: "arrow-triangle-outline", label: "Triangle Outline", value: "triangle-outline" }, { icon: "arrow-thin-triangle", label: "Thin Triangle", value: "thin-triangle" }, { icon: "arrow-halved-triangle", label: "Halved Triangle", value: "halved-triangle" }, { icon: "arrow-diamond", label: "Diamond", value: "diamond" }, { icon: "arrow-diamond-outline", label: "Diamond Outline", value: "diamond-outline" }, { icon: "arrow-circle", label: "Circle", value: "circle" }, { icon: "arrow-circle-outline", label: "Circle Outline", value: "circle-outline" }, { icon: "tally-1", label: "Blunt", value: "blunt" } ] }, { key: "pathfindingMethod", label: "Pathfinding Method", options: [ { icon: "pathfinding-method-bezier", label: "Bezier", value: null }, { icon: "slash", label: "Direct", value: "direct" }, { icon: "pathfinding-method-square", label: "Square", value: "square" }, { icon: "map", label: "A*", value: "a-star" } ] } ]; // src/canvas-extensions/canvas-extension.ts var CanvasExtension = class { constructor(plugin) { this.plugin = plugin; const isEnabled = this.isEnabled(); if (!(isEnabled === true || this.plugin.settings.getSetting(isEnabled))) return; this.init(); } }; // src/canvas-extensions/variable-breakpoint-canvas-extension.ts var VARIABLE_BREAKPOINT_CSS_VAR = "--variable-breakpoint"; var VariableBreakpointCanvasExtension = class extends CanvasExtension { isEnabled() { return "variableBreakpointFeatureEnabled"; } init() { this.plugin.registerEvent(this.plugin.app.workspace.on( "advanced-canvas:node-breakpoint-changed", (canvas, node, breakpointRef) => this.onNodeBreakpointChanged(canvas, node, breakpointRef) )); } onNodeBreakpointChanged(canvas, node, breakpointRef) { if (!node.initialized) return; if (node.breakpoint === void 0) { const computedStyle = window.getComputedStyle(node.nodeEl); const variableBreakpointString = computedStyle.getPropertyValue(VARIABLE_BREAKPOINT_CSS_VAR); let numberBreakpoint; if (variableBreakpointString.length > 0 && !isNaN(numberBreakpoint = parseFloat(variableBreakpointString))) node.breakpoint = numberBreakpoint; else node.breakpoint = null; } if (node.breakpoint === null) return; breakpointRef.value = canvas.zoom > node.breakpoint; } }; // src/settings.ts var README_URL = "https://github.com/Developer-Mike/obsidian-advanced-canvas?tab=readme-ov-file"; var ASK_FOR_DONATION_DELAY = 1e3 * 60 * 60 * 24 * 7; var SPENT_HOURS = 190; var RECEIVED_DONATIONS = 409; var HOURLY_RATE_GOAL = 20; var KOFI_PAGE_URL = "https://ko-fi.com/X8X27IA08"; var KOFI_BADGE_URI = "data:image/webp;base64,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"; var DEFAULT_SETTINGS_VALUES = { downloadTimestamp: (/* @__PURE__ */ new Date()).getTime(), askedForDonation: false, nodeTypeOnDoubleClick: "text", alignNewNodesToGrid: true, defaultTextNodeDimensions: [260, 60], defaultFileNodeDimensions: [400, 400], minNodeSize: 60, maxNodeWidth: -1, disableFontSizeRelativeToZoom: false, canvasMetadataCompatibilityEnabled: true, treatFileNodeEdgesAsLinks: true, enableSingleNodeLinks: true, combineCustomStylesInDropdown: false, nodeStylingFeatureEnabled: true, customNodeStyleAttributes: [], defaultTextNodeStyleAttributes: {}, edgesStylingFeatureEnabled: true, customEdgeStyleAttributes: [], defaultEdgeLineDirection: "unidirectional", defaultEdgeStyleAttributes: {}, edgeStyleUpdateWhileDragging: false, edgeStyleSquarePathRounded: true, edgeStylePathfinderAllowDiagonal: false, edgeStylePathfinderPathRounded: true, variableBreakpointFeatureEnabled: false, zOrderingControlFeatureEnabled: false, zOrderingControlShowOneLayerShiftOptions: false, aspectRatioControlFeatureEnabled: false, commandsFeatureEnabled: true, zoomToClonedNode: true, cloneNodeMargin: 20, expandNodeStepSize: 20, nativeFileSearchEnabled: true, floatingEdgeFeatureEnabled: true, allowFloatingEdgeCreation: false, newEdgeFromSideFloating: false, flipEdgeFeatureEnabled: true, betterExportFeatureEnabled: true, betterReadonlyEnabled: false, hideBackgroundGridWhenInReadonly: true, disableNodePopup: false, disableZoom: false, disablePan: false, autoResizeNodeFeatureEnabled: false, autoResizeNodeEnabledByDefault: false, autoResizeNodeMaxHeight: -1, autoResizeNodeSnapToGrid: true, collapsibleGroupsFeatureEnabled: true, collapsedGroupPreviewOnDrag: true, focusModeFeatureEnabled: false, presentationFeatureEnabled: true, showSetStartNodeInPopup: false, defaultSlideDimensions: [1200, 675], wrapInSlidePadding: 20, resetViewportOnPresentationEnd: true, useArrowKeysToChangeSlides: true, usePgUpPgDownKeysToChangeSlides: true, zoomToSlideWithoutPadding: true, useUnclampedZoomWhilePresenting: false, slideTransitionAnimationDuration: 0.5, slideTransitionAnimationIntensity: 1.25, canvasEncapsulationEnabled: false, portalsFeatureEnabled: true, showEdgesIntoDisabledPortals: true, autoFileNodeEdgesFeatureEnabled: false, autoFileNodeEdgesFrontmatterKey: "canvas-edges", edgeHighlightEnabled: false, highlightIncomingEdges: false }; var SETTINGS = { // @ts-ignore general: { label: "General", description: "General settings of the Advanced Canvas plugin.", disableToggle: true, children: { nodeTypeOnDoubleClick: { label: "Node type on double click", description: "The type of node that will be created when double clicking on the canvas.", type: "dropdown", options: { "text": "Text", "file": "File" } }, alignNewNodesToGrid: { label: "Always align new nodes to grid", description: "When enabled, new nodes will be aligned to the grid.", type: "boolean" }, defaultTextNodeDimensions: { label: "Default text node dimensions", description: "The default dimensions of a text node.", type: "dimension", parse: (value) => { const width = Math.max(1, parseInt(value[0]) || 0); const height = Math.max(1, parseInt(value[1]) || 0); return [width, height]; } }, defaultFileNodeDimensions: { label: "Default file node dimensions", description: "The default dimensions of a file node.", type: "dimension", parse: (value) => { const width = Math.max(1, parseInt(value[0]) || 0); const height = Math.max(1, parseInt(value[1]) || 0); return [width, height]; } }, minNodeSize: { label: "Minimum node size", description: "The minimum size (either width or height) of a node.", type: "number", parse: (value) => Math.max(1, parseInt(value) || 0) }, maxNodeWidth: { label: "Maximum node width", description: "The maximum width of a node. Set to -1 for no limit.", type: "number", parse: (value) => Math.max(-1, parseInt(value) || 0) }, disableFontSizeRelativeToZoom: { label: "Disable font size relative to zoom", description: "When enabled, the font size of e.g. group node titles and edge labels will not increase when zooming out.", type: "boolean" } } }, commandsFeatureEnabled: { label: "Extended commands", description: "Add more commands to the canvas.", infoSection: "canvas-commands", children: { zoomToClonedNode: { label: "Zoom to cloned node", description: "When enabled, the canvas will zoom to the cloned node.", type: "boolean" }, cloneNodeMargin: { label: "Clone node margin", description: "The margin between the cloned node and the source node.", type: "number", parse: (value) => Math.max(0, parseInt(value) || 0) }, expandNodeStepSize: { label: "Expand node step size", description: "The step size for expanding the node.", type: "number", parse: (value) => Math.max(1, parseInt(value) || 0) } } }, canvasMetadataCompatibilityEnabled: { label: "Enable .canvas metadata cache compatibility", description: "Make .canvas files compatible with the backlinks and outgoing links feature and show the connections in the graph view.", infoSection: "full-metadata-cache-support", children: { treatFileNodeEdgesAsLinks: { label: "Treat edges between file nodes as links", description: "When enabled, edges between file nodes will be treated as links. This means that if file node A.md has an edge to file node B.md in the canvas, file A.md will have a link to file B.md in the outgoing links section and show a connection in the graph view.", type: "boolean" }, enableSingleNodeLinks: { label: "Enable support for linking to a node using a [[wikilink]]", description: "When enabled, you can link and embed a node using [[canvas-file#node-id]].", type: "boolean" } } }, nativeFileSearchEnabled: { label: "Native-like file search", description: "When enabled, the file search will be done using the native Obsidian file search.", infoSection: "native-like-file-search", children: {} }, autoFileNodeEdgesFeatureEnabled: { label: "Auto file node edges", description: "Automatically create edges between file nodes based their frontmatter links.", infoSection: "auto-file-node-edges", children: { autoFileNodeEdgesFrontmatterKey: { label: "Frontmatter key name", description: "The frontmatter key to fetch the outgoing edges from. (Keep the default to ensure best compatibility.)", type: "text", parse: (value) => value.trim() || "canvas-edges" } } }, portalsFeatureEnabled: { label: "Portals", description: "Create portals to other canvases.", infoSection: "portals", children: { showEdgesIntoDisabledPortals: { label: "Show edges into disabled portals", description: "When enabled, edges into disabled portals will be shown.", type: "boolean" } } }, collapsibleGroupsFeatureEnabled: { label: "Collapsible groups", description: "Group nodes can be collapsed and expanded to keep the canvas organized.", infoSection: "collapsible-groups", children: { collapsedGroupPreviewOnDrag: { label: "Collapsed group preview on drag", description: "When enabled, a group that is collapsed show its border while dragging a node.", type: "boolean" } } }, combineCustomStylesInDropdown: { label: "Combine custom styles", description: "Combine all style attributes of Advanced Canvas in a single dropdown.", children: {} }, nodeStylingFeatureEnabled: { label: "Node styling", description: "Style your nodes with different shapes and borders.", infoSection: "node-styles", children: { customNodeStyleAttributes: { label: "Custom node style settings", description: "Add custom style settings for nodes. (Go to GitHub for more information)", type: "button", onClick: () => window.open("https://github.com/Developer-Mike/obsidian-advanced-canvas/blob/main/README.md#custom-styles") }, defaultTextNodeStyleAttributes: { label: "Default text node style attributes", type: "styles", getParameters(settingsManager) { return [...BUILTIN_NODE_STYLE_ATTRIBUTES, ...settingsManager.getSetting("customNodeStyleAttributes")].filter((setting) => { var _a; return setting.nodeTypes === void 0 || ((_a = setting.nodeTypes) == null ? void 0 : _a.includes("text")); }); } } } }, edgesStylingFeatureEnabled: { label: "Edges styling", description: "Style your edges with different path styles.", infoSection: "edge-styles", children: { customEdgeStyleAttributes: { label: "Custom edge style settings", description: "Add custom style settings for edges. (Go to GitHub for more information)", type: "button", onClick: () => window.open("https://github.com/Developer-Mike/obsidian-advanced-canvas/blob/main/README.md#custom-styles") }, defaultEdgeLineDirection: { label: "Default edge line direction", description: "The default line direction of an edge.", type: "dropdown", options: { "nondirectional": "Nondirectional", "unidirectional": "Unidirectional", "bidirectional": "Bidirectional" } }, defaultEdgeStyleAttributes: { label: "Default edge style attributes", type: "styles", getParameters(settingsManager) { return [...BUILTIN_EDGE_STYLE_ATTRIBUTES, ...settingsManager.getSetting("customEdgeStyleAttributes")]; } }, edgeStyleUpdateWhileDragging: { label: "Update edge style while dragging (Can be very slow)", description: "When enabled, the edge style will be updated while dragging an edge.", type: "boolean" }, edgeStyleSquarePathRounded: { label: "Square path rounded", description: "When enabled, the square path's corners will be rounded.", type: "boolean" }, edgeStylePathfinderAllowDiagonal: { label: "A* allow diagonal", description: "When enabled, the A* path style will allow diagonal paths.", type: "boolean" }, edgeStylePathfinderPathRounded: { label: "A* rounded path", description: "When enabled, the A* path style will be rounded.", type: "boolean" } } }, floatingEdgeFeatureEnabled: { label: "Floating edges (auto edge side)", description: "Floating edges are automatically placed on the most suitable side of the node.", infoSection: "floating-edges-automatic-edge-side", children: { allowFloatingEdgeCreation: { label: "Allow floating edges creation", description: "Allow floating edges creation by dragging the edge over the target node without placing it over a specific side connection point. (If disabled, floating edges can only be created and used by other Advanced Canvas features.)", type: "boolean" }, newEdgeFromSideFloating: { label: "New edge from side floating", description: 'When enabled, the "from" side of the edge will always be floating.', type: "boolean" } } }, flipEdgeFeatureEnabled: { label: "Flip edges", description: "Flip the direction of edges using the popup menu.", infoSection: "flip-edge", children: {} }, presentationFeatureEnabled: { label: "Presentations", description: "Create a presentation from your canvas.", infoSection: "presentation-mode", children: { showSetStartNodeInPopup: { label: 'Show "Set Start Node" in node popup', description: "If turned off, you can still set the start node using the corresponding command.", type: "boolean" }, defaultSlideDimensions: { label: "Default slide dimensions", description: "The default dimensions of a slide.", type: "dimension", parse: (value) => { const width = Math.max(1, parseInt(value[0]) || 0); const height = Math.max(1, parseInt(value[1]) || 0); return [width, height]; } }, wrapInSlidePadding: { label: "Wrap in slide padding", description: "The padding of the slide when wrapping the canvas in a slide.", type: "number", parse: (value) => Math.max(0, parseInt(value) || 0) }, resetViewportOnPresentationEnd: { label: "Reset viewport on presentation end", description: "When enabled, the viewport will be reset to the original position after the presentation ends.", type: "boolean" }, useArrowKeysToChangeSlides: { label: "Use arrow keys to change slides", description: "When enabled, you can use the arrow keys to change slides in presentation mode.", type: "boolean" }, usePgUpPgDownKeysToChangeSlides: { label: "Use PgUp/PgDown keys to change slides", description: "When enabled, you can use the PgUp/PgDown keys to change slides in presentation mode (Makes the presentation mode compatible with most presentation remotes).", type: "boolean" }, zoomToSlideWithoutPadding: { label: "Zoom to slide without padding", description: "When enabled, the canvas will zoom to the slide without padding.", type: "boolean" }, useUnclampedZoomWhilePresenting: { label: "Use unclamped zoom while presenting", description: "When enabled, the zoom will not be clamped while presenting.", type: "boolean" }, slideTransitionAnimationDuration: { label: "Slide transition animation duration", description: "The duration of the slide transition animation in seconds. Set to 0 to disable the animation.", type: "number", parse: (value) => Math.max(0, parseFloat(value) || 0) }, slideTransitionAnimationIntensity: { label: "Slide transition animation intensity", description: "The intensity of the slide transition animation. The higher the value, the more the canvas will zoom out before zooming in on the next slide.", type: "number", parse: (value) => Math.max(0, parseFloat(value) || 0) } } }, zOrderingControlFeatureEnabled: { label: "Z ordering controls", description: "Change the persistent z-index of nodes using the context menu.", children: { zOrderingControlShowOneLayerShiftOptions: { label: "Show one layer shift options", description: "When enabled, you can move nodes one layer forward or backward.", type: "boolean" } } }, aspectRatioControlFeatureEnabled: { label: "Aspect ratio control", description: "Change the aspect ratio of nodes using the context menu.", children: {} }, variableBreakpointFeatureEnabled: { label: "Variable breakpoint", description: `Change the zoom breakpoint (the zoom level at which the nodes won't render their content anymore) on a per-node basis using the ${VARIABLE_BREAKPOINT_CSS_VAR} CSS variable.`, infoSection: "variable-breakpoints", children: {} }, autoResizeNodeFeatureEnabled: { label: "Auto resize node", description: "Automatically resize the height of a node to fit the content.", infoSection: "auto-node-resizing", children: { autoResizeNodeEnabledByDefault: { label: "Enable auto resize by default", description: "When enabled, the auto resize feature will be enabled by default for all nodes.", type: "boolean" }, autoResizeNodeMaxHeight: { label: "Max height", description: "The maximum height of the node when auto resizing (-1 for unlimited).", type: "number", parse: (value) => { var _a; return Math.max(-1, (_a = parseInt(value)) != null ? _a : -1); } }, autoResizeNodeSnapToGrid: { label: "Snap to grid", description: "When enabled, the height of the node will snap to the grid.", type: "boolean" } } }, canvasEncapsulationEnabled: { label: "Canvas encapsulation", description: "Encapsulate a selection of nodes and edges into a new canvas using the context menu.", infoSection: "encapsulate-selection", children: {} }, betterReadonlyEnabled: { label: "Better readonly", description: "Improve the readonly mode.", infoSection: "better-readonly", children: { hideBackgroundGridWhenInReadonly: { label: "Hide background grid when in readonly", description: "When enabled, the background grid will be hidden when in readonly mode.", type: "boolean" } } }, edgeHighlightEnabled: { label: "Edge highlight", description: "Highlight outgoing (and optionally incoming) edges of a selected node.", infoSection: "edge-highlight", children: { highlightIncomingEdges: { label: "Highlight incoming edges", description: "When enabled, incoming edges will also be highlighted.", type: "boolean" } } }, focusModeFeatureEnabled: { label: "Focus mode", description: "Focus on a single node and blur all other nodes.", infoSection: "focus-mode", children: {} } }; var SettingsManager = class { constructor(plugin) { this.plugin = plugin; } async loadSettings() { this.settings = Object.assign({}, DEFAULT_SETTINGS_VALUES, await this.plugin.loadData()); this.plugin.app.workspace.trigger("advanced-canvas:settings-changed"); } async saveSettings() { await this.plugin.saveData(this.settings); } getSetting(key) { return this.settings[key]; } async setSetting(data) { this.settings = Object.assign(this.settings, data); await this.saveSettings(); this.plugin.app.workspace.trigger("advanced-canvas:settings-changed"); } addSettingsTab() { this.settingsTab = new AdvancedCanvasPluginSettingTab(this.plugin, this); this.plugin.addSettingTab(this.settingsTab); } }; var AdvancedCanvasPluginSettingTab = class extends import_obsidian2.PluginSettingTab { constructor(plugin, settingsManager) { super(plugin.app, plugin); this.settingsManager = settingsManager; } display() { let { containerEl } = this; containerEl.empty(); for (const [headingId, heading] of Object.entries(SETTINGS)) { this.createFeatureHeading( containerEl, heading.label, heading.description, heading.infoSection, heading.disableToggle ? null : headingId ); const settingsHeaderChildrenContainerEl = document.createElement("div"); settingsHeaderChildrenContainerEl.classList.add("settings-header-children"); settingsHeaderChildrenContainerEl.appendChild(document.createElement("span")); containerEl.appendChild(settingsHeaderChildrenContainerEl); for (let [settingId, setting] of Object.entries(heading.children)) { if (!(settingId in DEFAULT_SETTINGS_VALUES)) continue; switch (setting.type) { case "text": this.createTextSetting(settingsHeaderChildrenContainerEl, settingId, setting); break; case "number": this.createNumberSetting(settingsHeaderChildrenContainerEl, settingId, setting); break; case "dimension": this.createDimensionSetting(settingsHeaderChildrenContainerEl, settingId, setting); break; case "boolean": this.createBooleanSetting(settingsHeaderChildrenContainerEl, settingId, setting); break; case "dropdown": this.createDropdownSetting(settingsHeaderChildrenContainerEl, settingId, setting); break; case "button": this.createButtonSetting(settingsHeaderChildrenContainerEl, settingId, setting); break; case "styles": this.createStylesSetting(settingsHeaderChildrenContainerEl, settingId, setting); break; } } } this.createKoFiBadge(containerEl); const currentTimestamp = (/* @__PURE__ */ new Date()).getTime(); if (currentTimestamp - this.settingsManager.getSetting("downloadTimestamp") > ASK_FOR_DONATION_DELAY && !this.settingsManager.getSetting("askedForDonation")) { this.createKoFiOverlay(containerEl); } } createFeatureHeading(containerEl, label, description, infoSection, settingsKey) { const setting = new import_obsidian2.Setting(containerEl).setHeading().setClass("ac-settings-heading").setName(label).setDesc(description); if (infoSection !== void 0) { setting.addExtraButton( (button) => button.setTooltip("Open github documentation").setIcon("info").onClick(async () => { window.open(`${README_URL}#${infoSection}`); }) ); } if (settingsKey !== null) { setting.addToggle( (toggle) => toggle.setTooltip("Requires a reload to take effect.").setValue(this.settingsManager.getSetting(settingsKey)).onChange(async (value) => { await this.settingsManager.setSetting({ [settingsKey]: value }); new import_obsidian2.Notice("Reload obsidian to apply the changes."); }) ); } return setting; } createTextSetting(containerEl, settingId, setting) { new import_obsidian2.Setting(containerEl).setName(setting.label).setDesc(setting.description).addText( (text) => text.setValue(this.settingsManager.getSetting(settingId)).onChange(async (value) => { await this.settingsManager.setSetting({ [settingId]: setting.parse ? setting.parse(value) : value }); }) ); } createNumberSetting(containerEl, settingId, setting) { new import_obsidian2.Setting(containerEl).setName(setting.label).setDesc(setting.description).addText( (text) => text.setValue(this.settingsManager.getSetting(settingId).toString()).onChange(async (value) => { await this.settingsManager.setSetting({ [settingId]: setting.parse(value) }); }) ); } createDimensionSetting(containerEl, settingId, setting) { let text1; let text2; new import_obsidian2.Setting(containerEl).setName(setting.label).setDesc(setting.description).addText((text) => { text1 = text.setValue(this.settingsManager.getSetting(settingId)[0].toString()).onChange(async (value) => await this.settingsManager.setSetting({ [settingId]: setting.parse([value, text2.getValue()]) })); }).addText((text) => { text2 = text.setValue(this.settingsManager.getSetting(settingId)[1].toString()).onChange(async (value) => await this.settingsManager.setSetting({ [settingId]: setting.parse([text1.getValue(), value]) })); }); } createBooleanSetting(containerEl, settingId, setting) { new import_obsidian2.Setting(containerEl).setName(setting.label).setDesc(setting.description).addToggle( (toggle) => toggle.setValue(this.settingsManager.getSetting(settingId)).onChange(async (value) => { await this.settingsManager.setSetting({ [settingId]: value }); }) ); } createDropdownSetting(containerEl, settingId, setting) { new import_obsidian2.Setting(containerEl).setName(setting.label).setDesc(setting.description).addDropdown( (dropdown) => dropdown.addOptions(setting.options).setValue(this.settingsManager.getSetting(settingId)).onChange(async (value) => { await this.settingsManager.setSetting({ [settingId]: value }); }) ); } createButtonSetting(containerEl, settingId, setting) { new import_obsidian2.Setting(containerEl).setName(setting.label).setDesc(setting.description).addButton( (button) => button.setButtonText("Open").onClick(() => setting.onClick()) ); } createStylesSetting(containerEl, settingId, setting) { const nestedContainerEl = document.createElement("details"); nestedContainerEl.classList.add("setting-item"); containerEl.appendChild(nestedContainerEl); const summaryEl = document.createElement("summary"); summaryEl.textContent = setting.label; nestedContainerEl.appendChild(summaryEl); for (const styleAttribute of setting.getParameters(this.settingsManager)) { new import_obsidian2.Setting(nestedContainerEl).setName(styleAttribute.label).addDropdown( (dropdown) => { var _a; return dropdown.addOptions(Object.fromEntries(styleAttribute.options.map((option) => [option.value, option.value === null ? `${option.label} (default)` : option.label]))).setValue((_a = this.settingsManager.getSetting(settingId)[styleAttribute.key]) != null ? _a : "null").onChange(async (value) => { const newValue = this.settingsManager.getSetting(settingId); if (value === "null") delete newValue[styleAttribute.key]; else newValue[styleAttribute.key] = value; await this.settingsManager.setSetting({ [settingId]: newValue }); }); } ); } } async createKoFiOverlay(containerEl) { var _a, _b, _c; const sidebarWidth = (_c = (_b = (_a = containerEl.parentElement) == null ? void 0 : _a.previousElementSibling) == null ? void 0 : _b.clientWidth) != null ? _c : 0; const overlay = document.createElement("div"); overlay.classList.add("kofi-overlay"); overlay.style.left = `${sidebarWidth}px`; const dismiss = () => { overlay.remove(); this.settingsManager.setSetting({ askedForDonation: true }); }; const title = document.createElement("h1"); title.textContent = "Enjoying the plugin?"; overlay.appendChild(title); const description = document.createElement("p"); description.innerHTML = `Currently, Advanced Canvas has received ~${RECEIVED_DONATIONS}$ in donations with a total of ~${SPENT_HOURS} hours spent on development.`; overlay.appendChild(description); const hourlyRate = document.createElement("progress"); hourlyRate.value = RECEIVED_DONATIONS / SPENT_HOURS; hourlyRate.max = HOURLY_RATE_GOAL; overlay.appendChild(hourlyRate); const targetDescription = document.createElement("p"); targetDescription.innerHTML = `Please help me develop this plugin further by reaching the goal of ${HOURLY_RATE_GOAL}$/hour.`; overlay.appendChild(targetDescription); const koFiButton = document.createElement("a"); koFiButton.classList.add("kofi-button"); koFiButton.href = KOFI_PAGE_URL; koFiButton.target = "_blank"; koFiButton.addEventListener("click", dismiss); const koFiImage = document.createElement("img"); koFiImage.src = KOFI_BADGE_URI; koFiButton.appendChild(koFiImage); overlay.appendChild(koFiButton); const noButton = document.createElement("button"); noButton.classList.add("no-button"); noButton.textContent = "I don't want to help"; noButton.addEventListener("click", dismiss); overlay.appendChild(noButton); containerEl.appendChild(overlay); } createKoFiBadge(containerEl) { const koFiButton = document.createElement("a"); koFiButton.classList.add("kofi-button"); koFiButton.classList.add("sticky"); koFiButton.href = KOFI_PAGE_URL; koFiButton.target = "_blank"; const koFiImage = document.createElement("img"); koFiImage.src = KOFI_BADGE_URI; koFiButton.appendChild(koFiImage); containerEl.appendChild(koFiButton); } }; // src/managers/windows-manager.ts var WindowsManager = class { constructor(plugin) { this.windows = [window]; this.plugin = plugin; this.plugin.registerEvent(this.plugin.app.workspace.on( "window-open", (_win, window2) => this.windows.push(window2) )); this.plugin.registerEvent(this.plugin.app.workspace.on( "window-close", (_win, window2) => this.windows = this.windows.filter((w) => w !== window2) )); } }; // src/patchers/canvas-patcher.ts var import_view = require("@codemirror/view"); var import_json_stable_stringify = __toESM(require_json_stable_stringify()); // node_modules/monkey-around/mjs/index.js function around(obj, factories) { const removers = Object.keys(factories).map((key) => around1(obj, key, factories[key])); return removers.length === 1 ? removers[0] : function() { removers.forEach((r) => r()); }; } function around1(obj, method, createWrapper) { const original = obj[method], hadOwn = obj.hasOwnProperty(method); let current = createWrapper(original); if (original) Object.setPrototypeOf(current, original); Object.setPrototypeOf(wrapper, current); obj[method] = wrapper; return remove; function wrapper(...args) { if (current === original && obj[method] === wrapper) remove(); return current.apply(this, args); } function remove() { if (obj[method] === wrapper) { if (hadOwn) obj[method] = original; else delete obj[method]; } if (current === original) return; current = original; Object.setPrototypeOf(wrapper, original || Function); } } // src/patchers/canvas-patcher.ts var import_obsidian3 = require("obsidian"); // node_modules/tiny-jsonc/dist/index.js var stringOrCommentRe = /("(?:\\?[^])*?")|(\/\/.*)|(\/\*[^]*?\*\/)/g; var stringOrTrailingCommaRe = /("(?:\\?[^])*?")|(,\s*)(?=]|})/g; var JSONC = { parse: (text) => { text = String(text); try { return JSON.parse(text); } catch (e) { return JSON.parse(text.replace(stringOrCommentRe, "$1").replace(stringOrTrailingCommaRe, "$1")); } } }; var dist_default = JSONC; // src/patchers/patcher.ts var Patcher = class _Patcher { constructor(plugin) { this.plugin = plugin; this.patch(); } static async waitForViewRequest(plugin, viewType, patch) { return new Promise((resolve) => { const uninstaller = around(plugin.app.viewRegistry.viewByType, { [viewType]: (next) => function(...args) { const view = next.call(this, ...args); patch(view); const patchedView = next.call(this, ...args); uninstaller(); resolve(patchedView); return patchedView; } }); }); } static OverrideExisting(fn) { return Object.assign(fn, { __overrideExisting: true }); } static patchThisAndPrototype(plugin, object, patches) { _Patcher.patch(plugin, object, patches); return _Patcher.patchPrototype(plugin, object, patches); } static patchPrototype(plugin, target, patches) { return _Patcher.patch(plugin, target, patches, true); } static patch(plugin, object, patches, prototype = false) { if (!object) return null; const target = prototype ? object.constructor.prototype : object; for (const key of Object.keys(patches)) { const patch = patches[key]; if (patch == null ? void 0 : patch.__overrideExisting) { if (typeof target[key] !== "function") throw new Error(`Method ${String(key)} does not exist on target`); } } const uninstaller = around(target, patches); plugin.register(uninstaller); return object; } static tryPatchWorkspacePrototype(plugin, getTarget, patches) { return new Promise((resolve) => { const result = _Patcher.patchPrototype(plugin, getTarget(), patches); if (result) { resolve(result); return; } const listener = plugin.app.workspace.on("layout-change", () => { const result2 = _Patcher.patchPrototype(plugin, getTarget(), patches); if (result2) { plugin.app.workspace.offref(listener); resolve(result2); } }); plugin.registerEvent(listener); }); } }; // src/utils/bbox-helper.ts var BBoxHelper = class { static combineBBoxes(bboxes) { let minX = Infinity; let minY = Infinity; let maxX = -Infinity; let maxY = -Infinity; for (let bbox of bboxes) { minX = Math.min(minX, bbox.minX); minY = Math.min(minY, bbox.minY); maxX = Math.max(maxX, bbox.maxX); maxY = Math.max(maxY, bbox.maxY); } return { minX, minY, maxX, maxY }; } static scaleBBox(bbox, scale) { let diffX = (scale - 1) * (bbox.maxX - bbox.minX); let diffY = (scale - 1) * (bbox.maxY - bbox.minY); return { minX: bbox.minX - diffX / 2, maxX: bbox.maxX + diffX / 2, minY: bbox.minY - diffY / 2, maxY: bbox.maxY + diffY / 2 }; } static isColliding(bbox1, bbox2) { return bbox1.minX <= bbox2.maxX && bbox1.maxX >= bbox2.minX && bbox1.minY <= bbox2.maxY && bbox1.maxY >= bbox2.minY; } static insideBBox(position, bbox, canTouchEdge) { if ("x" in position) { const x = position.x, y = position.y; return canTouchEdge ? x >= bbox.minX && x <= bbox.maxX && y >= bbox.minY && y <= bbox.maxY : x > bbox.minX && x < bbox.maxX && y > bbox.minY && y < bbox.maxY; } return canTouchEdge ? position.minX >= bbox.minX && position.maxX <= bbox.maxX && position.minY >= bbox.minY && position.maxY <= bbox.maxY : position.minX > bbox.minX && position.maxX < bbox.maxX && position.minY > bbox.minY && position.maxY < bbox.maxY; } static enlargeBBox(bbox, padding) { return { minX: bbox.minX - padding, minY: bbox.minY - padding, maxX: bbox.maxX + padding, maxY: bbox.maxY + padding }; } static moveInDirection(position, side, distance) { switch (side) { case "top": return { x: position.x, y: position.y - distance }; case "right": return { x: position.x + distance, y: position.y }; case "bottom": return { x: position.x, y: position.y + distance }; case "left": return { x: position.x - distance, y: position.y }; } } static getCenterOfBBoxSide(bbox, side) { switch (side) { case "top": return { x: (bbox.minX + bbox.maxX) / 2, y: bbox.minY }; case "right": return { x: bbox.maxX, y: (bbox.minY + bbox.maxY) / 2 }; case "bottom": return { x: (bbox.minX + bbox.maxX) / 2, y: bbox.maxY }; case "left": return { x: bbox.minX, y: (bbox.minY + bbox.maxY) / 2 }; } } static getSideVector(side) { switch (side) { case "top": return { x: 0, y: 1 }; case "right": return { x: 1, y: 0 }; case "bottom": return { x: 0, y: -1 }; case "left": return { x: -1, y: 0 }; default: return { x: 0, y: 0 }; } } static getOppositeSide(side) { switch (side) { case "top": return "bottom"; case "right": return "left"; case "bottom": return "top"; case "left": return "right"; } } static isHorizontal(side) { return side === "left" || side === "right"; } static direction(side) { return side === "right" || side === "bottom" ? 1 : -1; } }; // src/utils/migration-helper.ts var CURRENT_SPEC_VERSION = "1.0-1.0"; var _MigrationHelper = class _MigrationHelper { static needsMigration(canvas) { var _a; return ((_a = canvas.metadata) == null ? void 0 : _a.version) !== CURRENT_SPEC_VERSION; } static migrate(canvas) { var _a, _b; let version = (_b = (_a = canvas.metadata) == null ? void 0 : _a.version) != null ? _b : "undefined"; if (version === CURRENT_SPEC_VERSION) return canvas; while (version !== CURRENT_SPEC_VERSION) { const migrationFunction = _MigrationHelper.MIGRATIONS[version]; if (!migrationFunction) { console.error(`No migration function found for version ${version}. Critical error!`); break; } const { version: newVersion, canvas: migratedCanvas } = migrationFunction(canvas); version = newVersion; canvas = migratedCanvas; if (!canvas.metadata) canvas.metadata = { version, frontmatter: {} }; else canvas.metadata.version = version; } return canvas; } }; _MigrationHelper.MIGRATIONS = { undefined: (canvas) => { var _a; const TARGET_SPEC_VERSION = "1.0-1.0"; let startNode; const globalInterdimensionalEdges = {}; for (const node of canvas.nodes) { node.dynamicHeight = node.autoResizeHeight; delete node.autoResizeHeight; node.ratio = node.sideRatio; delete node.sideRatio; node.collapsed = node.isCollapsed; delete node.isCollapsed; if (node.portalToFile) { node.portal = true; delete node.portalToFile; } if (node.isStartNode) { startNode = node.id; delete node.isStartNode; } if (node.edgesToNodeFromPortal) { const edgesToNodeFromPortal = node.edgesToNodeFromPortal; for (const [portalId, edges] of Object.entries(edgesToNodeFromPortal)) { if (!(portalId in globalInterdimensionalEdges)) globalInterdimensionalEdges[portalId] = []; for (const edge of edges) { if (edge.fromNode !== node.id) edge.fromNode = `${portalId}-${edge.fromNode}`; if (edge.toNode !== node.id) edge.toNode = `${portalId}-${edge.toNode}`; } globalInterdimensionalEdges[portalId].push(...edges); } delete node.edgesToNodeFromPortal; } } for (const node of canvas.nodes) { if (!(node.id in globalInterdimensionalEdges)) continue; node.interdimensionalEdges = globalInterdimensionalEdges[node.id]; } (_a = canvas.metadata) != null ? _a : canvas.metadata = { version: TARGET_SPEC_VERSION, frontmatter: {}, startNode }; return { version: TARGET_SPEC_VERSION, canvas }; } }; var MigrationHelper = _MigrationHelper; // src/patchers/canvas-patcher.ts var CanvasPatcher = class extends Patcher { async patch() { const loadedCanvasViewLeafs = this.plugin.app.workspace.getLeavesOfType("canvas").filter((leaf) => !(0, import_obsidian3.requireApiVersion)("1.7.2") || !leaf.isDeferred); if (loadedCanvasViewLeafs.length > 0) { console.debug(`Patching and reloading loaded canvas views (Count: ${loadedCanvasViewLeafs.length})`); this.patchCanvas(loadedCanvasViewLeafs.first().view); for (const leaf of loadedCanvasViewLeafs) leaf.rebuildView(); } else { await Patcher.waitForViewRequest(this.plugin, "canvas", (view) => this.patchCanvas(view)); console.debug(`Patched canvas view on first request`); } } patchCanvas(view) { const that = this; Patcher.patchPrototype(this.plugin, view, { setEphemeralState: Patcher.OverrideExisting((next) => function(state) { var _a, _b; if (state == null ? void 0 : state.subpath) { const nodeId = state.subpath.replace(/^#/, ""); const node = this.canvas.nodes.get(nodeId); if (node) { this.canvas.selectOnly(node); this.canvas.zoomToSelection(); return; } } if (((_b = (_a = state.match) == null ? void 0 : _a.matches) == null ? void 0 : _b[0]) && !(state == null ? void 0 : state.nodeId)) { const match = state.match.matches[0]; const elementType = match[0] === 0 ? "nodes" : "edges"; const elementIndex = match[1]; const element = elementType === "nodes" ? Array.from(this.canvas.nodes.values())[elementIndex] : Array.from(this.canvas.edges.values())[elementIndex]; if (element) { this.canvas.selectOnly(element); this.canvas.zoomToSelection(); return; } } return next.call(this, state); }), setViewData: Patcher.OverrideExisting((next) => function(json, ...args) { json = json !== "" ? json : '{"nodes": [], "edges": []}'; try { const canvasData = dist_default.parse(json); if (MigrationHelper.needsMigration(canvasData)) { if (this.file) that.plugin.createFileSnapshot(this.file.path, json); json = JSON.stringify(MigrationHelper.migrate(canvasData)); } } catch (e) { console.error("Failed to migrate canvas data:", e); } let result; try { result = next.call(this, json, ...args); } catch (e) { console.error("Invalid JSON, repairing through Advanced Canvas:", e); if (this.file) that.plugin.createFileSnapshot(this.file.path, json); json = JSON.stringify(dist_default.parse(json), null, 2); result = next.call(this, json, ...args); } that.plugin.app.workspace.trigger("advanced-canvas:canvas-changed", this.canvas); return result; }), getViewData: Patcher.OverrideExisting((next) => function(...args) { const canvasData = this.canvas.getData(); try { const stringified = (0, import_json_stable_stringify.default)(canvasData, { space: 2 }); if (stringified === void 0) throw new Error("Failed to stringify canvas data using json-stable-stringify"); return stringified; } catch (e) { console.error("Failed to stringify canvas data using json-stable-stringify:", e); try { return JSON.stringify(canvasData, null, 2); } catch (e2) { console.error("Failed to stringify canvas data using JSON.stringify:", e2); return next.call(this, ...args); } } }), close: Patcher.OverrideExisting((next) => function(...args) { that.plugin.app.workspace.trigger("advanced-canvas:canvas-view-unloaded:before", this); return next.call(this, ...args); }) }); Patcher.patchPrototype(this.plugin, view.canvas, { markViewportChanged: Patcher.OverrideExisting((next) => function(...args) { that.plugin.app.workspace.trigger("advanced-canvas:viewport-changed:before", this); const result = next.call(this, ...args); that.plugin.app.workspace.trigger("advanced-canvas:viewport-changed:after", this); return result; }), markMoved: Patcher.OverrideExisting((next) => function(node) { const result = next.call(this, node); if (!this.viewportChanged) { if (node.prevX !== node.x || node.prevY !== node.y) that.plugin.app.workspace.trigger("advanced-canvas:node-moved", this, node, !this.isDragging); if (node.prevWidth !== node.width || node.prevHeight !== node.height) that.plugin.app.workspace.trigger("advanced-canvas:node-resized", this, node); } node.prevX = node.x; node.prevY = node.y; node.prevWidth = node.width; node.prevHeight = node.height; return result; }), onDoubleClick: Patcher.OverrideExisting((next) => function(event) { const preventDefault = { value: false }; that.plugin.app.workspace.trigger("advanced-canvas:double-click", this, event, preventDefault); if (!preventDefault.value) next.call(this, event); }), setDragging: Patcher.OverrideExisting((next) => function(dragging) { const result = next.call(this, dragging); that.plugin.app.workspace.trigger("advanced-canvas:dragging-state-changed", this, dragging); return result; }), getContainingNodes: Patcher.OverrideExisting((next) => function(bbox) { const result = next.call(this, bbox); that.plugin.app.workspace.trigger("advanced-canvas:containing-nodes-requested", this, bbox, result); return result; }), updateSelection: Patcher.OverrideExisting((next) => function(update) { const oldSelection = new Set(this.selection); const result = next.call(this, update); that.plugin.app.workspace.trigger("advanced-canvas:selection-changed", this, oldSelection, (update2) => next.call(this, update2)); return result; }), createTextNode: Patcher.OverrideExisting((next) => function(...args) { const node = next.call(this, ...args); that.plugin.app.workspace.trigger("advanced-canvas:node-created", this, node); return node; }), createFileNode: Patcher.OverrideExisting((next) => function(...args) { const node = next.call(this, ...args); that.plugin.app.workspace.trigger("advanced-canvas:node-created", this, node); return node; }), createFileNodes: Patcher.OverrideExisting((next) => function(...args) { const nodes = next.call(this, ...args); nodes.forEach((node) => that.plugin.app.workspace.trigger("advanced-canvas:node-created", this, node)); return nodes; }), createGroupNode: Patcher.OverrideExisting((next) => function(...args) { const node = next.call(this, ...args); that.plugin.app.workspace.trigger("advanced-canvas:node-created", this, node); return node; }), createLinkNode: Patcher.OverrideExisting((next) => function(...args) { const node = next.call(this, ...args); that.plugin.app.workspace.trigger("advanced-canvas:node-created", this, node); return node; }), addNode: Patcher.OverrideExisting((next) => function(node) { that.patchNode(node); return next.call(this, node); }), addEdge: Patcher.OverrideExisting((next) => function(edge) { that.patchEdge(edge); if (!this.viewportChanged) that.plugin.app.workspace.trigger("advanced-canvas:edge-created", this, edge); return next.call(this, edge); }), removeNode: Patcher.OverrideExisting((next) => function(node) { const result = next.call(this, node); if (!this.isClearing) that.plugin.app.workspace.trigger("advanced-canvas:node-removed", this, node); return result; }), removeEdge: Patcher.OverrideExisting((next) => function(edge) { const result = next.call(this, edge); if (!this.isClearing) that.plugin.app.workspace.trigger("advanced-canvas:edge-removed", this, edge); return result; }), handleCopy: Patcher.OverrideExisting((next) => function(...args) { this.isCopying = true; const result = next.call(this, ...args); this.isCopying = false; return result; }), handlePaste: Patcher.OverrideExisting((next) => function(...args) { this.isPasting = true; const result = next.call(this, ...args); this.isPasting = false; return result; }), getSelectionData: Patcher.OverrideExisting((next) => function(...args) { const result = next.call(this, ...args); if (this.isCopying) that.plugin.app.workspace.trigger("advanced-canvas:copy", this, result); return result; }), zoomToBbox: Patcher.OverrideExisting((next) => function(bbox) { that.plugin.app.workspace.trigger("advanced-canvas:zoom-to-bbox:before", this, bbox); const result = next.call(this, bbox); that.plugin.app.workspace.trigger("advanced-canvas:zoom-to-bbox:after", this, bbox); return result; }), // Custom zoomToRealBbox: (_next) => function(bbox) { if (this.canvasRect.width === 0 || this.canvasRect.height === 0) return; that.plugin.app.workspace.trigger("advanced-canvas:zoom-to-bbox:before", this, bbox); const widthZoom = this.canvasRect.width / (bbox.maxX - bbox.minX); const heightZoom = this.canvasRect.height / (bbox.maxY - bbox.minY); const zoom = this.screenshotting ? Math.min(widthZoom, heightZoom) : Math.clamp(Math.min(widthZoom, heightZoom), -4, 1); this.tZoom = Math.log2(zoom); this.zoomCenter = null; this.tx = (bbox.minX + bbox.maxX) / 2; this.ty = (bbox.minY + bbox.maxY) / 2; this.markViewportChanged(); that.plugin.app.workspace.trigger("advanced-canvas:zoom-to-bbox:after", this, bbox); }, setReadonly: Patcher.OverrideExisting((next) => function(readonly) { const result = next.call(this, readonly); that.plugin.app.workspace.trigger("advanced-canvas:readonly-changed", this, readonly); return result; }), undo: Patcher.OverrideExisting((next) => function(...args) { const result = next.call(this, ...args); this.importData(this.getData(), true); that.plugin.app.workspace.trigger("advanced-canvas:undo", this); return result; }), redo: Patcher.OverrideExisting((next) => function(...args) { const result = next.call(this, ...args); this.importData(this.getData(), true); that.plugin.app.workspace.trigger("advanced-canvas:redo", this); return result; }), clear: Patcher.OverrideExisting((next) => function(...args) { this.isClearing = true; const result = next.call(this, ...args); this.isClearing = false; return result; }), /*setData: Patcher.OverrideExisting(next => function (...args: any): void { // const result = next.call(this, ...args) // return result }),*/ getData: Patcher.OverrideExisting((next) => function(...args) { const result = next.call(this, ...args); that.plugin.app.workspace.trigger("advanced-canvas:data-requested", this, result); return result; }), importData: Patcher.OverrideExisting((next) => function(data, clearCanvas, silent) { const targetFilePath = this.view.file.path; const setData = (data2) => { if (!this.view.file || this.view.file.path !== targetFilePath) return; this.importData(data2, true, true); }; if (!silent) that.plugin.app.workspace.trigger("advanced-canvas:data-loaded:before", this, data, setData); const result = next.call(this, data, clearCanvas); if (!silent) that.plugin.app.workspace.trigger("advanced-canvas:data-loaded:after", this, data, setData); return result; }), requestSave: Patcher.OverrideExisting((next) => function(...args) { that.plugin.app.workspace.trigger("advanced-canvas:canvas-saved:before", this); const result = next.call(this, ...args); that.plugin.app.workspace.trigger("advanced-canvas:canvas-saved:after", this); return result; }) }); Patcher.patchPrototype(this.plugin, view.canvas.menu, { render: Patcher.OverrideExisting((next) => function(...args) { const result = next.call(this, ...args); that.plugin.app.workspace.trigger("advanced-canvas:popup-menu-created", this.canvas); next.call(this); return result; }) }); Patcher.patchPrototype(this.plugin, view.canvas.nodeInteractionLayer, { setTarget: Patcher.OverrideExisting((next) => function(node) { const result = next.call(this, node); that.plugin.app.workspace.trigger("advanced-canvas:node-interaction", this.canvas, node); return result; }) }); this.plugin.registerEditorExtension([import_view.EditorView.updateListener.of((update) => { if (!update.docChanged) return; const editor = update.state.field(import_obsidian3.editorInfoField); const node = editor.node; if (!node) return; that.plugin.app.workspace.trigger("advanced-canvas:node-text-content-changed", node.canvas, node, update); })]); } patchNode(node) { const that = this; Patcher.patch(this.plugin, node, { setData: Patcher.OverrideExisting((next) => function(data, addHistory) { const result = next.call(this, data); if (node.initialized && !node.isDirty) { node.isDirty = true; that.plugin.app.workspace.trigger("advanced-canvas:node-changed", this.canvas, node); delete node.isDirty; } this.canvas.data = this.canvas.getData(); if (this.initialized) this.canvas.view.requestSave(); if (addHistory) this.canvas.pushHistory(this.canvas.data); return result; }), setZIndex: (_next) => function(value) { this.setData({ ...this.getData(), zIndex: value }, true); this.updateZIndex(); }, updateZIndex: Patcher.OverrideExisting((next) => function() { const persistentZIndex = this.getData().zIndex; if (persistentZIndex === void 0) return next.call(this); this.canvas.zIndexCounter = Math.max(this.canvas.zIndexCounter, persistentZIndex); this.renderZIndex(); }), renderZIndex: Patcher.OverrideExisting((next) => function() { const persistentZIndex = this.getData().zIndex; if (persistentZIndex === void 0) return next.call(this); this.zIndex = persistentZIndex; if (this.canvas.selection.size === 1 && this.canvas.selection.has(this)) this.zIndex = this.canvas.zIndexCounter + 1; this.nodeEl.style.zIndex = this.zIndex.toString(); }), setIsEditing: Patcher.OverrideExisting((next) => function(editing, ...args) { const result = next.call(this, editing, ...args); that.plugin.app.workspace.trigger("advanced-canvas:node-editing-state-changed", this.canvas, node, editing); return result; }), updateBreakpoint: Patcher.OverrideExisting((next) => function(breakpoint) { const breakpointRef = { value: breakpoint }; that.plugin.app.workspace.trigger("advanced-canvas:node-breakpoint-changed", this.canvas, node, breakpointRef); return next.call(this, breakpointRef.value); }), getBBox: Patcher.OverrideExisting((next) => function(...args) { const result = next.call(this, ...args); that.plugin.app.workspace.trigger("advanced-canvas:node-bbox-requested", this.canvas, node, result); return result; }), onConnectionPointerdown: Patcher.OverrideExisting((next) => function(e, side) { const addEdgeEventRef = that.plugin.app.workspace.on("advanced-canvas:edge-added", (_canvas, edge) => { that.plugin.app.workspace.trigger("advanced-canvas:edge-connection-dragging:before", this.canvas, edge, e, true, "to"); that.plugin.app.workspace.offref(addEdgeEventRef); document.addEventListener("pointerup", (e2) => { that.plugin.app.workspace.trigger("advanced-canvas:edge-connection-dragging:after", this.canvas, edge, e2, true, "to"); }, { once: true }); }); const result = next.call(this, e, side); return result; }), // File nodes setFile: (next) => function(...args) { const result = next.call(this, ...args); that.plugin.app.workspace.trigger("advanced-canvas:node-changed", this.canvas, this); return result; }, setFilePath: (next) => function(...args) { const result = next.call(this, ...args); that.plugin.app.workspace.trigger("advanced-canvas:node-changed", this.canvas, this); return result; } }); this.runAfterInitialized(node, () => { this.plugin.app.workspace.trigger("advanced-canvas:node-added", node.canvas, node); this.plugin.app.workspace.trigger("advanced-canvas:node-changed", node.canvas, node); }); } patchEdge(edge) { const that = this; Patcher.patch(this.plugin, edge, { setData: Patcher.OverrideExisting((next) => function(data, addHistory) { const result = next.call(this, data); if (this.initialized && !this.isDirty) { this.isDirty = true; that.plugin.app.workspace.trigger("advanced-canvas:edge-changed", this.canvas, this); delete this.isDirty; } this.canvas.data = this.canvas.getData(); if (this.initialized) this.canvas.view.requestSave(); if (addHistory) this.canvas.pushHistory(this.canvas.getData()); return result; }), render: Patcher.OverrideExisting((next) => function(...args) { const result = next.call(this, ...args); that.plugin.app.workspace.trigger("advanced-canvas:edge-changed", this.canvas, this); return result; }), getCenter: Patcher.OverrideExisting((next) => function(...args) { const result = next.call(this, ...args); that.plugin.app.workspace.trigger("advanced-canvas:edge-center-requested", this.canvas, this, result); return result; }), onConnectionPointerdown: Patcher.OverrideExisting((next) => function(e) { const cancelRef = { value: false }; that.plugin.app.workspace.trigger("advanced-canvas:edge-connection-try-dragging:before", this.canvas, this, e, cancelRef); if (cancelRef.value) return; const previousEnds = { from: this.from, to: this.to }; const result = next.call(this, e); const eventPos = this.canvas.posFromEvt(e); const fromPos = BBoxHelper.getCenterOfBBoxSide(this.from.node.getBBox(), this.from.side); const toPos = BBoxHelper.getCenterOfBBoxSide(this.to.node.getBBox(), this.to.side); const draggingSide = Math.hypot(eventPos.x - fromPos.x, eventPos.y - fromPos.y) > Math.hypot(eventPos.x - toPos.x, eventPos.y - toPos.y) ? "to" : "from"; that.plugin.app.workspace.trigger("advanced-canvas:edge-connection-dragging:before", this.canvas, this, e, false, draggingSide, previousEnds); document.addEventListener("pointerup", (e2) => { that.plugin.app.workspace.trigger("advanced-canvas:edge-connection-dragging:after", this.canvas, this, e2, false, draggingSide, previousEnds); }, { once: true }); return result; }) }); this.runAfterInitialized(edge, () => { this.plugin.app.workspace.trigger("advanced-canvas:edge-added", edge.canvas, edge); }); } runAfterInitialized(canvasElement, onReady) { if (canvasElement.initialized) { onReady(); return; } const that = this; const uninstall = around(canvasElement, { initialize: (next) => function(...args) { const result = next.call(this, ...args); onReady(); uninstall(); return result; } }); that.plugin.register(uninstall); } }; // src/patchers/link-suggestions-patcher.ts var import_obsidian4 = require("obsidian"); var LinkSuggestionsPatcher = class extends Patcher { async patch() { var _a; if (!this.plugin.settings.getSetting("enableSingleNodeLinks")) return; const suggestManager = (_a = this.plugin.app.workspace.editorSuggest.suggests.find((s) => s.suggestManager)) == null ? void 0 : _a.suggestManager; if (!suggestManager) return console.warn("LinkSuggestionsPatcher: No suggest manager found."); const that = this; Patcher.patchThisAndPrototype(this.plugin, suggestManager, { getHeadingSuggestions: Patcher.OverrideExisting((next) => async function(context, path, subpath) { const result = await next.call(this, context, path, subpath); if (!path.endsWith(".canvas")) return result; const currentFilePath = this.getSourcePath(); const targetFile = this.app.metadataCache.getFirstLinkpathDest(path, currentFilePath); if (!targetFile) return result; if (!(targetFile instanceof import_obsidian4.TFile) || targetFile.extension !== "canvas") return result; const fileCache = this.app.metadataCache.getFileCache(targetFile); if (!fileCache) return result; const canvasNodeCaches = fileCache.nodes; if (!canvasNodeCaches) return result; for (const [nodeId, nodeCache] of Object.entries(canvasNodeCaches)) { if (nodeId === subpath) continue; const suggestion = { file: targetFile, heading: nodeId, level: 1, matches: [], path, subpath: `#${nodeId}`, score: 0, type: "heading" }; result.push(suggestion); } return result; }) }); } }; // src/advanced-canvas-embed.ts var import_obsidian5 = require("obsidian"); var AdvancedCanvasEmbed = class extends import_obsidian5.Component { constructor(context, file, subpath) { super(); this.onModifyCallback = (file) => { if (file.path !== this.file.path) return; this.loadFile(); }; this.context = context; this.file = file; this.subpath = subpath; if (!subpath) console.warn("AdvancedCanvasEmbed: No subpath provided. This embed will not work as expected."); } onload() { this.context.app.vault.on("modify", this.onModifyCallback); } onunload() { this.context.app.vault.off("modify", this.onModifyCallback); } async loadFile() { if (!this.subpath) return; const nodeId = this.subpath.replace(/^#/, ""); const canvasContent = await this.context.app.vault.cachedRead(this.file); if (!canvasContent) return console.warn("AdvancedCanvasEmbed: No canvas content found."); const canvasJson = JSON.parse(canvasContent); const canvasNode = canvasJson.nodes.find((node) => node.id === nodeId); if (!canvasNode) { this.context.containerEl.classList.add("mod-empty"); this.context.containerEl.textContent = "Node not found"; return; } let nodeContent = ""; if (canvasNode.type === "text") nodeContent = canvasNode.text; else if (canvasNode.type === "group") nodeContent = `**Group Node:** ${canvasNode.label}`; else if (canvasNode.type === "file") nodeContent = `**File Node:** ${canvasNode.file}`; this.context.containerEl.classList.add("markdown-embed"); this.context.containerEl.empty(); import_obsidian5.MarkdownRenderer.render(this.context.app, nodeContent, this.context.containerEl, this.file.path, this); } }; // src/patchers/embed-patcher.ts var EmbedPatcher = class extends Patcher { async patch() { if (!this.plugin.settings.getSetting("enableSingleNodeLinks")) return; Patcher.patch(this.plugin, this.plugin.app.embedRegistry.embedByExtension, { canvas: (next) => function(context, file, subpath) { if (subpath) return new AdvancedCanvasEmbed(context, file, subpath); return next.call(this, context, file, subpath); } }); } }; // src/patchers/metadata-cache-patcher.ts var import_obsidian6 = require("obsidian"); // src/utils/hash-helper.ts var HashHelper = class _HashHelper { static async getFileHash(plugin, file) { const bytes = await plugin.app.vault.readBinary(file); const cryptoBytes = await crypto.subtle.digest("SHA-256", new Uint8Array(bytes)); return _HashHelper.arrayBufferToHexString(cryptoBytes); } static arrayBufferToHexString(buffer) { const uint8Array = new Uint8Array(buffer); const hexArray = []; for (const byte of uint8Array) { hexArray.push((byte >>> 4).toString(16)); hexArray.push((byte & 15).toString(16)); } return hexArray.join(""); } }; // src/utils/filepath-helper.ts var FilepathHelper = class { static extension(path) { return path.includes(".") ? path.split(".").pop() : void 0; } }; // src/patchers/metadata-cache-patcher.ts var MetadataCachePatcher = class extends Patcher { async patch() { if (!this.plugin.settings.getSetting("canvasMetadataCompatibilityEnabled")) return; const that = this; Patcher.patchPrototype(this.plugin, this.plugin.app.metadataCache, { getCache: Patcher.OverrideExisting((next) => function(filepath, ...args) { if (FilepathHelper.extension(filepath) === "canvas") { if (!this.fileCache.hasOwnProperty(filepath)) return null; const hash = this.fileCache[filepath].hash; return this.metadataCache[hash] || null; } return next.call(this, filepath, ...args); }), computeFileMetadataAsync: Patcher.OverrideExisting((next) => async function(file, ...args) { var _a, _b, _c, _d, _e, _f; if (FilepathHelper.extension(file.path) !== "canvas") return next.call(this, file, ...args); const fileHash = await HashHelper.getFileHash(that.plugin, file); this.saveFileCache(file.path, { hash: fileHash, // Hash wouldn't get set in the original function mtime: file.stat.mtime, size: file.stat.size }); const content = JSON.parse(await this.vault.cachedRead(file) || "{}"); const frontmatter = (_a = content.metadata) == null ? void 0 : _a.frontmatter; const frontmatterData = {}; if (frontmatter) { frontmatterData.frontmatterPosition = { start: { line: 0, col: 0, offset: 0 }, end: { line: 0, col: 0, offset: 0 } }; frontmatterData.frontmatter = frontmatter; frontmatterData.frontmatterLinks = Object.entries(frontmatter).flatMap(([key, value]) => { const getLinks = (value2) => value2.map((v) => { if (!v.startsWith("[[") || !v.endsWith("]]")) return null; const [link, ...aliases] = v.slice(2, -2).split("|"); return { key, displayText: aliases.length > 0 ? aliases.join("|") : link, link, original: v }; }).filter((v) => v !== null); if (typeof value === "string") return getLinks([value]); else if (Array.isArray(value)) return getLinks(value); if (value) console.warn(`Unsupported frontmatter value type: ${typeof value}`); return []; }); } const fileNodesEmbeds = (_d = (_c = (_b = content.nodes) == null ? void 0 : _b.map((nodeData, index) => nodeData.type === "file" && nodeData.file ? { link: nodeData.file, original: nodeData.file, displayText: nodeData.file, position: { start: { line: 0, col: 1, offset: 0 }, // 0 for nodes end: { line: 0, col: 1, offset: index } // index of node } } : null)) == null ? void 0 : _c.filter((entry) => entry !== null)) != null ? _d : []; const textEncoder = new TextEncoder(); const nodesMetadataPromises = (_f = (_e = content.nodes) == null ? void 0 : _e.map((node) => node.type === "text" ? textEncoder.encode(node.text).buffer : null)) == null ? void 0 : _f.map((buffer) => buffer ? this.computeMetadataAsync(buffer) : Promise.resolve(null)); const nodesMetadata = await Promise.all(nodesMetadataPromises); const textNodesEmbeds = nodesMetadata.map((metadata, index) => { var _a2; return ((_a2 = metadata == null ? void 0 : metadata.embeds) != null ? _a2 : []).map((embed2) => { var _a3, _b2; return { ...embed2, position: { nodeId: (_b2 = (_a3 = content.nodes) == null ? void 0 : _a3[index]) == null ? void 0 : _b2.id, start: { line: 0, col: 1, offset: 0 }, // 0 for node end: { line: 0, col: 1, offset: index } // index of node } }; }); }).flat(); const textNodesLinks = nodesMetadata.map((metadata, index) => { var _a2; return ((_a2 = metadata == null ? void 0 : metadata.links) != null ? _a2 : []).map((link) => { var _a3, _b2; return { ...link, position: { nodeId: (_b2 = (_a3 = content.nodes) == null ? void 0 : _a3[index]) == null ? void 0 : _b2.id, start: { line: 0, col: 1, offset: 0 }, // 0 for node end: { line: 0, col: 1, offset: index } // index of node } }; }); }).flat(); this.metadataCache[fileHash] = { v: 1, ...frontmatterData, embeds: [ ...fileNodesEmbeds, ...textNodesEmbeds ], links: [ ...textNodesLinks ], nodes: { ...nodesMetadata.reduce((acc, metadata, index) => { var _a2, _b2; const nodeId = (_b2 = (_a2 = content.nodes) == null ? void 0 : _a2[index]) == null ? void 0 : _b2.id; if (nodeId && metadata) acc[nodeId] = metadata; return acc; }, {}) } }; this.trigger("changed", file, "", this.metadataCache[fileHash]); if (await Promise.race([this.workQueue.promise.then(() => false), new Promise((resolve) => setTimeout(() => resolve(true), 0))])) this.trigger("finished", file, "", this.metadataCache[fileHash], true); this.resolveLinks(file.path, content); }), resolveLinks: Patcher.OverrideExisting((next) => async function(filepath, cachedContent) { var _a, _b; if (FilepathHelper.extension(filepath) !== "canvas") return next.call(this, filepath); const file = this.vault.getAbstractFileByPath(filepath); if (!file) return; const metadataCache = this.metadataCache[(_a = this.fileCache[filepath]) == null ? void 0 : _a.hash]; if (!metadataCache) return; const metadataReferences = [...metadataCache.links || [], ...metadataCache.embeds || []]; this.resolvedLinks[filepath] = metadataReferences.reduce((acc, metadataReference) => { const resolvedLinkpath = this.getFirstLinkpathDest(metadataReference.link, filepath); if (!resolvedLinkpath) return acc; acc[resolvedLinkpath.path] = (acc[resolvedLinkpath.path] || 0) + 1; return acc; }, {}); if (that.plugin.settings.getSetting("treatFileNodeEdgesAsLinks")) { ; ((_b = cachedContent.edges) != null ? _b : []).forEach((edge) => { var _a2, _b2; const from = (_a2 = cachedContent.nodes) == null ? void 0 : _a2.find((node) => node.id === edge.fromNode); const to = (_b2 = cachedContent.nodes) == null ? void 0 : _b2.find((node) => node.id === edge.toNode); if (!from || !to) return; if (from.type !== "file" || to.type !== "file" || !from.file || !from.file) return; const fromFile = from.file; const toFile = to.file; this.registerInternalLinkAC(file.name, fromFile, toFile); if (!(edge.toEnd !== "none" || edge.fromEnd === "arrow")) this.registerInternalLinkAC(file.name, toFile, fromFile); }); } this.trigger("resolve", file); this.trigger("resolved"); }), registerInternalLinkAC: (_next) => async function(canvasName, from, to) { var _a, _b, _c, _d; if (from === to) return; const fromFile = this.vault.getAbstractFileByPath(from); if (!fromFile || !(fromFile instanceof import_obsidian6.TFile)) return; if (!["md", "canvas"].includes(fromFile.extension)) return; const fromFileHash = (_b = (_a = this.fileCache[from]) == null ? void 0 : _a.hash) != null ? _b : await HashHelper.getFileHash(that.plugin, fromFile); const fromFileMetadataCache = (_c = this.metadataCache[fromFileHash]) != null ? _c : { v: 1 }; this.metadataCache[fromFileHash] = { ...fromFileMetadataCache, links: [ ...fromFileMetadataCache.links || [], { link: to, original: to, displayText: `${canvasName} \u2192 ${to}`, position: { start: { line: 0, col: 0, offset: 0 }, end: { line: 0, col: 0, offset: 0 } } } ] }; this.resolvedLinks[from] = { ...this.resolvedLinks[from], [to]: (((_d = this.resolvedLinks[from]) == null ? void 0 : _d[to]) || 0) + 1 }; } }); this.plugin.registerEvent(this.plugin.app.vault.on("modify", (file) => { if (FilepathHelper.extension(file.path) !== "canvas") return; this.plugin.app.metadataCache.computeFileMetadataAsync(file); })); } }; // src/patchers/backlinks-patcher.ts var import_obsidian7 = require("obsidian"); var BacklinksPatcher = class extends Patcher { constructor() { super(...arguments); this.isRecomputingBacklinks = false; } async patch() { if (!this.plugin.settings.getSetting("canvasMetadataCompatibilityEnabled")) return; const that = this; await Patcher.waitForViewRequest(this.plugin, "backlink", (view) => { Patcher.patchPrototype(this.plugin, view.backlink, { recomputeBacklink: Patcher.OverrideExisting((next) => function(file, ...args) { that.isRecomputingBacklinks = true; const result = next.call(this, file, ...args); that.isRecomputingBacklinks = false; return result; }) }); }); Patcher.patchPrototype(this.plugin, this.plugin.app.vault, { recurseChildrenAC: (_next) => function(origin, traverse) { for (var stack = [origin]; stack.length > 0; ) { var current = stack.pop(); if (current) { traverse(current); if (current instanceof import_obsidian7.TFolder) stack = stack.concat(current.children); } } }, getMarkdownFiles: Patcher.OverrideExisting((next) => function(...args) { if (!that.isRecomputingBacklinks) return next.call(this, ...args); var files = []; var root = this.getRoot(); this.recurseChildrenAC(root, (child) => { if (child instanceof import_obsidian7.TFile && (child.extension === "md" || child.extension === "canvas")) { files.push(child); } }); return files; }) }); } }; // src/patchers/outgoing-links-patcher.ts var OutgoingLinksPatcher = class extends Patcher { async patch() { if (!this.plugin.settings.getSetting("canvasMetadataCompatibilityEnabled")) return; const that = this; await Patcher.waitForViewRequest(this.plugin, "outgoing-link", (view) => { Patcher.patchPrototype(this.plugin, view.outgoingLink, { recomputeLinks: Patcher.OverrideExisting((next) => function(...args) { var _a; const isCanvas = ((_a = this.file) == null ? void 0 : _a.extension) === "canvas"; if (isCanvas) this.file.extension = "md"; const result = next.call(this, ...args); if (isCanvas) this.file.extension = "canvas"; return result; }), recomputeUnlinked: Patcher.OverrideExisting((next) => function(...args) { var _a; const isCanvas = ((_a = this.file) == null ? void 0 : _a.extension) === "canvas"; if (isCanvas) this.file.extension = "md"; const result = next.call(this, ...args); if (isCanvas) this.file.extension = "canvas"; return result; }) }); }); } }; // src/patchers/properties-patcher.ts var PropertiesPatcher = class extends Patcher { async patch() { if (!this.plugin.settings.getSetting("canvasMetadataCompatibilityEnabled")) return; const that = this; await Patcher.waitForViewRequest(this.plugin, "file-properties", (view) => { Patcher.patchPrototype(this.plugin, view, { isSupportedFile: Patcher.OverrideExisting((next) => function(file) { if ((file == null ? void 0 : file.extension) === "canvas") return true; return next.call(this, file); }), updateFrontmatter: Patcher.OverrideExisting((next) => function(file, content) { var _a, _b, _c; if ((file == null ? void 0 : file.extension) === "canvas") { const frontmatter = (_c = (_b = (_a = JSON.parse(content)) == null ? void 0 : _a.metadata) == null ? void 0 : _b.frontmatter) != null ? _c : {}; this.rawFrontmatter = JSON.stringify(frontmatter, null, 2); this.frontmatter = frontmatter; return frontmatter; } return next.call(this, file, content); }), saveFrontmatter: Patcher.OverrideExisting((next) => function(frontmatter) { var _a; if (((_a = this.file) == null ? void 0 : _a.extension) === "canvas") { if (this.file !== this.modifyingFile) return; this.app.vault.process(this.file, (data) => { const content = JSON.parse(data); if (content == null ? void 0 : content.metadata) content.metadata.frontmatter = frontmatter; return JSON.stringify(content, null, 2); }); return; } return next.call(this, frontmatter); }) }); }); } }; // src/patchers/search-patcher.ts var SearchPatcher = class extends Patcher { async patch() { if (!this.plugin.settings.getSetting("canvasMetadataCompatibilityEnabled")) return; const that = this; await Patcher.waitForViewRequest(this.plugin, "search", (view) => { const uninstaller = around(view, { startSearch: (next) => function(...args) { const result = next.call(this, ...args); if (this.searchQuery) { that.patchSearchQuery(this.searchQuery); uninstaller(); } return result; } }); that.plugin.register(uninstaller); }); } patchSearchQuery(searchQuery) { Patcher.patchThisAndPrototype(this.plugin, searchQuery, { _match: Patcher.OverrideExisting((next) => function(data) { const isCanvas = data.strings.filepath.endsWith(".canvas"); if (isCanvas && !data.cache) data.cache = this.app.metadataCache.getCache(data.strings.filepath); return next.call(this, data); }) }); } }; // src/patchers/search-command-patcher.ts var import_obsidian8 = require("obsidian"); var SearchCommandPatcher = class extends Patcher { async patch() { if (!this.plugin.settings.getSetting("nativeFileSearchEnabled")) return; const that = this; Patcher.patch(this.plugin, this.plugin.app.commands.commands["editor:open-search"], { checkCallback: Patcher.OverrideExisting((next) => function(checking) { if (that.plugin.app.workspace.activeEditor) return next.call(this, checking); const activeCanvasView = that.plugin.getCurrentCanvasView(); if (!activeCanvasView) return next.call(this, checking); if (checking) return true; if (!activeCanvasView.canvas.searchEl) new CanvasSearchView(activeCanvasView); return true; }) }); } }; var CanvasSearchView = class { constructor(view) { this.searchMatches = []; this.matchIndex = 0; this.view = view; this.createSearchView(); } createSearchView() { this.containerEl = document.createElement("div"); this.containerEl.className = "document-search-container"; const documentSearch = document.createElement("div"); documentSearch.className = "document-search"; this.containerEl.appendChild(documentSearch); const searchInputContainer = document.createElement("div"); searchInputContainer.className = "search-input-container document-search-input"; documentSearch.appendChild(searchInputContainer); this.searchInput = document.createElement("input"); this.searchInput.type = "text"; this.searchInput.placeholder = "Find..."; this.searchInput.addEventListener("keydown", (e) => this.onKeyDown(e)); this.searchInput.addEventListener("input", () => this.onInput()); searchInputContainer.appendChild(this.searchInput); this.searchCount = document.createElement("div"); this.searchCount.className = "document-search-count"; this.searchCount.style.display = "none"; this.searchCount.textContent = "0 / 0"; searchInputContainer.appendChild(this.searchCount); const documentSearchButtons = document.createElement("div"); documentSearchButtons.className = "document-search-buttons"; documentSearch.appendChild(documentSearchButtons); const previousButton = document.createElement("button"); previousButton.className = "clickable-icon document-search-button"; previousButton.setAttribute("aria-label", "Previous\nShift + F3"); previousButton.setAttribute("data-tooltip-position", "top"); (0, import_obsidian8.setIcon)(previousButton, "arrow-up"); previousButton.addEventListener("click", () => this.changeMatch(this.matchIndex - 1)); documentSearchButtons.appendChild(previousButton); const nextButton = document.createElement("button"); nextButton.className = "clickable-icon document-search-button"; nextButton.setAttribute("aria-label", "Next\nF3"); nextButton.setAttribute("data-tooltip-position", "top"); (0, import_obsidian8.setIcon)(nextButton, "arrow-down"); nextButton.addEventListener("click", () => this.changeMatch(this.matchIndex + 1)); documentSearchButtons.appendChild(nextButton); const closeButton = document.createElement("button"); closeButton.className = "clickable-icon document-search-close-button"; closeButton.setAttribute("aria-label", "Exit search"); closeButton.setAttribute("data-tooltip-position", "top"); (0, import_obsidian8.setIcon)(closeButton, "x"); closeButton.addEventListener("click", () => this.close()); documentSearch.appendChild(closeButton); this.view.canvas.wrapperEl.appendChild(this.containerEl); this.view.canvas.searchEl = this.containerEl; this.searchInput.focus(); } onKeyDown(e) { if (e.key === "Enter" || e.key === "F3") this.changeMatch(this.matchIndex + (e.shiftKey ? -1 : 1)); else if (e.key === "Escape") this.close(); } onInput() { const hasQuery = this.searchInput.value.length > 0; this.searchCount.style.display = hasQuery ? "block" : "none"; if (!hasQuery) this.searchMatches = []; else { this.searchMatches = Array.from(this.view.canvas.nodes.values()).map((node) => { const nodeData = node.getData(); let content = void 0; if (nodeData.type === "text") content = nodeData.text; else if (nodeData.type === "group") content = nodeData.label; else if (nodeData.type === "file") content = node.child.data; if (!content) return null; const matches = []; const regex = new RegExp(this.searchInput.value, "gi"); let match; while ((match = regex.exec(content)) !== null) { matches.push([match.index, match.index + match[0].length]); } return { nodeId: node.id, content, matches }; }).filter((match) => match && match.matches.length > 0); } this.changeMatch(0); } changeMatch(index) { if (this.searchMatches.length === 0) this.matchIndex = -1; else { if (index < 0) index += this.searchMatches.length; this.matchIndex = index % this.searchMatches.length; } const match = this.searchMatches[this.matchIndex]; if (match) this.goToMatch(match); this.searchCount.textContent = `${this.matchIndex + 1} / ${this.searchMatches.length}`; } goToMatch(match) { this.view.setEphemeralState({ match }); } close() { this.containerEl.remove(); this.view.canvas.searchEl = void 0; } }; // src/canvas-extensions/metadata-canvas-extension.ts var import_obsidian9 = require("obsidian"); var MetadataCanvasExtension = class extends CanvasExtension { constructor() { super(...arguments); this.canvasCssclassesCache = /* @__PURE__ */ new Map(); } isEnabled() { return true; } init() { this.plugin.registerEvent(this.plugin.app.workspace.on( "advanced-canvas:canvas-changed", (canvas) => this.onCanvasChanged(canvas) )); this.plugin.registerEvent(this.plugin.app.workspace.on( "advanced-canvas:canvas-metadata-changed", (canvas) => this.onMetadataChanged(canvas) )); this.plugin.registerEvent(this.plugin.app.workspace.on( "advanced-canvas:canvas-view-unloaded:before", (view) => this.onCanvasViewUnloaded(view) )); } onCanvasChanged(canvas) { var _a; let metadata = (_a = canvas.data) == null ? void 0 : _a.metadata; if (!metadata || metadata.version !== CURRENT_SPEC_VERSION) return new import_obsidian9.Notice("Metadata node not found or version mismatch. Should have been migrated (but wasn't)."); const that = this; const validator = { get(target, key) { if (typeof target[key] === "object" && target[key] !== null) return new Proxy(target[key], validator); else return target[key]; }, set(target, key, value) { target[key] = value; that.plugin.app.workspace.trigger("advanced-canvas:canvas-metadata-changed", canvas); canvas.requestSave(); return true; } }; canvas.metadata = new Proxy(metadata, validator); this.plugin.app.workspace.trigger("advanced-canvas:canvas-metadata-changed", canvas); } onMetadataChanged(canvas) { var _a, _b, _c; if (this.canvasCssclassesCache.has(canvas.view)) canvas.wrapperEl.classList.remove(...this.canvasCssclassesCache.get(canvas.view)); const currentClasses = (_c = (_b = (_a = canvas.metadata) == null ? void 0 : _a.frontmatter) == null ? void 0 : _b.cssclasses) != null ? _c : []; this.canvasCssclassesCache.set(canvas.view, currentClasses); if (currentClasses.length > 0) canvas.wrapperEl.classList.add(...currentClasses); } onCanvasViewUnloaded(view) { this.canvasCssclassesCache.delete(view); } }; // src/utils/modal-helper.ts var import_obsidian10 = require("obsidian"); var AbstractSelectionModal = class extends import_obsidian10.FuzzySuggestModal { constructor(app, placeholder, suggestions) { super(app); this.suggestions = suggestions; this.setPlaceholder(placeholder); this.setInstructions([{ command: "\u2191\u2193", purpose: "to navigate" }, { command: "esc", purpose: "to dismiss" }]); } getItems() { return this.suggestions; } getItemText(item) { return item; } onChooseItem(item, evt) { } awaitInput() { return new Promise((resolve, _reject) => { this.onChooseItem = (item) => { resolve(item); }; this.open(); }); } }; var FileNameModal = class extends import_obsidian10.SuggestModal { constructor(app, parentPath, fileExtension) { super(app); this.parentPath = parentPath.replace(/^\//, "").replace(/\/$/, ""); this.fileExtension = fileExtension; } getSuggestions(query) { const queryWithoutExtension = query.replace(new RegExp(`\\.${this.fileExtension}$`), ""); if (queryWithoutExtension === "") return []; const queryWithExtension = queryWithoutExtension + "." + this.fileExtension; const suggestions = [queryWithExtension]; if (this.parentPath.length > 0) suggestions.splice(0, 0, `${this.parentPath}/${queryWithExtension}`); return suggestions.filter((s) => this.app.vault.getAbstractFileByPath(s) === null); } renderSuggestion(text, el) { el.setText(text); } onChooseSuggestion(_text, _evt) { } awaitInput() { return new Promise((resolve, _reject) => { this.onChooseSuggestion = (text) => { resolve(text); }; this.open(); }); } }; var FileSelectModal = class extends import_obsidian10.SuggestModal { constructor(app, extensionsRegex, suggestNewFile = false) { super(app); this.files = this.app.vault.getFiles().map((file) => file.path).filter((path) => { var _a; return (_a = FilepathHelper.extension(path)) == null ? void 0 : _a.match(extensionsRegex != null ? extensionsRegex : /.*/); }); this.suggestNewFile = suggestNewFile; this.setPlaceholder("Type to search..."); this.setInstructions([{ command: "\u2191\u2193", purpose: "to navigate" }, { command: "\u21B5", purpose: "to open" }, { command: "shift \u21B5", purpose: "to create" }, { command: "esc", purpose: "to dismiss" }]); this.scope.register(["Shift"], "Enter", (e) => { this.onChooseSuggestion(this.inputEl.value, e); this.close(); }); } getSuggestions(query) { const suggestions = this.files.filter((path) => path.toLowerCase().includes(query.toLowerCase())); if (suggestions.length === 0 && this.suggestNewFile) suggestions.push(query); return suggestions; } renderSuggestion(path, el) { const simplifiedPath = path.replace(/\.md$/, ""); el.setText(simplifiedPath); } onChooseSuggestion(_path, _evt) { } awaitInput() { return new Promise((resolve, _reject) => { this.onChooseSuggestion = (path, _evt) => { const file = this.app.vault.getAbstractFileByPath(path); if (file instanceof import_obsidian10.TFile) return resolve(file); if (!this.suggestNewFile) return; if (FilepathHelper.extension(path) === void 0) path += ".md"; const newFile = this.app.vault.create(path, ""); resolve(newFile); }; this.open(); }); } }; // src/canvas-extensions/node-ratio-canvas-extension.ts var NodeRatioCanvasExtension = class extends CanvasExtension { isEnabled() { return true; } init() { this.plugin.registerEvent(this.plugin.app.workspace.on( "canvas:node-menu", (menu, node) => this.onNodeMenu(menu, node) )); this.plugin.registerEvent(this.plugin.app.workspace.on( "advanced-canvas:node-resized", (canvas, node) => this.onNodeResized(canvas, node) )); } onNodeMenu(menu, node) { if (!this.plugin.settings.getSetting("aspectRatioControlFeatureEnabled")) return; menu.addItem((item) => { item.setTitle("Set Aspect Ratio").setIcon("aspect-ratio").onClick(async () => { const NO_RATIO = "No ratio enforcement"; const newRatioString = await new AbstractSelectionModal(this.plugin.app, "Enter aspect ratio (width:height)", ["16:9", "4:3", "3:2", "1:1", NO_RATIO]).awaitInput(); const nodeData = node.getData(); if (newRatioString === NO_RATIO) { node.setData({ ...nodeData, ratio: void 0 }); return; } const [width, height] = newRatioString.split(":").map(Number); if (width && height) { node.setData({ ...nodeData, ratio: width / height }); node.setData({ ...node.getData(), width: nodeData.height * (width / height) }); } }); }); } onNodeResized(_canvas, node) { const nodeData = node.getData(); if (!nodeData.ratio) return; const nodeBBox = node.getBBox(); const nodeSize = { width: nodeBBox.maxX - nodeBBox.minX, height: nodeBBox.maxY - nodeBBox.minY }; const nodeAspectRatio = nodeSize.width / nodeSize.height; if (nodeAspectRatio < nodeData.ratio) nodeSize.width = nodeSize.height * nodeData.ratio; else nodeSize.height = nodeSize.width / nodeData.ratio; node.setData({ ...nodeData, width: nodeSize.width, height: nodeSize.height }); } }; // src/utils/canvas-helper.ts var import_obsidian11 = require("obsidian"); var _CanvasHelper = class _CanvasHelper { static canvasCommand(plugin, check, run) { return (checking) => { const canvas = plugin.getCurrentCanvas(); if (checking) return canvas !== null && check(canvas); if (canvas) run(canvas); return true; }; } static createControlMenuButton(menuOption) { const quickSetting = document.createElement("div"); if (menuOption.id) quickSetting.id = menuOption.id; quickSetting.classList.add("canvas-control-item"); (0, import_obsidian11.setIcon)(quickSetting, menuOption.icon); (0, import_obsidian11.setTooltip)(quickSetting, menuOption.label, { placement: "left" }); quickSetting.addEventListener("click", () => { var _a; return (_a = menuOption.callback) == null ? void 0 : _a.call(menuOption); }); return quickSetting; } static addControlMenuButton(controlGroup, element) { var _a; if (element.id) (_a = controlGroup.querySelector(`#${element.id}`)) == null ? void 0 : _a.remove(); controlGroup.appendChild(element); } static createCardMenuOption(canvas, menuOption, previewNodeSize, onPlaced) { const menuOptionElement = document.createElement("div"); if (menuOption.id) menuOptionElement.id = menuOption.id; menuOptionElement.classList.add("canvas-card-menu-button"); menuOptionElement.classList.add("mod-draggable"); (0, import_obsidian11.setIcon)(menuOptionElement, menuOption.icon); (0, import_obsidian11.setTooltip)(menuOptionElement, menuOption.label, { placement: "top" }); menuOptionElement.addEventListener("click", (_e) => { onPlaced(canvas, this.getCenterCoordinates(canvas, previewNodeSize())); }); menuOptionElement.addEventListener("pointerdown", (e) => { canvas.dragTempNode(e, previewNodeSize(), (pos) => { canvas.deselectAll(); onPlaced(canvas, pos); }); }); return menuOptionElement; } static addCardMenuOption(canvas, element) { var _a; if (element.id) (_a = canvas == null ? void 0 : canvas.cardMenuEl.querySelector(`#${element.id}`)) == null ? void 0 : _a.remove(); canvas == null ? void 0 : canvas.cardMenuEl.appendChild(element); } static createPopupMenuOption(menuOption) { const menuOptionElement = document.createElement("button"); if (menuOption.id) menuOptionElement.id = menuOption.id; menuOptionElement.classList.add("clickable-icon"); (0, import_obsidian11.setIcon)(menuOptionElement, menuOption.icon); (0, import_obsidian11.setTooltip)(menuOptionElement, menuOption.label, { placement: "top" }); menuOptionElement.addEventListener("click", () => { var _a; return (_a = menuOption.callback) == null ? void 0 : _a.call(menuOption); }); return menuOptionElement; } static createExpandablePopupMenuOption(menuOption, subMenuOptions) { const menuOptionElement = this.createPopupMenuOption({ ...menuOption, callback: () => { var _a, _b, _c; const submenuId = `${menuOption.id}-submenu`; if (menuOptionElement.classList.contains("is-active")) { menuOptionElement.classList.remove("is-active"); (_b = (_a = menuOptionElement.parentElement) == null ? void 0 : _a.querySelector(`#${submenuId}`)) == null ? void 0 : _b.remove(); return; } menuOptionElement.classList.add("is-active"); const submenu = document.createElement("div"); submenu.id = submenuId; submenu.classList.add("canvas-submenu"); for (const subMenuOption of subMenuOptions) { const subMenuOptionElement = this.createPopupMenuOption(subMenuOption); submenu.appendChild(subMenuOptionElement); } (_c = menuOptionElement.parentElement) == null ? void 0 : _c.appendChild(submenu); } }); return menuOptionElement; } static addPopupMenuOption(canvas, element, index = -1) { var _a; const popupMenuEl = (_a = canvas == null ? void 0 : canvas.menu) == null ? void 0 : _a.menuEl; if (!popupMenuEl) return; if (element.id) { const optionToReplace = popupMenuEl.querySelector(`#${element.id}`); if (optionToReplace && index === -1) index = Array.from(popupMenuEl.children).indexOf(optionToReplace) - 1; optionToReplace == null ? void 0 : optionToReplace.remove(); } const sisterElement = index >= 0 ? popupMenuEl.children[index] : popupMenuEl.children[popupMenuEl.children.length + index]; popupMenuEl.insertAfter(element, sisterElement); } static getCenterCoordinates(canvas, nodeSize) { const viewBounds = canvas.getViewportBBox(); return { x: (viewBounds.minX + viewBounds.maxX) / 2 - nodeSize.width / 2, y: (viewBounds.minY + viewBounds.maxY) / 2 - nodeSize.height / 2 }; } static getBBox(canvasElements) { const bBoxes = canvasElements.map((element) => { if (element.getBBox) return element.getBBox(); const nodeData = element; if (nodeData.x !== void 0 && nodeData.y !== void 0 && nodeData.width !== void 0 && nodeData.height !== void 0) return { minX: nodeData.x, minY: nodeData.y, maxX: nodeData.x + nodeData.width, maxY: nodeData.y + nodeData.height }; return null; }).filter((bbox) => bbox !== null); return BBoxHelper.combineBBoxes(bBoxes); } static getSmallestAllowedZoomBBox(canvas, bbox) { if (canvas.screenshotting) return bbox; if (canvas.canvasRect.width === 0 || canvas.canvasRect.height === 0) return bbox; const widthZoom = canvas.canvasRect.width / (bbox.maxX - bbox.minX); const heightZoom = canvas.canvasRect.height / (bbox.maxY - bbox.minY); const requiredZoom = Math.min(widthZoom, heightZoom); if (requiredZoom > _CanvasHelper.MAX_ALLOWED_ZOOM) { const scaleFactor = requiredZoom / _CanvasHelper.MAX_ALLOWED_ZOOM; return BBoxHelper.scaleBBox(bbox, scaleFactor); } return bbox; } static addStyleAttributesToPopup(plugin, canvas, styleAttributes, currentStyleAttributes, setStyleAttribute) { if (!plugin.settings.getSetting("combineCustomStylesInDropdown")) this.addStyleAttributesButtons(canvas, styleAttributes, currentStyleAttributes, setStyleAttribute); else this.addStyleAttributesDropdownMenu(canvas, styleAttributes, currentStyleAttributes, setStyleAttribute); } static addStyleAttributesButtons(canvas, stylableAttributes, currentStyleAttributes, setStyleAttribute) { var _a; for (const stylableAttribute of stylableAttributes) { const selectedStyle = (_a = stylableAttribute.options.find((option) => currentStyleAttributes[stylableAttribute.key] === option.value)) != null ? _a : stylableAttribute.options.find((value) => value.value === null); const menuOption = _CanvasHelper.createExpandablePopupMenuOption({ id: `menu-option-${stylableAttribute.key}`, label: stylableAttribute.label, icon: selectedStyle.icon }, stylableAttribute.options.map((styleOption) => ({ label: styleOption.label, icon: styleOption.icon, callback: () => { setStyleAttribute(stylableAttribute, styleOption.value); currentStyleAttributes[stylableAttribute.key] = styleOption.value; (0, import_obsidian11.setIcon)(menuOption, styleOption.icon); menuOption.dispatchEvent(new Event("click")); } }))); _CanvasHelper.addPopupMenuOption(canvas, menuOption); } } static addStyleAttributesDropdownMenu(canvas, stylableAttributes, currentStyleAttributes, setStyleAttribute) { var _a, _b; const STYLE_MENU_ID = "style-menu"; const STYLE_MENU_DROPDOWN_ID = "style-menu-dropdown"; const STYLE_MENU_DROPDOWN_SUBMENU_ID = "style-menu-dropdown-submenu"; const popupMenuElement = (_a = canvas == null ? void 0 : canvas.menu) == null ? void 0 : _a.menuEl; if (!popupMenuElement) return; (_b = popupMenuElement.querySelector(`#${STYLE_MENU_ID}`)) == null ? void 0 : _b.remove(); const styleMenuButtonElement = document.createElement("button"); styleMenuButtonElement.id = STYLE_MENU_ID; styleMenuButtonElement.classList.add("clickable-icon"); (0, import_obsidian11.setIcon)(styleMenuButtonElement, "paintbrush"); (0, import_obsidian11.setTooltip)(styleMenuButtonElement, "Style", { placement: "top" }); popupMenuElement.appendChild(styleMenuButtonElement); styleMenuButtonElement.addEventListener("click", () => { var _a2, _b2, _c; const isOpen = styleMenuButtonElement.classList.toggle("has-active-menu"); if (!isOpen) { (_a2 = popupMenuElement.querySelector(`#${STYLE_MENU_DROPDOWN_ID}`)) == null ? void 0 : _a2.remove(); (_b2 = popupMenuElement.querySelector(`#${STYLE_MENU_DROPDOWN_SUBMENU_ID}`)) == null ? void 0 : _b2.remove(); return; } const styleMenuDropdownElement = document.createElement("div"); styleMenuDropdownElement.id = STYLE_MENU_DROPDOWN_ID; styleMenuDropdownElement.classList.add("menu"); styleMenuDropdownElement.style.position = "absolute"; styleMenuDropdownElement.style.maxHeight = "initial"; styleMenuDropdownElement.style.top = `${popupMenuElement.getBoundingClientRect().height}px`; const canvasWrapperCenterX = canvas.wrapperEl.getBoundingClientRect().left + canvas.wrapperEl.getBoundingClientRect().width / 2; const leftPosition = styleMenuButtonElement.getBoundingClientRect().left - popupMenuElement.getBoundingClientRect().left; const rightPosition = popupMenuElement.getBoundingClientRect().right - styleMenuButtonElement.getBoundingClientRect().right; if (popupMenuElement.getBoundingClientRect().left + leftPosition < canvasWrapperCenterX) styleMenuDropdownElement.style.left = `${leftPosition}px`; else styleMenuDropdownElement.style.right = `${rightPosition}px`; for (const stylableAttribute of stylableAttributes) { const stylableAttributeElement = document.createElement("div"); stylableAttributeElement.classList.add("menu-item"); stylableAttributeElement.classList.add("tappable"); const iconElement = document.createElement("div"); iconElement.classList.add("menu-item-icon"); let selectedStyle = (_c = stylableAttribute.options.find((option) => currentStyleAttributes[stylableAttribute.key] === option.value)) != null ? _c : stylableAttribute.options.find((value) => value.value === null); (0, import_obsidian11.setIcon)(iconElement, selectedStyle.icon); stylableAttributeElement.appendChild(iconElement); const labelElement = document.createElement("div"); labelElement.classList.add("menu-item-title"); labelElement.textContent = stylableAttribute.label; stylableAttributeElement.appendChild(labelElement); const expandIconElement = document.createElement("div"); expandIconElement.classList.add("menu-item-icon"); (0, import_obsidian11.setIcon)(expandIconElement, "chevron-right"); stylableAttributeElement.appendChild(expandIconElement); styleMenuDropdownElement.appendChild(stylableAttributeElement); stylableAttributeElement.addEventListener("pointerenter", () => { stylableAttributeElement.classList.add("selected"); }); stylableAttributeElement.addEventListener("pointerleave", () => { stylableAttributeElement.classList.remove("selected"); }); stylableAttributeElement.addEventListener("click", () => { var _a3; (_a3 = popupMenuElement.querySelector(`#${STYLE_MENU_DROPDOWN_SUBMENU_ID}`)) == null ? void 0 : _a3.remove(); const styleMenuDropdownSubmenuElement = document.createElement("div"); styleMenuDropdownSubmenuElement.id = STYLE_MENU_DROPDOWN_SUBMENU_ID; styleMenuDropdownSubmenuElement.classList.add("menu"); styleMenuDropdownSubmenuElement.style.position = "absolute"; styleMenuDropdownSubmenuElement.style.maxHeight = "initial"; const topOffset = parseFloat(window.getComputedStyle(styleMenuDropdownElement).getPropertyValue("padding-top")) + (styleMenuDropdownElement.offsetHeight - styleMenuDropdownElement.clientHeight) / 2; styleMenuDropdownSubmenuElement.style.top = `${stylableAttributeElement.getBoundingClientRect().top - topOffset - popupMenuElement.getBoundingClientRect().top}px`; const leftPosition2 = styleMenuDropdownElement.getBoundingClientRect().right - popupMenuElement.getBoundingClientRect().left; const rightPosition2 = popupMenuElement.getBoundingClientRect().right - styleMenuDropdownElement.getBoundingClientRect().left; if (popupMenuElement.getBoundingClientRect().left + leftPosition2 < canvasWrapperCenterX) styleMenuDropdownSubmenuElement.style.left = `${leftPosition2}px`; else styleMenuDropdownSubmenuElement.style.right = `${rightPosition2}px`; for (const styleOption of stylableAttribute.options) { const styleMenuDropdownSubmenuOptionElement = this.createDropdownOptionElement({ label: styleOption.label, icon: styleOption.icon, callback: () => { setStyleAttribute(stylableAttribute, styleOption.value); currentStyleAttributes[stylableAttribute.key] = styleOption.value; selectedStyle = styleOption; (0, import_obsidian11.setIcon)(iconElement, styleOption.icon); styleMenuDropdownSubmenuElement.remove(); } }); if (selectedStyle === styleOption) { styleMenuDropdownSubmenuOptionElement.classList.add("mod-selected"); const selectedIconElement = document.createElement("div"); selectedIconElement.classList.add("menu-item-icon"); selectedIconElement.classList.add("mod-selected"); (0, import_obsidian11.setIcon)(selectedIconElement, "check"); styleMenuDropdownSubmenuOptionElement.appendChild(selectedIconElement); } styleMenuDropdownSubmenuElement.appendChild(styleMenuDropdownSubmenuOptionElement); } popupMenuElement.appendChild(styleMenuDropdownSubmenuElement); }); } popupMenuElement.appendChild(styleMenuDropdownElement); }); } static createDropdownOptionElement(menuOption) { const menuDropdownOptionElement = document.createElement("div"); menuDropdownOptionElement.classList.add("menu-item"); menuDropdownOptionElement.classList.add("tappable"); const iconElement = document.createElement("div"); iconElement.classList.add("menu-item-icon"); (0, import_obsidian11.setIcon)(iconElement, menuOption.icon); menuDropdownOptionElement.appendChild(iconElement); const labelElement = document.createElement("div"); labelElement.classList.add("menu-item-title"); labelElement.textContent = menuOption.label; menuDropdownOptionElement.appendChild(labelElement); menuDropdownOptionElement.addEventListener("pointerenter", () => { menuDropdownOptionElement.classList.add("selected"); }); menuDropdownOptionElement.addEventListener("pointerleave", () => { menuDropdownOptionElement.classList.remove("selected"); }); menuDropdownOptionElement.addEventListener("click", () => { var _a; (_a = menuOption.callback) == null ? void 0 : _a.call(menuOption); }); return menuDropdownOptionElement; } static createDropdownSeparatorElement() { const separatorElement = document.createElement("div"); separatorElement.classList.add("menu-separator"); return separatorElement; } static alignToGrid(value, gridSize = this.GRID_SIZE) { return Math.round(value / gridSize) * gridSize; } static getBestSideForFloatingEdge(sourcePos, target) { const targetBBox = target.getBBox(); const possibleSides = ["top", "right", "bottom", "left"]; const possibleTargetPos = possibleSides.map((side) => [side, BBoxHelper.getCenterOfBBoxSide(targetBBox, side)]); let bestSide = null; let bestDistance = Infinity; for (const [side, pos] of possibleTargetPos) { const distance = Math.sqrt(Math.pow(sourcePos.x - pos.x, 2) + Math.pow(sourcePos.y - pos.y, 2)); if (distance < bestDistance) { bestDistance = distance; bestSide = side; } } return bestSide; } }; _CanvasHelper.GRID_SIZE = 20; _CanvasHelper.MAX_ALLOWED_ZOOM = 1; var CanvasHelper = _CanvasHelper; // src/canvas-extensions/group-canvas-extension.ts var GROUP_NODE_SIZE = { width: 300, height: 300 }; var GroupCanvasExtension = class extends CanvasExtension { isEnabled() { return true; } init() { this.plugin.registerEvent(this.plugin.app.workspace.on( "advanced-canvas:canvas-changed", (canvas) => { CanvasHelper.addCardMenuOption( canvas, CanvasHelper.createCardMenuOption( canvas, { id: "create-group", label: "Drag to add group", icon: "group" }, () => GROUP_NODE_SIZE, (canvas2, pos) => { canvas2.createGroupNode({ pos, size: GROUP_NODE_SIZE }); } ) ); } )); } }; // src/canvas-extensions/presentation-canvas-extension.ts var import_obsidian12 = require("obsidian"); var START_SLIDE_NAME = "Start Slide"; var DEFAULT_SLIDE_NAME = "New Slide"; var PresentationCanvasExtension = class extends CanvasExtension { constructor() { super(...arguments); this.savedViewport = null; this.isPresentationMode = false; this.visitedNodeIds = []; this.fullscreenModalObserver = null; } isEnabled() { return "presentationFeatureEnabled"; } init() { this.plugin.registerEvent(this.plugin.app.workspace.on( "canvas:selection-menu", (menu, canvas) => { menu.addItem( (item) => item.setTitle("Wrap in slide").setIcon("gallery-vertical").onClick(() => this.addSlide( canvas, void 0, BBoxHelper.enlargeBBox(BBoxHelper.combineBBoxes( [...canvas.selection.values()].map((element) => element.getBBox()) ), this.plugin.settings.getSetting("wrapInSlidePadding")) )) ); } )); this.plugin.addCommand({ id: "create-new-slide", name: "Create new slide", checkCallback: CanvasHelper.canvasCommand( this.plugin, (canvas) => !canvas.readonly && !this.isPresentationMode, (canvas) => this.addSlide(canvas) ) }); this.plugin.addCommand({ id: "set-start-node", name: "Set start node", checkCallback: CanvasHelper.canvasCommand( this.plugin, (canvas) => !canvas.readonly && !this.isPresentationMode && canvas.getSelectionData().nodes.length === 1, (canvas) => this.setStartNode(canvas, canvas.nodes.get(canvas.getSelectionData().nodes[0].id)) ) }); this.plugin.addCommand({ id: "start-presentation", name: "Start presentation", checkCallback: CanvasHelper.canvasCommand( this.plugin, (_canvas) => !this.isPresentationMode, (canvas) => this.startPresentation(canvas) ) }); this.plugin.addCommand({ id: "continue-presentation", name: "Continue presentation", checkCallback: CanvasHelper.canvasCommand( this.plugin, (_canvas) => !this.isPresentationMode, (canvas) => this.startPresentation(canvas, true) ) }); this.plugin.addCommand({ id: "end-presentation", name: "End presentation", checkCallback: CanvasHelper.canvasCommand( this.plugin, (_canvas) => this.isPresentationMode, (canvas) => this.endPresentation(canvas) ) }); this.plugin.addCommand({ id: "previous-node", name: "Previous node", checkCallback: CanvasHelper.canvasCommand( this.plugin, (_canvas) => this.isPresentationMode, (canvas) => this.previousNode(canvas) ) }); this.plugin.addCommand({ id: "next-node", name: "Next node", checkCallback: CanvasHelper.canvasCommand( this.plugin, (_canvas) => this.isPresentationMode, (canvas) => this.nextNode(canvas) ) }); this.plugin.registerEvent(this.plugin.app.workspace.on( "advanced-canvas:canvas-changed", (canvas) => this.onCanvasChanged(canvas) )); this.plugin.registerEvent(this.plugin.app.workspace.on( "advanced-canvas:popup-menu-created", (canvas) => this.onPopupMenuCreated(canvas) )); } onCanvasChanged(canvas) { CanvasHelper.addCardMenuOption( canvas, CanvasHelper.createCardMenuOption( canvas, { id: "new-slide", label: "Drag to add slide", icon: "gallery-vertical" }, () => this.getDefaultSlideSize(), (canvas2, pos) => this.addSlide(canvas2, pos) ) ); } onPopupMenuCreated(canvas) { if (!this.plugin.settings.getSetting("showSetStartNodeInPopup")) return; const selectedNodesData = canvas.getSelectionData().nodes; if (canvas.readonly || selectedNodesData.length !== 1 || canvas.selection.size > 1) return; const selectedNode = canvas.nodes.get(selectedNodesData[0].id); if (!selectedNode) return; CanvasHelper.addPopupMenuOption( canvas, CanvasHelper.createPopupMenuOption({ id: "start-node", label: "Set as start slide", icon: "play", callback: () => this.setStartNode(canvas, selectedNode) }) ); } setStartNode(canvas, node) { if (!node) return; canvas.metadata["startNode"] = node.getData().id; } getDefaultSlideSize() { const slideSize = this.plugin.settings.getSetting("defaultSlideDimensions"); return { width: slideSize[0], height: slideSize[1] }; } getSlideAspectRatio() { const slideSize = this.getDefaultSlideSize(); return slideSize.width / slideSize.height; } addSlide(canvas, pos, bbox) { const isStartNode = canvas.metadata["startNode"] === void 0; const slideSize = this.getDefaultSlideSize(); const slideAspectRatio = this.getSlideAspectRatio(); if (bbox) { const bboxWidth = bbox.maxX - bbox.minX; const bboxHeight = bbox.maxY - bbox.minY; if (bboxWidth / bboxHeight > slideAspectRatio) { slideSize.width = bboxWidth; slideSize.height = bboxWidth / slideAspectRatio; } else { slideSize.height = bboxHeight; slideSize.width = bboxHeight * slideAspectRatio; } pos = { x: bbox.minX, y: bbox.minY }; } if (!pos) pos = CanvasHelper.getCenterCoordinates(canvas, this.getDefaultSlideSize()); const groupNode = canvas.createGroupNode({ pos, size: slideSize, label: isStartNode ? START_SLIDE_NAME : DEFAULT_SLIDE_NAME, focus: false }); groupNode.setData({ ...groupNode.getData(), ratio: slideAspectRatio }); if (isStartNode) canvas.metadata["startNode"] = groupNode.getData().id; } async animateNodeTransition(canvas, fromNode, toNode) { const useCustomZoomFunction = this.plugin.settings.getSetting("zoomToSlideWithoutPadding"); const animationDurationMs = this.plugin.settings.getSetting("slideTransitionAnimationDuration") * 1e3; const toNodeBBox = CanvasHelper.getSmallestAllowedZoomBBox(canvas, toNode.getBBox()); if (animationDurationMs > 0 && fromNode) { const animationIntensity = this.plugin.settings.getSetting("slideTransitionAnimationIntensity"); const fromNodeBBox = CanvasHelper.getSmallestAllowedZoomBBox(canvas, fromNode.getBBox()); const currentNodeBBoxEnlarged = BBoxHelper.scaleBBox(fromNodeBBox, animationIntensity); if (useCustomZoomFunction) canvas.zoomToRealBbox(currentNodeBBoxEnlarged); else canvas.zoomToBbox(currentNodeBBoxEnlarged); await sleep(animationDurationMs / 2); if (fromNode.getData().id !== toNode.getData().id) { const nextNodeBBoxEnlarged = BBoxHelper.scaleBBox(toNodeBBox, animationIntensity + 0.1); if (useCustomZoomFunction) canvas.zoomToRealBbox(nextNodeBBoxEnlarged); else canvas.zoomToBbox(nextNodeBBoxEnlarged); await sleep(animationDurationMs / 2); } } if (useCustomZoomFunction) canvas.zoomToRealBbox(toNodeBBox); else canvas.zoomToBbox(toNodeBBox); } async startPresentation(canvas, tryContinue = false) { if (!tryContinue || this.visitedNodeIds.length === 0) { const startNode2 = canvas.metadata["startNode"] && canvas.nodes.get(canvas.metadata["startNode"]); if (!startNode2) { new import_obsidian12.Notice("No start node found. Please mark a node as a start node trough the popup menu."); return; } this.visitedNodeIds = [startNode2.getData().id]; } this.savedViewport = { x: canvas.tx, y: canvas.ty, zoom: canvas.tZoom }; canvas.wrapperEl.focus(); canvas.wrapperEl.requestFullscreen(); canvas.wrapperEl.classList.add("presentation-mode"); canvas.setReadonly(true); if (this.plugin.settings.getSetting("useUnclampedZoomWhilePresenting")) canvas.screenshotting = true; canvas.wrapperEl.onkeydown = (e) => { if (this.plugin.settings.getSetting("useArrowKeysToChangeSlides")) { if (e.key === "ArrowRight") this.nextNode(canvas); else if (e.key === "ArrowLeft") this.previousNode(canvas); } if (this.plugin.settings.getSetting("usePgUpPgDownKeysToChangeSlides")) { if (e.key === "PageDown") this.nextNode(canvas); else if (e.key === "PageUp") this.previousNode(canvas); } }; this.fullscreenModalObserver = new MutationObserver((mutationRecords) => { mutationRecords.forEach((mutationRecord) => { mutationRecord.addedNodes.forEach((node) => { var _a; document.body.removeChild(node); (_a = document.fullscreenElement) == null ? void 0 : _a.appendChild(node); }); }); const inputField = document.querySelector(".prompt-input"); if (inputField) inputField.focus(); }); this.fullscreenModalObserver.observe(document.body, { childList: true }); canvas.wrapperEl.onfullscreenchange = (_e) => { if (document.fullscreenElement) return; this.endPresentation(canvas); }; this.isPresentationMode = true; await sleep(500); const startNodeId = this.visitedNodeIds.first(); if (!startNodeId) return; const startNode = canvas.nodes.get(startNodeId); if (!startNode) return; this.animateNodeTransition(canvas, void 0, startNode); } endPresentation(canvas) { var _a; (_a = this.fullscreenModalObserver) == null ? void 0 : _a.disconnect(); this.fullscreenModalObserver = null; canvas.wrapperEl.onkeydown = null; canvas.wrapperEl.onfullscreenchange = null; canvas.setReadonly(false); if (this.plugin.settings.getSetting("useUnclampedZoomWhilePresenting")) canvas.screenshotting = false; canvas.wrapperEl.classList.remove("presentation-mode"); if (document.fullscreenElement) document.exitFullscreen(); if (this.plugin.settings.getSetting("resetViewportOnPresentationEnd")) canvas.setViewport(this.savedViewport.x, this.savedViewport.y, this.savedViewport.zoom); this.isPresentationMode = false; } nextNode(canvas) { var _a; const fromNodeId = this.visitedNodeIds.last(); if (!fromNodeId) return; const fromNode = canvas.nodes.get(fromNodeId); if (!fromNode) return; const outgoingEdges = canvas.getEdgesForNode(fromNode).filter((edge) => edge.from.node.getData().id === fromNodeId); let toNode = (_a = outgoingEdges.first()) == null ? void 0 : _a.to.node; if (outgoingEdges.length > 1) { const sortedEdges = outgoingEdges.sort((a, b) => { if (!a.label) return 1; if (!b.label) return -1; return a.label.localeCompare(b.label); }); const traversedEdgesCount = this.visitedNodeIds.filter((visitedNodeId) => visitedNodeId === fromNodeId).length - 1; const nextEdge = sortedEdges[traversedEdgesCount]; toNode = nextEdge.to.node; } if (toNode) { this.visitedNodeIds.push(toNode.getData().id); this.animateNodeTransition(canvas, fromNode, toNode); } else { this.animateNodeTransition(canvas, fromNode, fromNode); } } previousNode(canvas) { const fromNodeId = this.visitedNodeIds.pop(); if (!fromNodeId) return; const fromNode = canvas.nodes.get(fromNodeId); if (!fromNode) return; const toNodeId = this.visitedNodeIds.last(); let toNode = toNodeId ? canvas.nodes.get(toNodeId) : null; if (!toNode) { toNode = fromNode; this.visitedNodeIds.push(fromNodeId); } this.animateNodeTransition(canvas, fromNode, toNode); } }; // src/canvas-extensions/z-ordering-canvas-extension.ts var ZOrderingCanvasExtension = class extends CanvasExtension { isEnabled() { return "zOrderingControlFeatureEnabled"; } init() { this.plugin.registerEvent(this.plugin.app.workspace.on( "canvas:node-menu", (menu, node) => this.nodeContextMenu(node, menu) )); this.plugin.registerEvent(this.plugin.app.workspace.on( "canvas:selection-menu", (menu, canvas) => this.selectionContextMenu(canvas, menu) )); } nodeContextMenu(node, menu) { this.addZOrderingContextMenuItems(node.canvas, [node], menu); } selectionContextMenu(canvas, menu) { const selectedNodes = canvas.getSelectionData().nodes.map((nodeData) => canvas.nodes.get(nodeData.id)).filter((node) => node !== void 0); this.addZOrderingContextMenuItems(canvas, selectedNodes, menu); } addZOrderingContextMenuItems(canvas, nodes, menu) { menu.addSeparator(); if (this.plugin.settings.getSetting("zOrderingControlShowOneLayerShiftOptions") && nodes.length === 1) { menu.addItem((item) => { item.setTitle("Move one layer forward"); item.setIcon("arrow-up"); item.onClick(() => this.moveOneLayer(canvas, nodes.first(), true)); }); menu.addItem((item) => { item.setTitle("Move one layer backward"); item.setIcon("arrow-down"); item.onClick(() => this.moveOneLayer(canvas, nodes.first(), false)); }); } menu.addItem((item) => { item.setTitle("Bring to Front"); item.setIcon("bring-to-front"); item.onClick(() => this.moveMaxLayers(canvas, nodes, true)); }); menu.addItem((item) => { item.setTitle("Send to Back"); item.setIcon("send-to-back"); item.onClick(() => this.moveMaxLayers(canvas, nodes, false)); }); if (nodes.some((node) => node.getData().zIndex !== void 0)) { menu.addItem((item) => { item.setTitle("Remove persistent z-index"); item.setIcon("pin-off"); item.onClick(() => this.removePersistentZIndexes(canvas, nodes)); }); } menu.addSeparator(); } moveOneLayer(canvas, selectedNode, forward) { const selectedNodeBBox = selectedNode.getBBox(); const collidingNodes = [...canvas.nodes.values()].filter((node) => BBoxHelper.isColliding(selectedNodeBBox, node.getBBox())).filter((node) => node !== selectedNode); const nearestZIndexNode = collidingNodes.sort((a, b) => forward ? a.zIndex - b.zIndex : b.zIndex - a.zIndex).filter((node) => forward ? node.zIndex > selectedNode.zIndex : node.zIndex < selectedNode.zIndex).first(); if (nearestZIndexNode === void 0) return; const targetZIndex = nearestZIndexNode.zIndex; this.setNodesZIndex([nearestZIndexNode], selectedNode.zIndex); this.setNodesZIndex([selectedNode], targetZIndex); } moveMaxLayers(canvas, selectedNodes, forward) { let targetZIndex = forward ? Math.max(...this.getAllZIndexes(canvas)) + 1 : Math.min(...this.getAllZIndexes(canvas)) - selectedNodes.length; this.setNodesZIndex(selectedNodes, targetZIndex); } removePersistentZIndexes(_canvas, nodes) { for (const node of nodes) node.setZIndex(void 0); } setNodesZIndex(nodes, zIndex) { const sortedNodes = nodes.sort((a, b) => a.zIndex - b.zIndex); for (let i = 0; i < sortedNodes.length; i++) { const node = sortedNodes[i]; const finalZIndex = zIndex + i; node.setZIndex(finalZIndex); } } getAllZIndexes(canvas) { return [...canvas.nodes.values()].map((n) => n.zIndex); } }; // src/canvas-extensions/better-readonly-canvas-extension.ts var BetterReadonlyCanvasExtension = class extends CanvasExtension { constructor() { super(...arguments); this.isMovingToBBox = false; } isEnabled() { return "betterReadonlyEnabled"; } init() { this.plugin.registerEvent(this.plugin.app.workspace.on( "advanced-canvas:popup-menu-created", (canvas) => this.updatePopupMenu(canvas) )); this.plugin.registerEvent(this.plugin.app.workspace.on( "advanced-canvas:viewport-changed:before", (canvas) => this.onBeforeViewPortChanged(canvas) )); this.plugin.registerEvent(this.plugin.app.workspace.on( "advanced-canvas:zoom-to-bbox:before", () => this.isMovingToBBox = true )); this.plugin.registerEvent(this.plugin.app.workspace.on( "advanced-canvas:readonly-changed", (canvas, _readonly) => { this.updatePopupMenu(canvas); this.updateLockedZoom(canvas); this.updateLockedPan(canvas); } )); this.plugin.registerEvent(this.plugin.app.workspace.on( "advanced-canvas:canvas-changed", (canvas) => this.addQuickSettings(canvas) )); } onBeforeViewPortChanged(canvas) { var _a, _b, _c, _d, _e, _f; if (this.isMovingToBBox) { this.isMovingToBBox = false; this.updateLockedZoom(canvas); this.updateLockedPan(canvas); return; } if (!canvas.readonly) return; if (this.plugin.settings.getSetting("disableZoom")) { canvas.zoom = (_a = canvas.lockedZoom) != null ? _a : canvas.zoom; canvas.tZoom = (_b = canvas.lockedZoom) != null ? _b : canvas.tZoom; } if (this.plugin.settings.getSetting("disablePan")) { canvas.x = (_c = canvas.lockedX) != null ? _c : canvas.x; canvas.tx = (_d = canvas.lockedX) != null ? _d : canvas.tx; canvas.y = (_e = canvas.lockedY) != null ? _e : canvas.y; canvas.ty = (_f = canvas.lockedY) != null ? _f : canvas.ty; } } addQuickSettings(canvas) { var _a; const settingsContainer = (_a = canvas.quickSettingsButton) == null ? void 0 : _a.parentElement; if (!settingsContainer) return; CanvasHelper.addControlMenuButton( settingsContainer, this.createToggle({ id: "disable-node-popup", label: "Disable node popup", icon: "arrow-up-right-from-circle", callback: () => this.updatePopupMenu(canvas) }, "disableNodePopup") ); CanvasHelper.addControlMenuButton( settingsContainer, this.createToggle({ id: "disable-zoom", label: "Disable zoom", icon: "zoom-in", callback: () => this.updateLockedZoom(canvas) }, "disableZoom") ); CanvasHelper.addControlMenuButton( settingsContainer, this.createToggle({ id: "disable-pan", label: "Disable pan", icon: "move", callback: () => this.updateLockedPan(canvas) }, "disablePan") ); } createToggle(menuOption, settingKey) { const toggle = CanvasHelper.createControlMenuButton({ ...menuOption, callback: () => (async () => { var _a; const newValue = !this.plugin.settings.getSetting(settingKey); await this.plugin.settings.setSetting({ [settingKey]: newValue }); toggle.dataset.toggled = this.plugin.settings.getSetting(settingKey).toString(); (_a = menuOption.callback) == null ? void 0 : _a.call(this); })() }); toggle.classList.add("show-while-readonly"); toggle.dataset.toggled = this.plugin.settings.getSetting(settingKey).toString(); return toggle; } updatePopupMenu(canvas) { const hidden = canvas.readonly && this.plugin.settings.getSetting("disableNodePopup"); canvas.menu.menuEl.style.visibility = hidden ? "hidden" : "visible"; } updateLockedZoom(canvas) { canvas.lockedZoom = canvas.tZoom; } updateLockedPan(canvas) { canvas.lockedX = canvas.tx; canvas.lockedY = canvas.ty; } }; // src/canvas-extensions/encapsulate-canvas-extension.ts var ENCAPSULATED_FILE_NODE_SIZE = { width: 300, height: 300 }; var EncapsulateCanvasExtension = class extends CanvasExtension { isEnabled() { return "canvasEncapsulationEnabled"; } init() { this.plugin.addCommand({ id: "encapsulate-selection", name: "Encapsulate selection", checkCallback: CanvasHelper.canvasCommand( this.plugin, (canvas) => !canvas.readonly && canvas.selection.size > 0, (canvas) => this.encapsulateSelection(canvas) ) }); this.plugin.registerEvent(this.plugin.app.workspace.on( "canvas:selection-menu", (menu, canvas) => { menu.addItem( (item) => item.setTitle("Encapsulate").setIcon("file-plus").onClick(() => this.encapsulateSelection(canvas)) ); } )); } async encapsulateSelection(canvas) { var _a, _b, _c, _d; const selection = canvas.getSelectionData(); const canvasSettings = this.plugin.app.internalPlugins.plugins.canvas.instance.options; const defaultNewCanvasLocation = canvasSettings.newFileLocation; let targetFolderPath = this.plugin.app.vault.getRoot().path; if (defaultNewCanvasLocation === "current") targetFolderPath = (_c = (_b = (_a = canvas.view.file) == null ? void 0 : _a.parent) == null ? void 0 : _b.path) != null ? _c : targetFolderPath; else if (defaultNewCanvasLocation === "folder") targetFolderPath = (_d = canvasSettings.newFileFolderPath) != null ? _d : targetFolderPath; const targetFilePath = await new FileNameModal( this.plugin.app, targetFolderPath, "canvas" ).awaitInput(); const newFileData = { nodes: selection.nodes, edges: selection.edges }; const file = await this.plugin.app.vault.create(targetFilePath, JSON.stringify(newFileData, null, 2)); for (const nodeData of selection.nodes) { const node = canvas.nodes.get(nodeData.id); if (node) canvas.removeNode(node); } canvas.createFileNode({ pos: { x: selection.center.x - ENCAPSULATED_FILE_NODE_SIZE.width / 2, y: selection.center.y - ENCAPSULATED_FILE_NODE_SIZE.height / 2 }, size: ENCAPSULATED_FILE_NODE_SIZE, file }); } }; // src/canvas-extensions/commands-canvas-extension.ts var DIRECTIONS = ["up", "down", "left", "right"]; var CommandsCanvasExtension = class extends CanvasExtension { isEnabled() { return "commandsFeatureEnabled"; } init() { this.plugin.addCommand({ id: "toggle-readonly", name: "Toggle readonly", checkCallback: CanvasHelper.canvasCommand( this.plugin, (_canvas) => true, (canvas) => canvas.setReadonly(!canvas.readonly) ) }); this.plugin.addCommand({ id: "create-text-node", name: "Create text node", checkCallback: CanvasHelper.canvasCommand( this.plugin, (canvas) => !canvas.readonly, (canvas) => this.createTextNode(canvas) ) }); this.plugin.addCommand({ id: "create-file-node", name: "Create file node", checkCallback: CanvasHelper.canvasCommand( this.plugin, (canvas) => !canvas.readonly, (canvas) => this.createFileNode(canvas) ) }); this.plugin.addCommand({ id: "select-all-edges", name: "Select all edges", checkCallback: CanvasHelper.canvasCommand( this.plugin, (_canvas) => true, (canvas) => canvas.updateSelection( () => canvas.selection = new Set(canvas.edges.values()) ) ) }); this.plugin.addCommand({ id: "zoom-to-selection", name: "Zoom to selection", checkCallback: CanvasHelper.canvasCommand( this.plugin, (canvas) => canvas.selection.size > 0, (canvas) => canvas.zoomToSelection() ) }); this.plugin.addCommand({ id: "zoom-to-fit", name: "Zoom to fit", checkCallback: CanvasHelper.canvasCommand( this.plugin, (_canvas) => true, (canvas) => canvas.zoomToFit() ) }); for (const direction of DIRECTIONS) { this.plugin.addCommand({ id: `clone-node-${direction}`, name: `Clone node ${direction}`, checkCallback: CanvasHelper.canvasCommand( this.plugin, (canvas) => { var _a; return !canvas.readonly && canvas.selection.size === 1 && ((_a = canvas.selection.values().next().value) == null ? void 0 : _a.getData().type) === "text"; }, (canvas) => this.cloneNode(canvas, direction) ) }); this.plugin.addCommand({ id: `expand-node-${direction}`, name: `Expand node ${direction}`, checkCallback: CanvasHelper.canvasCommand( this.plugin, (canvas) => !canvas.readonly && canvas.selection.size === 1, (canvas) => this.expandNode(canvas, direction) ) }); this.plugin.addCommand({ id: `navigate-${direction}`, name: `Navigate ${direction}`, checkCallback: CanvasHelper.canvasCommand( this.plugin, (canvas) => canvas.getSelectionData().nodes.length === 1, (canvas) => this.navigate(canvas, direction) ) }); } this.plugin.addCommand({ id: "flip-selection-horizontally", name: "Flip selection horizontally", checkCallback: CanvasHelper.canvasCommand( this.plugin, (canvas) => !canvas.readonly && canvas.selection.size > 0, (canvas) => this.flipSelection( canvas, true ) ) }); this.plugin.addCommand({ id: "flip-selection-vertically", name: "Flip selection vertically", checkCallback: CanvasHelper.canvasCommand( this.plugin, (canvas) => !canvas.readonly && canvas.selection.size > 0, (canvas) => this.flipSelection(canvas, false) ) }); this.plugin.addCommand({ id: "swap-nodes", name: "Swap nodes", checkCallback: CanvasHelper.canvasCommand( this.plugin, (canvas) => !canvas.readonly && canvas.getSelectionData().nodes.length === 2, (canvas) => { const selectedNodes = canvas.getSelectionData().nodes.map((nodeData) => canvas.nodes.get(nodeData.id)).filter((node) => node !== void 0); if (selectedNodes.length !== 2) return; const [nodeA, nodeB] = selectedNodes; const nodeAData = nodeA.getData(); const nodeBData = nodeB.getData(); nodeA.setData({ ...nodeAData, x: nodeBData.x, y: nodeBData.y, width: nodeBData.width, height: nodeBData.height }); nodeB.setData({ ...nodeBData, x: nodeAData.x, y: nodeAData.y, width: nodeAData.width, height: nodeAData.height }); canvas.pushHistory(canvas.getData()); } ) }); } createTextNode(canvas) { const size = canvas.config.defaultTextNodeDimensions; const pos = CanvasHelper.getCenterCoordinates(canvas, size); canvas.createTextNode({ pos, size }); } async createFileNode(canvas) { const size = canvas.config.defaultFileNodeDimensions; const pos = CanvasHelper.getCenterCoordinates(canvas, size); const file = await new FileSelectModal(this.plugin.app, void 0, true).awaitInput(); canvas.createFileNode({ pos, size, file }); } cloneNode(canvas, cloneDirection) { const sourceNode = canvas.selection.values().next().value; if (!sourceNode) return; const sourceNodeData = sourceNode.getData(); const nodeMargin = this.plugin.settings.getSetting("cloneNodeMargin"); const offset = { x: (sourceNode.width + nodeMargin) * (cloneDirection === "left" ? -1 : cloneDirection === "right" ? 1 : 0), y: (sourceNode.height + nodeMargin) * (cloneDirection === "up" ? -1 : cloneDirection === "down" ? 1 : 0) }; const clonedNode = canvas.createTextNode({ pos: { x: sourceNode.x + offset.x, y: sourceNode.y + offset.y }, size: { width: sourceNode.width, height: sourceNode.height } }); clonedNode.setData({ ...clonedNode.getData(), color: sourceNodeData.color, styleAttributes: sourceNodeData.styleAttributes }); if (this.plugin.settings.getSetting("zoomToClonedNode")) canvas.zoomToBbox(clonedNode.getBBox()); } expandNode(canvas, expandDirection) { const node = canvas.selection.values().next().value; if (!node) return; const expandNodeStepSize = this.plugin.settings.getSetting("expandNodeStepSize"); const expand = { x: expandDirection === "left" ? -1 : expandDirection === "right" ? 1 : 0, y: expandDirection === "up" ? -1 : expandDirection === "down" ? 1 : 0 }; node.setData({ ...node.getData(), width: node.width + expand.x * expandNodeStepSize, height: node.height + expand.y * expandNodeStepSize }); } flipSelection(canvas, horizontally) { const selectionData = canvas.getSelectionData(); if (selectionData.nodes.length === 0) return; const nodeIds = /* @__PURE__ */ new Set(); for (const nodeData of selectionData.nodes) { nodeIds.add(nodeData.id); const node = canvas.nodes.get(nodeData.id); if (!node) continue; const newX = horizontally ? 2 * selectionData.center.x - nodeData.x - nodeData.width : nodeData.x; const newY = horizontally ? nodeData.y : 2 * selectionData.center.y - nodeData.y - nodeData.height; node.setData({ ...nodeData, x: newX, y: newY }); } for (const edge of canvas.edges.values()) { const edgeData = edge.getData(); let newFromSide = edgeData.fromSide; if (nodeIds.has(edgeData.fromNode) && BBoxHelper.isHorizontal(edgeData.fromSide) === horizontally) newFromSide = BBoxHelper.getOppositeSide(edgeData.fromSide); let newToSide = edgeData.toSide; if (nodeIds.has(edgeData.toNode) && BBoxHelper.isHorizontal(edgeData.toSide) === horizontally) newToSide = BBoxHelper.getOppositeSide(edgeData.toSide); edge.setData({ ...edgeData, fromSide: newFromSide, toSide: newToSide }); } canvas.pushHistory(canvas.getData()); } navigate(canvas, direction) { const node = this.getNextNode(canvas, direction); if (!node) return; canvas.updateSelection(() => { canvas.selection = /* @__PURE__ */ new Set([node]); }); } getNextNode(canvas, direction) { var _a; const selectedNodeData = (_a = canvas.getSelectionData().nodes) == null ? void 0 : _a.first(); if (!selectedNodeData) return; const selectedNodeBBox = { minX: selectedNodeData.x, minY: selectedNodeData.y, maxX: selectedNodeData.x + selectedNodeData.width, maxY: selectedNodeData.y + selectedNodeData.height }; const possibleTargetNodes = Array.from(canvas.nodes.values()).filter((node) => { const nodeData = node.getData(); return nodeData.id !== selectedNodeData.id && (nodeData.type === "text" || nodeData.type === "file"); }); const closestNode = possibleTargetNodes.reduce((closestNode2, node) => { const nodeBBox = node.getBBox(); const isInVerticalRange = selectedNodeBBox.minY <= nodeBBox.maxY && selectedNodeBBox.maxY >= nodeBBox.minY; const isInHorizontalRange = selectedNodeBBox.minX <= nodeBBox.maxX && selectedNodeBBox.maxX >= nodeBBox.minX; if (["up", "down"].includes(direction) && !isInHorizontalRange) return closestNode2; if (["left", "right"].includes(direction) && !isInVerticalRange) return closestNode2; let distance = -1; switch (direction) { case "up": distance = selectedNodeBBox.minY - nodeBBox.maxY; break; case "down": distance = nodeBBox.minY - selectedNodeBBox.maxY; break; case "left": distance = selectedNodeBBox.minX - nodeBBox.maxX; break; case "right": distance = nodeBBox.minX - selectedNodeBBox.maxX; break; } if (distance < 0) return closestNode2; if (!closestNode2) return { node, distance }; if (distance < closestNode2.distance) return { node, distance }; if (distance === closestNode2.distance) { const selectedNodeCenter = { x: selectedNodeData.x + selectedNodeData.width / 2, y: selectedNodeData.y + selectedNodeData.height / 2 }; const closestNodeCenter = { x: closestNode2.node.x + closestNode2.node.width / 2, y: closestNode2.node.y + closestNode2.node.height / 2 }; const nodeCenter = { x: node.x + node.width / 2, y: node.y + node.height / 2 }; const closestNodeDistance = Math.sqrt( Math.pow(selectedNodeCenter.x - closestNodeCenter.x, 2) + Math.pow(selectedNodeCenter.y - closestNodeCenter.y, 2) ); const nodeDistance = Math.sqrt( Math.pow(selectedNodeCenter.x - nodeCenter.x, 2) + Math.pow(selectedNodeCenter.y - nodeCenter.y, 2) ); if (nodeDistance < closestNodeDistance) return { node, distance }; } return closestNode2; }, null); return closestNode == null ? void 0 : closestNode.node; } }; // src/canvas-extensions/auto-resize-node-canvas-extension.ts var AutoResizeNodeCanvasExtension = class extends CanvasExtension { isEnabled() { return "autoResizeNodeFeatureEnabled"; } init() { this.plugin.registerEvent(this.plugin.app.workspace.on( "advanced-canvas:node-created", (canvas, node) => this.onNodeCreated(canvas, node) )); this.plugin.registerEvent(this.plugin.app.workspace.on( "advanced-canvas:popup-menu-created", (canvas) => this.onPopupMenuCreated(canvas) )); this.plugin.registerEvent(this.plugin.app.workspace.on( "advanced-canvas:node-editing-state-changed", (canvas, node, editing) => this.onNodeEditingStateChanged(canvas, node, editing) )); this.plugin.registerEvent(this.plugin.app.workspace.on( "advanced-canvas:node-text-content-changed", (canvas, node, viewUpdate) => this.onNodeTextContentChanged(canvas, node, viewUpdate.view.dom) )); } isValidNodeType(nodeData) { return nodeData.type === "text" || nodeData.type === "file" && nodeData.file.endsWith(".md"); } onNodeCreated(_canvas, node) { const autoResizeNodeEnabledByDefault = this.plugin.settings.getSetting("autoResizeNodeEnabledByDefault"); if (!autoResizeNodeEnabledByDefault) return; const nodeData = node.getData(); if (nodeData.type !== "text" && nodeData.type !== "file") return; node.setData({ ...node.getData(), dynamicHeight: true }); } onPopupMenuCreated(canvas) { if (canvas.readonly) return; const selectedNodes = canvas.getSelectionData().nodes.filter((nodeData) => this.isValidNodeType(nodeData)).map((nodeData) => canvas.nodes.get(nodeData.id)).filter((node) => node !== void 0); if (selectedNodes.length === 0) return; const autoResizeHeightEnabled = selectedNodes.some((node) => node.getData().dynamicHeight); CanvasHelper.addPopupMenuOption( canvas, CanvasHelper.createPopupMenuOption({ id: "auto-resize-height", label: autoResizeHeightEnabled ? "Disable auto-resize" : "Enable auto-resize", icon: autoResizeHeightEnabled ? "scan-text" : "lock", callback: () => this.toggleAutoResizeHeightEnabled(canvas, selectedNodes, autoResizeHeightEnabled) }) ); } toggleAutoResizeHeightEnabled(canvas, nodes, autoResizeHeight) { nodes.forEach((node) => node.setData({ ...node.getData(), dynamicHeight: !autoResizeHeight })); this.onPopupMenuCreated(canvas); } canBeResized(node) { const nodeData = node.getData(); return nodeData.dynamicHeight; } async onNodeEditingStateChanged(_canvas, node, editing) { if (!this.isValidNodeType(node.getData())) return; if (!this.canBeResized(node)) return; await sleep(10); if (editing) { this.onNodeTextContentChanged(_canvas, node, node.child.editMode.cm.dom); return; } const renderedMarkdownContainer = node.nodeEl.querySelector(".markdown-preview-view.markdown-rendered"); if (!renderedMarkdownContainer) return; renderedMarkdownContainer.style.height = "min-content"; let newHeight = renderedMarkdownContainer.clientHeight; renderedMarkdownContainer.style.removeProperty("height"); this.setNodeHeight(node, newHeight); } async onNodeTextContentChanged(_canvas, node, dom) { if (!this.isValidNodeType(node.getData())) return; if (!this.canBeResized(node)) return; const cmScroller = dom.querySelector(".cm-scroller"); if (!cmScroller) return; cmScroller.style.height = "min-content"; const newHeight = cmScroller.scrollHeight; cmScroller.style.removeProperty("height"); this.setNodeHeight(node, newHeight); } setNodeHeight(node, height) { if (height === 0) return; const maxHeight = this.plugin.settings.getSetting("autoResizeNodeMaxHeight"); if (maxHeight != -1 && height > maxHeight) height = maxHeight; const nodeData = node.getData(); height = Math.max(height, node.canvas.config.minContainerDimension); if (this.plugin.settings.getSetting("autoResizeNodeSnapToGrid")) height = Math.ceil(height / CanvasHelper.GRID_SIZE) * CanvasHelper.GRID_SIZE; node.setData({ ...nodeData, height }); } }; // src/canvas-extensions/portals-canvas-extension.ts var import_obsidian13 = require("obsidian"); var PORTAL_PADDING = 50; var MIN_OPEN_PORTAL_SIZE = { width: 200, height: 200 }; var PortalsCanvasExtension = class _PortalsCanvasExtension extends CanvasExtension { isEnabled() { return "portalsFeatureEnabled"; } init() { this.plugin.registerEvent(this.plugin.app.vault.on("modify", (file) => { for (const canvas of this.plugin.getCanvases()) this.onFileModified(canvas, file); })); this.plugin.registerEvent(this.plugin.app.workspace.on( "advanced-canvas:popup-menu-created", (canvas) => this.onPopupMenu(canvas) )); this.plugin.registerEvent(this.plugin.app.workspace.on( "advanced-canvas:node-removed", (canvas, node) => this.onNodeRemoved(canvas, node) )); this.plugin.registerEvent(this.plugin.app.workspace.on( "advanced-canvas:node-moved", (canvas, node, _keyboard) => this.onNodeMoved(canvas, node) )); this.plugin.registerEvent(this.plugin.app.workspace.on( "advanced-canvas:node-resized", (canvas, node) => this.onNodeResized(canvas, node) )); this.plugin.registerEvent(this.plugin.app.workspace.on( "advanced-canvas:dragging-state-changed", (canvas, startedDragging) => this.onDraggingStateChanged(canvas, startedDragging) )); this.plugin.registerEvent(this.plugin.app.workspace.on( "advanced-canvas:containing-nodes-requested", (canvas, bbox, nodes) => this.onContainingNodesRequested(canvas, bbox, nodes) )); this.plugin.registerEvent(this.plugin.app.workspace.on( "advanced-canvas:edge-connection-try-dragging:before", (canvas, edge, event, cancelRef) => this.onEdgeConnectionTryDraggingBefore(canvas, edge, event, cancelRef) )); this.plugin.registerEvent(this.plugin.app.workspace.on( "advanced-canvas:edge-connection-dragging:after", (canvas, edge, event, newEdge, side, previousEnds) => this.onEdgeConnectionDraggingAfter(canvas, edge, event, newEdge, side, previousEnds) )); this.plugin.registerEvent(this.plugin.app.workspace.on( "advanced-canvas:selection-changed", (canvas, oldSelection, updateSelection) => this.onSelectionChanged(canvas, oldSelection, updateSelection) )); this.plugin.registerEvent(this.plugin.app.workspace.on( "advanced-canvas:data-requested", (canvas, data) => this.onGetData(canvas, data) )); this.plugin.registerEvent(this.plugin.app.workspace.on( "advanced-canvas:data-loaded:before", (canvas, data, setData) => { this.onSetData(canvas, data).then((newData) => { if (newData.nodes.length === data.nodes.length && newData.edges.length === data.edges.length) return; setData(newData); }); } )); } onFileModified(canvas, file) { const isAffected = Object.values(canvas.nodes).filter( (nodeData) => nodeData.getData().type === "file" && nodeData.currentPortalFile === file.path ).length > 0; if (!isAffected) return; canvas.setData(canvas.getData()); canvas.history.current--; canvas.history.data.pop(); } onContainingNodesRequested(_canvas, _bbox, nodes) { const filteredNodes = nodes.filter((node) => !_PortalsCanvasExtension.isPortalElement(node)); nodes.splice(0, nodes.length, ...filteredNodes); } onSelectionChanged(canvas, _oldSelection, updateSelection) { updateSelection(() => { const updatedSelection = Array.from(canvas.selection).filter((canvasElement) => !_PortalsCanvasExtension.isPortalElement(canvasElement)); canvas.selection = new Set(updatedSelection); }); } onDraggingStateChanged(canvas, startedDragging) { if (!startedDragging) return; if (!canvas.getSelectionData().nodes.some((node) => node.type === "file" && node.portal)) return; const objectSnappingEnabled = canvas.options.snapToObjects; if (!objectSnappingEnabled) return; canvas.toggleObjectSnapping(false); const dragEndEventRef = this.plugin.app.workspace.on( "advanced-canvas:dragging-state-changed", (canvas2, startedDragging2) => { if (startedDragging2) return; canvas2.toggleObjectSnapping(objectSnappingEnabled); this.plugin.app.workspace.offref(dragEndEventRef); } ); this.plugin.registerEvent(dragEndEventRef); } onNodeMoved(canvas, portalNode) { const portalNodeData = portalNode.getData(); if (portalNodeData.type !== "file" || !portalNodeData.isPortalLoaded) return; const nestedNodes = this.getContainingNodes(canvas, portalNode); const containingNodesBBox = CanvasHelper.getBBox(nestedNodes); const portalOffset = { x: portalNodeData.x - containingNodesBBox.minX + PORTAL_PADDING, y: portalNodeData.y - containingNodesBBox.minY + PORTAL_PADDING }; for (const nestedNode of nestedNodes) { const nestedNodeData = nestedNode.getData(); nestedNode.setData({ ...nestedNodeData, x: nestedNodeData.x + portalOffset.x, y: nestedNodeData.y + portalOffset.y }); } } onNodeResized(_canvas, portalNode) { const portalNodeData = portalNode.getData(); if (portalNodeData.type !== "file" || !portalNodeData.isPortalLoaded) return; portalNode.setData({ ...portalNodeData, x: portalNode.prevX ? portalNode.prevX : portalNodeData.x, y: portalNode.prevY ? portalNode.prevY : portalNodeData.y, width: portalNode.prevWidth ? portalNode.prevWidth : portalNodeData.width, height: portalNode.prevHeight ? portalNode.prevHeight : portalNodeData.height }); } onNodeRemoved(canvas, portalNode) { const portalNodeData = portalNode.getData(); if (portalNodeData.type !== "file" || !portalNodeData.portal) return; for (const node of this.getContainingNodes(canvas, portalNode, false)) canvas.removeNode(node); for (const edge of this.getContainingEdges(canvas, portalNode, false)) canvas.removeEdge(edge); } onEdgeConnectionTryDraggingBefore(_canvas, edge, _event, cancelRef) { if (!_PortalsCanvasExtension.isPortalElement(edge)) return; cancelRef.value = true; new import_obsidian13.Notice("Updating edges from portals is not supported yet."); } onEdgeConnectionDraggingAfter(canvas, edge, _event, _newEdge, _side, _previousEnds) { if (_PortalsCanvasExtension.isPortalElement(edge)) return; if (!_PortalsCanvasExtension.isPortalElement(edge.from.node) || !_PortalsCanvasExtension.isPortalElement(edge.to.node)) return; canvas.removeEdge(edge); new import_obsidian13.Notice("Creating edges with both ends in portals are not supported yet."); } onPopupMenu(canvas) { if (canvas.readonly) return; const selectedFileNodes = canvas.getSelectionData().nodes.map((nodeData) => { var _a; const node = canvas.nodes.get(nodeData.id); if (!node) return null; if (nodeData.type !== "file") return null; if (((_a = node.file) == null ? void 0 : _a.extension) === "canvas") return node; if (nodeData.portal) this.setPortalOpen(canvas, node, false); return null; }).filter((node) => node !== null); if (selectedFileNodes.length !== 1) return; const portalNode = selectedFileNodes.first(); const portalNodeData = portalNode.getData(); if (portalNodeData.portal && portalNodeData.file !== portalNode.currentPortalFile) this.setPortalOpen(canvas, portalNode, true); CanvasHelper.addPopupMenuOption( canvas, CanvasHelper.createPopupMenuOption({ id: "toggle-portal", label: portalNodeData.portal ? "Close portal" : "Open portal", icon: portalNodeData.portal ? "door-open" : "door-closed", callback: () => { this.setPortalOpen(canvas, portalNode, !portalNodeData.portal); this.onPopupMenu(canvas); } }) ); } setPortalOpen(canvas, portalNode, open) { const portalNodeData = portalNode.getData(); portalNode.setData({ ...portalNodeData, portal: open }); portalNode.currentPortalFile = open ? portalNodeData.file : void 0; canvas.setData(canvas.getData()); } // Remove all edges and nodes from portals onGetData(_canvas, data) { data.nodes = data.nodes.filter((nodeData) => _PortalsCanvasExtension.getNestedIds(nodeData.id).length === 1); for (const nodeData of data.nodes) delete nodeData.isPortalLoaded; const portalsIdMap = new Map( data.nodes.filter((nodeData) => nodeData.portal).map((nodeData) => [nodeData.id, nodeData]) ); data.edges = data.edges.filter((edgeData) => { var _a; if (_PortalsCanvasExtension.getNestedIds(edgeData.fromNode).length > 1) return false; const isFromNodeFromPortal = _PortalsCanvasExtension.getNestedIds(edgeData.fromNode).length > 1; const isToNodeFromPortal = _PortalsCanvasExtension.getNestedIds(edgeData.toNode).length > 1; if (!isFromNodeFromPortal && !isToNodeFromPortal) return true; if (isFromNodeFromPortal && isToNodeFromPortal) return false; const targetPortalId = this.getParentPortalId(isFromNodeFromPortal ? edgeData.fromNode : edgeData.toNode); const targetPortalData = portalsIdMap.get(targetPortalId); if (!targetPortalData) return false; (_a = targetPortalData.interdimensionalEdges) != null ? _a : targetPortalData.interdimensionalEdges = []; targetPortalData.interdimensionalEdges.push(edgeData); return false; }); } // Add all edges and nodes from portals async onSetData(canvas, dataRef) { const data = JSON.parse(JSON.stringify(dataRef)); const addedData = await Promise.all(data.nodes.map((nodeData) => this.tryOpenPortal(canvas, nodeData))); for (const newData of addedData) { data.nodes.push(...newData.nodes); data.edges.push(...newData.edges); } for (const nodeData of data.nodes) { if (nodeData.type !== "file" || !nodeData.isPortalLoaded) continue; const interdimensionalEdges = nodeData.interdimensionalEdges; if (!interdimensionalEdges) continue; for (const edge of interdimensionalEdges) data.edges.push(edge); } return data; } async tryOpenPortal(canvas, portalNodeData, nestedPortalFiles = /* @__PURE__ */ new Set()) { const addedData = { nodes: [], edges: [] }; if (portalNodeData.type !== "file" || !portalNodeData.portal) return addedData; if (portalNodeData.file === canvas.view.file.path) return addedData; if (nestedPortalFiles.has(portalNodeData.file)) return addedData; nestedPortalFiles.add(portalNodeData.file); const portalFile = this.plugin.app.vault.getAbstractFileByPath(portalNodeData.file); if (!(portalFile instanceof import_obsidian13.TFile) || portalFile.extension !== "canvas") return addedData; const portalFileDataString = await this.plugin.app.vault.cachedRead(portalFile); if (portalFileDataString === "") return addedData; const portalFileData = JSON.parse(portalFileDataString); if (!portalFileData) return addedData; portalNodeData.isPortalLoaded = true; const sourceMinCoordinates = CanvasHelper.getBBox(portalFileData.nodes); const portalOffset = { x: portalNodeData.x - sourceMinCoordinates.minX + PORTAL_PADDING, y: portalNodeData.y - sourceMinCoordinates.minY + PORTAL_PADDING }; for (const nodeDataFromPortal of portalFileData.nodes) { const newNodeId = `${portalNodeData.id}-${nodeDataFromPortal.id}`; const addedNode = { ...nodeDataFromPortal, id: newNodeId, x: nodeDataFromPortal.x + portalOffset.x, y: nodeDataFromPortal.y + portalOffset.y }; addedData.nodes.push(addedNode); const nestedNodes = await this.tryOpenPortal(canvas, addedNode, nestedPortalFiles); addedData.nodes.push(...nestedNodes.nodes); addedData.edges.push(...nestedNodes.edges); } for (const edgeDataFromPortal of portalFileData.edges) { const newEdgeId = `${portalNodeData.id}-${edgeDataFromPortal.id}`; const fromNodeId = `${portalNodeData.id}-${edgeDataFromPortal.fromNode}`; const toNodeId = `${portalNodeData.id}-${edgeDataFromPortal.toNode}`; addedData.edges.push({ ...edgeDataFromPortal, id: newEdgeId, fromNode: fromNodeId, toNode: toNodeId }); } const targetSize = this.getPortalSize(CanvasHelper.getBBox(addedData.nodes)); portalNodeData.width = targetSize.width; portalNodeData.height = targetSize.height; return addedData; } // Helper functions getPortalSize(sourceBBox) { const sourceSize = { width: sourceBBox.maxX - sourceBBox.minX, height: sourceBBox.maxY - sourceBBox.minY }; const targetSize = { width: Math.max(sourceSize.width + PORTAL_PADDING * 2, MIN_OPEN_PORTAL_SIZE.width), height: Math.max(sourceSize.height + PORTAL_PADDING * 2, MIN_OPEN_PORTAL_SIZE.height) }; if (!Number.isFinite(targetSize.width)) targetSize.width = MIN_OPEN_PORTAL_SIZE.width; if (!Number.isFinite(targetSize.height)) targetSize.height = MIN_OPEN_PORTAL_SIZE.height; return targetSize; } getContainingNodes(canvas, portalNode, directChildren = true) { return Array.from(canvas.nodes.values()).filter((node) => this.isChildOfPortal(portalNode.getData(), node.getData(), directChildren)); } getContainingEdges(canvas, portalNode, directChildren = true) { return Array.from(canvas.edges.values()).filter((edge) => this.isChildOfPortal(portalNode.getData(), edge.getData(), directChildren)); } getParentPortalId(elementId) { const nestedIds = _PortalsCanvasExtension.getNestedIds(elementId); if (nestedIds.length < 2) return void 0; return nestedIds.slice(0, -1).join("-"); } static getNestedIds(id) { return id.split("-"); } static isPortalElement(canvasElement) { return this.getNestedIds(canvasElement.id).length > 1; } isChildOfPortal(portal, canvasElement, directChild = true) { return canvasElement.id !== portal.id && // Not the portal itself canvasElement.id.startsWith(portal.id) && // Is a child of the portal (!directChild || _PortalsCanvasExtension.getNestedIds(canvasElement.id).length === _PortalsCanvasExtension.getNestedIds(portal.id).length + 1); } }; // src/canvas-extensions/frontmatter-control-button-canvas-extension.ts var import_obsidian14 = require("obsidian"); var FrontmatterControlButtonCanvasExtension = class extends CanvasExtension { isEnabled() { return "canvasMetadataCompatibilityEnabled"; } init() { this.plugin.registerEvent(this.plugin.app.workspace.on( "advanced-canvas:canvas-changed", (canvas) => this.addQuickSettings(canvas) )); } addQuickSettings(canvas) { var _a; if (!canvas) return; const settingsContainer = (_a = canvas.quickSettingsButton) == null ? void 0 : _a.parentElement; if (!settingsContainer) return; CanvasHelper.addControlMenuButton( settingsContainer, CanvasHelper.createControlMenuButton({ id: "properties-button", icon: "info", label: "Properties", callback: () => { var _a2; const propertiesPlugin = this.plugin.app.internalPlugins.plugins["properties"]; if (!(propertiesPlugin == null ? void 0 : propertiesPlugin._loaded)) { new import_obsidian14.Notice(`Core plugin "Properties" was not found or isn't enabled.`); return; } let propertiesLeaf = (_a2 = this.plugin.app.workspace.getLeavesOfType("file-properties").first()) != null ? _a2 : null; if (!propertiesLeaf) { propertiesLeaf = this.plugin.app.workspace.getRightLeaf(false); propertiesLeaf == null ? void 0 : propertiesLeaf.setViewState({ type: "file-properties" }); } if (propertiesLeaf) this.plugin.app.workspace.revealLeaf(propertiesLeaf); } }) ); } }; // src/canvas-extensions/better-default-settings-canvas-extension.ts var BetterDefaultSettingsCanvasExtension = class extends CanvasExtension { isEnabled() { return true; } init() { this.modifyCanvasSettings(this.plugin.getCurrentCanvas()); this.plugin.registerEvent(this.plugin.app.workspace.on( "advanced-canvas:settings-changed", () => this.modifyCanvasSettings(this.plugin.getCurrentCanvas()) )); this.plugin.registerEvent(this.plugin.app.workspace.on( "advanced-canvas:canvas-changed", (canvas) => this.modifyCanvasSettings(canvas) )); this.plugin.registerEvent(this.plugin.app.workspace.on( "advanced-canvas:double-click", (canvas, event, preventDefault) => this.onDoubleClick(canvas, event, preventDefault) )); this.plugin.registerEvent(this.plugin.app.workspace.on( "advanced-canvas:node-created", (canvas, node) => { this.enforceNodeGridAlignment(canvas, node); this.applyDefaultNodeStyles(canvas, node); } )); this.plugin.registerEvent(this.plugin.app.workspace.on( "advanced-canvas:edge-created", (canvas, edge) => this.applyDefaultEdgeStyles(canvas, edge) )); this.plugin.registerEvent(this.plugin.app.workspace.on( "advanced-canvas:node-resized", (canvas, node) => this.enforceMaxNodeWidth(canvas, node) )); } modifyCanvasSettings(canvas) { if (!canvas) return; const defaultTextNodeDimensionsArray = this.plugin.settings.getSetting("defaultTextNodeDimensions"); canvas.config.defaultTextNodeDimensions = { width: defaultTextNodeDimensionsArray[0], height: defaultTextNodeDimensionsArray[1] }; const defaultFileNodeDimensionsArray = this.plugin.settings.getSetting("defaultFileNodeDimensions"); canvas.config.defaultFileNodeDimensions = { width: defaultFileNodeDimensionsArray[0], height: defaultFileNodeDimensionsArray[1] }; canvas.config.minContainerDimension = this.plugin.settings.getSetting("minNodeSize"); } async onDoubleClick(canvas, event, preventDefault) { if (event.defaultPrevented || event.target !== canvas.wrapperEl || canvas.isDragging || canvas.readonly) return; preventDefault.value = true; let pos = canvas.posFromEvt(event); switch (this.plugin.settings.getSetting("nodeTypeOnDoubleClick")) { case "file": const file = await new FileSelectModal(this.plugin.app, void 0, true).awaitInput(); canvas.createFileNode({ pos, position: "center", file }); break; default: canvas.createTextNode({ pos, position: "center" }); break; } } enforceNodeGridAlignment(_canvas, node) { if (!this.plugin.settings.getSetting("alignNewNodesToGrid")) return; const nodeData = node.getData(); node.setData({ ...nodeData, x: CanvasHelper.alignToGrid(nodeData.x), y: CanvasHelper.alignToGrid(nodeData.y) }); } applyDefaultNodeStyles(_canvas, node) { const nodeData = node.getData(); if (nodeData.type !== "text") return; node.setData({ ...nodeData, styleAttributes: { ...nodeData.styleAttributes, ...this.plugin.settings.getSetting("defaultTextNodeStyleAttributes") } }); } async applyDefaultEdgeStyles(canvas, edge) { const edgeData = edge.getData(); edge.setData({ ...edgeData, styleAttributes: { ...edgeData.styleAttributes, ...this.plugin.settings.getSetting("defaultEdgeStyleAttributes") } }); if (canvas.canvasEl.hasClass("is-connecting")) { await new Promise((resolve) => { new MutationObserver(() => { if (!canvas.canvasEl.hasClass("is-connecting")) resolve(); }).observe(canvas.canvasEl, { attributes: true, attributeFilter: ["class"] }); }); } const lineDirection = this.plugin.settings.getSetting("defaultEdgeLineDirection"); edge.setData({ ...edge.getData(), fromEnd: lineDirection === "bidirectional" ? "arrow" : "none", toEnd: lineDirection === "nondirectional" ? "none" : "arrow" }); } enforceMaxNodeWidth(_canvas, node) { const maxNodeWidth = this.plugin.settings.getSetting("maxNodeWidth"); if (maxNodeWidth <= 0) return; const nodeData = node.getData(); if (nodeData.type !== "text" && nodeData.type !== "file" || nodeData.portal) return; if (nodeData.width <= maxNodeWidth) return; node.setData({ ...nodeData, x: node.prevX !== void 0 ? node.prevX : nodeData.x, // Reset the position to the previous value width: maxNodeWidth }); } }; // src/canvas-extensions/color-palette-canvas-extension.ts var DEFAULT_COLORS_COUNT = 6; var CUSTOM_COLORS_MOD_STYLES_ID = "mod-custom-colors"; var ColorPaletteCanvasExtension = class extends CanvasExtension { constructor() { super(...arguments); this.observer = null; } isEnabled() { return true; } init() { this.plugin.registerEvent(this.plugin.app.workspace.on( "window-open", (_win, _window) => this.updateCustomColorModStyleClasses() )); this.plugin.registerEvent(this.plugin.app.workspace.on( "css-change", () => this.updateCustomColorModStyleClasses() )); this.updateCustomColorModStyleClasses(); this.plugin.registerEvent(this.plugin.app.workspace.on( "advanced-canvas:popup-menu-created", (canvas) => this.patchColorSelection(canvas) )); this.plugin.register(() => { var _a; return (_a = this.observer) == null ? void 0 : _a.disconnect(); }); } updateCustomColorModStyleClasses() { var _a; const customCss = this.getCustomColors().map((colorId) => ` .mod-canvas-color-${colorId} { --canvas-color: var(--canvas-color-${colorId}); } `).join(""); for (const win of this.plugin.windowsManager.windows) { const doc = win.document; (_a = doc.getElementById(CUSTOM_COLORS_MOD_STYLES_ID)) == null ? void 0 : _a.remove(); const customColorModStyle = doc.createElement("style"); customColorModStyle.id = CUSTOM_COLORS_MOD_STYLES_ID; doc.head.appendChild(customColorModStyle); customColorModStyle.textContent = customCss; } } patchColorSelection(canvas) { if (this.observer) this.observer.disconnect(); this.observer = new MutationObserver((mutations) => { const colorMenuOpened = mutations.some( (mutation) => Object.values(mutation.addedNodes).some( (node) => node instanceof HTMLElement && node.classList.contains("canvas-submenu") && Object.values(node.childNodes).some( (node2) => node2 instanceof HTMLElement && node2.classList.contains("canvas-color-picker-item") ) ) ); if (!colorMenuOpened) return; const submenu = canvas.menu.menuEl.querySelector(".canvas-submenu"); if (!submenu) return; const currentNodeColor = canvas.getSelectionData().nodes.map((node) => node.color).last(); for (const colorId of this.getCustomColors()) { const customColorMenuItem = this.createColorMenuItem(canvas, colorId); if (currentNodeColor === colorId) customColorMenuItem.classList.add("is-active"); submenu.insertBefore(customColorMenuItem, submenu.lastChild); } }); this.observer.observe(canvas.menu.menuEl, { childList: true }); } createColorMenuItem(canvas, colorId) { const menuItem = document.createElement("div"); menuItem.classList.add("canvas-color-picker-item"); menuItem.classList.add(`mod-canvas-color-${colorId}`); menuItem.addEventListener("click", () => { menuItem.classList.add("is-active"); for (const item of canvas.selection) { item.setColor(colorId); } canvas.requestSave(); }); return menuItem; } getCustomColors() { const colors = []; while (true) { const colorId = (DEFAULT_COLORS_COUNT + colors.length + 1).toString(); if (!getComputedStyle(document.body).getPropertyValue(`--canvas-color-${colorId}`)) break; colors.push(colorId); } return colors; } }; // src/canvas-extensions/collapsible-groups-canvas-extension.ts var import_obsidian15 = require("obsidian"); var CollapsibleGroupsCanvasExtension = class extends CanvasExtension { isEnabled() { return "collapsibleGroupsFeatureEnabled"; } init() { this.plugin.registerEvent(this.plugin.app.workspace.on( "advanced-canvas:node-changed", (canvas, node) => this.onNodeChanged(canvas, node) )); this.plugin.registerEvent(this.plugin.app.workspace.on( "advanced-canvas:node-bbox-requested", (canvas, node, bbox) => this.onNodeBBoxRequested(canvas, node, bbox) )); this.plugin.registerEvent(this.plugin.app.workspace.on( "advanced-canvas:copy", (canvas, selectionData) => this.onCopy(canvas, selectionData) )); this.plugin.registerEvent(this.plugin.app.workspace.on( "advanced-canvas:data-requested", (_canvas, data) => this.expandAllCollapsedNodes(data) )); this.plugin.registerEvent(this.plugin.app.workspace.on( "advanced-canvas:data-loaded:before", (_canvas, data, _setData) => this.collapseNodes(data) )); } onNodeChanged(canvas, groupNode) { var _a, _b; const groupNodeData = groupNode.getData(); if (groupNodeData.type !== "group") return; (_a = groupNode.collapseEl) == null ? void 0 : _a.remove(); const collapseEl = document.createElement("span"); collapseEl.className = "collapse-button"; (0, import_obsidian15.setIcon)(collapseEl, groupNodeData.collapsed ? "plus-circle" : "minus-circle"); collapseEl.onclick = () => { const groupNodeData2 = groupNode.getData(); this.setCollapsed(canvas, groupNode, groupNodeData2.collapsed ? void 0 : true); canvas.markMoved(groupNode); }; groupNode.collapseEl = collapseEl; (_b = groupNode.labelEl) == null ? void 0 : _b.insertAdjacentElement("afterend", collapseEl); } onCopy(_canvas, selectionData) { for (const collapsedGroupData of selectionData.nodes) { if (collapsedGroupData.type !== "group" || !collapsedGroupData.collapsed || !collapsedGroupData.collapsedData) continue; selectionData.nodes.push(...collapsedGroupData.collapsedData.nodes.map((nodeData) => ({ ...nodeData, // Restore the relative position of the node to the group x: nodeData.x + collapsedGroupData.x, y: nodeData.y + collapsedGroupData.y }))); selectionData.edges.push(...collapsedGroupData.collapsedData.edges); } } setCollapsed(canvas, groupNode, collapsed) { groupNode.setData({ ...groupNode.getData(), collapsed }); canvas.setData(canvas.getData()); canvas.history.current--; canvas.pushHistory(canvas.getData()); } onNodeBBoxRequested(canvas, node, bbox) { var _a, _b; const nodeData = node.getData(); if (nodeData.type !== "group" || !nodeData.collapsed) return; const collapseElBBox = (_a = node.collapseEl) == null ? void 0 : _a.getBoundingClientRect(); if (!collapseElBBox) return; const labelElBBox = (_b = node.labelEl) == null ? void 0 : _b.getBoundingClientRect(); if (!labelElBBox) return; const minPos = canvas.posFromClient({ x: collapseElBBox.left, y: collapseElBBox.top }); const maxPos = canvas.posFromClient({ x: labelElBBox.right, y: collapseElBBox.bottom }); bbox.minX = minPos.x; bbox.minY = minPos.y; bbox.maxX = maxPos.x; bbox.maxY = maxPos.y; } expandAllCollapsedNodes(data) { data.nodes = data.nodes.flatMap((groupNodeData) => { const collapsedData = groupNodeData.collapsedData; if (collapsedData === void 0) return [groupNodeData]; delete groupNodeData.collapsedData; data.edges.push(...collapsedData.edges); return [groupNodeData, ...collapsedData.nodes.map((nodeData) => ({ ...nodeData, // Restore the relative position of the node to the group x: nodeData.x + groupNodeData.x, y: nodeData.y + groupNodeData.y }))]; }); } collapseNodes(data) { data.nodes.forEach((groupNodeData) => { if (!groupNodeData.collapsed) return; const groupNodeBBox = CanvasHelper.getBBox([groupNodeData]); const containedNodesData = data.nodes.filter( (nodeData) => nodeData.id !== groupNodeData.id && BBoxHelper.insideBBox(CanvasHelper.getBBox([nodeData]), groupNodeBBox, false) ); const containedEdgesData = data.edges.filter((edgeData) => { return containedNodesData.some((nodeData) => nodeData.id === edgeData.fromNode) || containedNodesData.some((nodeData) => nodeData.id === edgeData.toNode); }); data.nodes = data.nodes.filter((nodeData) => !containedNodesData.includes(nodeData)); data.edges = data.edges.filter((edgeData) => !containedEdgesData.includes(edgeData)); groupNodeData.collapsedData = { nodes: containedNodesData.map((nodeData) => ({ ...nodeData, // Store the relative position of the node to the group x: nodeData.x - groupNodeData.x, y: nodeData.y - groupNodeData.y })), edges: containedEdgesData }; }); } }; // src/canvas-extensions/focus-mode-canvas-extension.ts var CONTROL_MENU_FOCUS_TOGGLE_ID = "focus-mode-toggle"; var FocusModeCanvasExtension = class extends CanvasExtension { isEnabled() { return "focusModeFeatureEnabled"; } init() { this.plugin.addCommand({ id: "toggle-focus-mode", name: "Toggle Focus Mode", checkCallback: CanvasHelper.canvasCommand( this.plugin, (_canvas) => true, (canvas) => this.toggleFocusMode(canvas) ) }); this.plugin.registerEvent(this.plugin.app.workspace.on( "advanced-canvas:canvas-changed", (canvas) => this.addControlMenuToggle(canvas) )); } addControlMenuToggle(canvas) { var _a; const settingsContainer = (_a = canvas.quickSettingsButton) == null ? void 0 : _a.parentElement; if (!settingsContainer) return; const controlMenuFocusToggle = CanvasHelper.createControlMenuButton({ id: CONTROL_MENU_FOCUS_TOGGLE_ID, label: "Focus Mode", icon: "focus", callback: () => this.toggleFocusMode(canvas) }); CanvasHelper.addControlMenuButton(settingsContainer, controlMenuFocusToggle); } toggleFocusMode(canvas) { var _a, _b; const controlMenuFocusToggle = (_b = (_a = canvas.quickSettingsButton) == null ? void 0 : _a.parentElement) == null ? void 0 : _b.querySelector(`#${CONTROL_MENU_FOCUS_TOGGLE_ID}`); if (!controlMenuFocusToggle) return; const newValue = controlMenuFocusToggle.dataset.toggled !== "true"; canvas.wrapperEl.dataset.focusModeEnabled = newValue.toString(); controlMenuFocusToggle.dataset.toggled = newValue.toString(); } }; // src/canvas-extensions/auto-file-node-edges-canvas-extension.ts var AUTO_EDGE_ID_PREFIX = "afe"; var AutoFileNodeEdgesCanvasExtension = class extends CanvasExtension { isEnabled() { return "autoFileNodeEdgesFeatureEnabled"; } init() { this.plugin.registerEvent(this.plugin.app.metadataCache.on("changed", (file) => { for (const canvas of this.plugin.getCanvases()) this.onMetadataChanged(canvas, file); })); this.plugin.registerEvent(this.plugin.app.workspace.on( "advanced-canvas:node-added", (canvas, node) => this.onNodeChanged(canvas, node) )); this.plugin.registerEvent(this.plugin.app.workspace.on( "advanced-canvas:node-changed", (canvas, node) => this.onNodeChanged(canvas, node) )); } onMetadataChanged(canvas, file) { var _a; for (const node of canvas.nodes.values()) { if (node.getData().type !== "file" || ((_a = node.file) == null ? void 0 : _a.path) !== file.path) continue; this.updateFileNodeEdges(canvas, node); } } onNodeChanged(canvas, node) { if (node.getData().type !== "file") return; for (const node2 of canvas.nodes.values()) { if (node2.getData().type !== "file") continue; this.updateFileNodeEdges(canvas, node2); } } updateFileNodeEdges(canvas, node) { const edges = this.getFileNodeEdges(canvas, node); const newEdges = Array.from(edges.values()).filter((edge) => !canvas.edges.has(edge.id)); canvas.importData({ nodes: [], edges: newEdges }, false, false); for (const edge of canvas.edges.values()) { if (edge.id.startsWith(`${AUTO_EDGE_ID_PREFIX}${node.id}`) && !edges.has(edge.id)) canvas.removeEdge(edge); } } getFileNodeEdges(canvas, node) { var _a, _b; const canvasFile = canvas.view.file; if (!canvasFile || !node.file) return /* @__PURE__ */ new Map(); const fileMetadata = this.plugin.app.metadataCache.getFileCache(node.file); if (!fileMetadata) return /* @__PURE__ */ new Map(); const linkedFilesFrontmatterKey = this.plugin.settings.getSetting("autoFileNodeEdgesFrontmatterKey"); const fileLinksToBeLinkedTo = (_b = (_a = fileMetadata.frontmatterLinks) == null ? void 0 : _a.filter((link) => link.key.split(".")[0] === linkedFilesFrontmatterKey)) != null ? _b : []; const filepathsToBeLinkedTo = fileLinksToBeLinkedTo.map((link) => this.plugin.app.metadataCache.getFirstLinkpathDest(link.link, canvasFile.path)).map((file) => file == null ? void 0 : file.path).filter((path) => path !== null); const nodesToBeLinkedTo = Array.from(canvas.nodes.values()).filter((otherNode) => { var _a2; return otherNode.id !== node.id && filepathsToBeLinkedTo.includes((_a2 = otherNode.file) == null ? void 0 : _a2.path); }); const newEdges = /* @__PURE__ */ new Map(); for (const otherNode of nodesToBeLinkedTo) { const edgeId = `${AUTO_EDGE_ID_PREFIX}${node.id}${otherNode.id}`; const bestFromSide = CanvasHelper.getBestSideForFloatingEdge(BBoxHelper.getCenterOfBBoxSide(otherNode.getBBox(), "right"), node); const bestToSide = CanvasHelper.getBestSideForFloatingEdge(BBoxHelper.getCenterOfBBoxSide(node.getBBox(), "left"), otherNode); newEdges.set(edgeId, { id: edgeId, fromNode: node.id, fromSide: bestFromSide, fromFloating: true, toNode: otherNode.id, toSide: bestToSide, toFloating: true }); } return newEdges; } }; // src/canvas-extensions/flip-edge-canvas-extension.ts var FlipEdgeCanvasExtension = class extends CanvasExtension { isEnabled() { return "flipEdgeFeatureEnabled"; } init() { this.plugin.registerEvent(this.plugin.app.workspace.on( "advanced-canvas:popup-menu-created", (canvas) => this.onPopupMenuCreated(canvas) )); } onPopupMenuCreated(canvas) { var _a, _b; const popupMenuEl = (_a = canvas == null ? void 0 : canvas.menu) == null ? void 0 : _a.menuEl; if (!popupMenuEl) return; const POSSIBLE_ICONS = ["lucide-arrow-right", "lucide-move-horizontal", "line-horizontal"]; let edgeDirectionButton = null; for (const icon of POSSIBLE_ICONS) { edgeDirectionButton = (_b = popupMenuEl.querySelector(`button:not([id]) > .svg-icon.${icon}`)) == null ? void 0 : _b.parentElement; if (edgeDirectionButton) break; } if (!edgeDirectionButton) return; edgeDirectionButton.addEventListener("click", () => this.onEdgeDirectionDropdownCreated(canvas)); } onEdgeDirectionDropdownCreated(canvas) { const dropdownEl = document.body.querySelector("div.menu"); if (!dropdownEl) return; const separatorEl = CanvasHelper.createDropdownSeparatorElement(); dropdownEl.appendChild(separatorEl); const flipEdgeButton = CanvasHelper.createDropdownOptionElement({ icon: "flip-horizontal-2", label: "Flip Edge", callback: () => this.flipEdge(canvas) }); dropdownEl.appendChild(flipEdgeButton); } flipEdge(canvas) { const selectedEdges = [...canvas.selection].filter((item) => item.path !== void 0); if (selectedEdges.length === 0) return; for (const edge of selectedEdges) { const edgeData = edge.getData(); edge.setData({ ...edgeData, fromNode: edgeData.toNode, fromSide: edgeData.toSide, toNode: edgeData.fromNode, toSide: edgeData.fromSide }); } canvas.pushHistory(canvas.getData()); } }; // node_modules/html-to-image/es/util.js function resolveUrl(url, baseUrl) { if (url.match(/^[a-z]+:\/\//i)) { return url; } if (url.match(/^\/\//)) { return window.location.protocol + url; } if (url.match(/^[a-z]+:/i)) { return url; } const doc = document.implementation.createHTMLDocument(); const base = doc.createElement("base"); const a = doc.createElement("a"); doc.head.appendChild(base); doc.body.appendChild(a); if (baseUrl) { base.href = baseUrl; } a.href = url; return a.href; } var uuid = /* @__PURE__ */ (() => { let counter = 0; const random = () => ( // eslint-disable-next-line no-bitwise `0000${(Math.random() * 36 ** 4 << 0).toString(36)}`.slice(-4) ); return () => { counter += 1; return `u${random()}${counter}`; }; })(); function toArray(arrayLike) { const arr = []; for (let i = 0, l = arrayLike.length; i < l; i++) { arr.push(arrayLike[i]); } return arr; } function px(node, styleProperty) { const win = node.ownerDocument.defaultView || window; const val = win.getComputedStyle(node).getPropertyValue(styleProperty); return val ? parseFloat(val.replace("px", "")) : 0; } function getNodeWidth(node) { const leftBorder = px(node, "border-left-width"); const rightBorder = px(node, "border-right-width"); return node.clientWidth + leftBorder + rightBorder; } function getNodeHeight(node) { const topBorder = px(node, "border-top-width"); const bottomBorder = px(node, "border-bottom-width"); return node.clientHeight + topBorder + bottomBorder; } function getImageSize(targetNode, options = {}) { const width = options.width || getNodeWidth(targetNode); const height = options.height || getNodeHeight(targetNode); return { width, height }; } function getPixelRatio() { let ratio; let FINAL_PROCESS; try { FINAL_PROCESS = process; } catch (e) { } const val = FINAL_PROCESS && FINAL_PROCESS.env ? FINAL_PROCESS.env.devicePixelRatio : null; if (val) { ratio = parseInt(val, 10); if (Number.isNaN(ratio)) { ratio = 1; } } return ratio || window.devicePixelRatio || 1; } var canvasDimensionLimit = 16384; function checkCanvasDimensions(canvas) { if (canvas.width > canvasDimensionLimit || canvas.height > canvasDimensionLimit) { if (canvas.width > canvasDimensionLimit && canvas.height > canvasDimensionLimit) { if (canvas.width > canvas.height) { canvas.height *= canvasDimensionLimit / canvas.width; canvas.width = canvasDimensionLimit; } else { canvas.width *= canvasDimensionLimit / canvas.height; canvas.height = canvasDimensionLimit; } } else if (canvas.width > canvasDimensionLimit) { canvas.height *= canvasDimensionLimit / canvas.width; canvas.width = canvasDimensionLimit; } else { canvas.width *= canvasDimensionLimit / canvas.height; canvas.height = canvasDimensionLimit; } } } function createImage(url) { return new Promise((resolve, reject) => { const img = new Image(); img.decode = () => resolve(img); img.onload = () => resolve(img); img.onerror = reject; img.crossOrigin = "anonymous"; img.decoding = "async"; img.src = url; }); } async function svgToDataURL(svg) { return Promise.resolve().then(() => new XMLSerializer().serializeToString(svg)).then(encodeURIComponent).then((html) => `data:image/svg+xml;charset=utf-8,${html}`); } async function nodeToDataURL(node, width, height) { const xmlns = "http://www.w3.org/2000/svg"; const svg = document.createElementNS(xmlns, "svg"); const foreignObject = document.createElementNS(xmlns, "foreignObject"); svg.setAttribute("width", `${width}`); svg.setAttribute("height", `${height}`); svg.setAttribute("viewBox", `0 0 ${width} ${height}`); foreignObject.setAttribute("width", "100%"); foreignObject.setAttribute("height", "100%"); foreignObject.setAttribute("x", "0"); foreignObject.setAttribute("y", "0"); foreignObject.setAttribute("externalResourcesRequired", "true"); svg.appendChild(foreignObject); foreignObject.appendChild(node); return svgToDataURL(svg); } var isInstanceOfElement = (node, instance) => { if (node instanceof instance) return true; const nodePrototype = Object.getPrototypeOf(node); if (nodePrototype === null) return false; return nodePrototype.constructor.name === instance.name || isInstanceOfElement(nodePrototype, instance); }; // node_modules/html-to-image/es/clone-pseudos.js function formatCSSText(style) { const content = style.getPropertyValue("content"); return `${style.cssText} content: '${content.replace(/'|"/g, "")}';`; } function formatCSSProperties(style) { return toArray(style).map((name) => { const value = style.getPropertyValue(name); const priority = style.getPropertyPriority(name); return `${name}: ${value}${priority ? " !important" : ""};`; }).join(" "); } function getPseudoElementStyle(className, pseudo, style) { const selector = `.${className}:${pseudo}`; const cssText = style.cssText ? formatCSSText(style) : formatCSSProperties(style); return document.createTextNode(`${selector}{${cssText}}`); } function clonePseudoElement(nativeNode, clonedNode, pseudo) { const style = window.getComputedStyle(nativeNode, pseudo); const content = style.getPropertyValue("content"); if (content === "" || content === "none") { return; } const className = uuid(); try { clonedNode.className = `${clonedNode.className} ${className}`; } catch (err) { return; } const styleElement = document.createElement("style"); styleElement.appendChild(getPseudoElementStyle(className, pseudo, style)); clonedNode.appendChild(styleElement); } function clonePseudoElements(nativeNode, clonedNode) { clonePseudoElement(nativeNode, clonedNode, ":before"); clonePseudoElement(nativeNode, clonedNode, ":after"); } // node_modules/html-to-image/es/mimes.js var WOFF = "application/font-woff"; var JPEG = "image/jpeg"; var mimes = { woff: WOFF, woff2: WOFF, ttf: "application/font-truetype", eot: "application/vnd.ms-fontobject", png: "image/png", jpg: JPEG, jpeg: JPEG, gif: "image/gif", tiff: "image/tiff", svg: "image/svg+xml", webp: "image/webp" }; function getExtension(url) { const match = /\.([^./]*?)$/g.exec(url); return match ? match[1] : ""; } function getMimeType(url) { const extension = getExtension(url).toLowerCase(); return mimes[extension] || ""; } // node_modules/html-to-image/es/dataurl.js function getContentFromDataUrl(dataURL) { return dataURL.split(/,/)[1]; } function isDataUrl(url) { return url.search(/^(data:)/) !== -1; } function makeDataUrl(content, mimeType) { return `data:${mimeType};base64,${content}`; } async function fetchAsDataURL(url, init, process2) { const res = await fetch(url, init); if (res.status === 404) { throw new Error(`Resource "${res.url}" not found`); } const blob = await res.blob(); return new Promise((resolve, reject) => { const reader = new FileReader(); reader.onerror = reject; reader.onloadend = () => { try { resolve(process2({ res, result: reader.result })); } catch (error) { reject(error); } }; reader.readAsDataURL(blob); }); } var cache = {}; function getCacheKey(url, contentType, includeQueryParams) { let key = url.replace(/\?.*/, ""); if (includeQueryParams) { key = url; } if (/ttf|otf|eot|woff2?/i.test(key)) { key = key.replace(/.*\//, ""); } return contentType ? `[${contentType}]${key}` : key; } async function resourceToDataURL(resourceUrl, contentType, options) { const cacheKey = getCacheKey(resourceUrl, contentType, options.includeQueryParams); if (cache[cacheKey] != null) { return cache[cacheKey]; } if (options.cacheBust) { resourceUrl += (/\?/.test(resourceUrl) ? "&" : "?") + (/* @__PURE__ */ new Date()).getTime(); } let dataURL; try { const content = await fetchAsDataURL(resourceUrl, options.fetchRequestInit, ({ res, result }) => { if (!contentType) { contentType = res.headers.get("Content-Type") || ""; } return getContentFromDataUrl(result); }); dataURL = makeDataUrl(content, contentType); } catch (error) { dataURL = options.imagePlaceholder || ""; let msg = `Failed to fetch resource: ${resourceUrl}`; if (error) { msg = typeof error === "string" ? error : error.message; } if (msg) { console.warn(msg); } } cache[cacheKey] = dataURL; return dataURL; } // node_modules/html-to-image/es/clone-node.js async function cloneCanvasElement(canvas) { const dataURL = canvas.toDataURL(); if (dataURL === "data:,") { return canvas.cloneNode(false); } return createImage(dataURL); } async function cloneVideoElement(video, options) { if (video.currentSrc) { const canvas = document.createElement("canvas"); const ctx = canvas.getContext("2d"); canvas.width = video.clientWidth; canvas.height = video.clientHeight; ctx === null || ctx === void 0 ? void 0 : ctx.drawImage(video, 0, 0, canvas.width, canvas.height); const dataURL2 = canvas.toDataURL(); return createImage(dataURL2); } const poster = video.poster; const contentType = getMimeType(poster); const dataURL = await resourceToDataURL(poster, contentType, options); return createImage(dataURL); } async function cloneIFrameElement(iframe) { var _a; try { if ((_a = iframe === null || iframe === void 0 ? void 0 : iframe.contentDocument) === null || _a === void 0 ? void 0 : _a.body) { return await cloneNode(iframe.contentDocument.body, {}, true); } } catch (_b) { } return iframe.cloneNode(false); } async function cloneSingleNode(node, options) { if (isInstanceOfElement(node, HTMLCanvasElement)) { return cloneCanvasElement(node); } if (isInstanceOfElement(node, HTMLVideoElement)) { return cloneVideoElement(node, options); } if (isInstanceOfElement(node, HTMLIFrameElement)) { return cloneIFrameElement(node); } return node.cloneNode(false); } var isSlotElement = (node) => node.tagName != null && node.tagName.toUpperCase() === "SLOT"; async function cloneChildren(nativeNode, clonedNode, options) { var _a, _b; let children = []; if (isSlotElement(nativeNode) && nativeNode.assignedNodes) { children = toArray(nativeNode.assignedNodes()); } else if (isInstanceOfElement(nativeNode, HTMLIFrameElement) && ((_a = nativeNode.contentDocument) === null || _a === void 0 ? void 0 : _a.body)) { children = toArray(nativeNode.contentDocument.body.childNodes); } else { children = toArray(((_b = nativeNode.shadowRoot) !== null && _b !== void 0 ? _b : nativeNode).childNodes); } if (children.length === 0 || isInstanceOfElement(nativeNode, HTMLVideoElement)) { return clonedNode; } await children.reduce((deferred, child) => deferred.then(() => cloneNode(child, options)).then((clonedChild) => { if (clonedChild) { clonedNode.appendChild(clonedChild); } }), Promise.resolve()); return clonedNode; } function cloneCSSStyle(nativeNode, clonedNode) { const targetStyle = clonedNode.style; if (!targetStyle) { return; } const sourceStyle = window.getComputedStyle(nativeNode); if (sourceStyle.cssText) { targetStyle.cssText = sourceStyle.cssText; targetStyle.transformOrigin = sourceStyle.transformOrigin; } else { toArray(sourceStyle).forEach((name) => { let value = sourceStyle.getPropertyValue(name); if (name === "font-size" && value.endsWith("px")) { const reducedFont = Math.floor(parseFloat(value.substring(0, value.length - 2))) - 0.1; value = `${reducedFont}px`; } if (isInstanceOfElement(nativeNode, HTMLIFrameElement) && name === "display" && value === "inline") { value = "block"; } if (name === "d" && clonedNode.getAttribute("d")) { value = `path(${clonedNode.getAttribute("d")})`; } targetStyle.setProperty(name, value, sourceStyle.getPropertyPriority(name)); }); } } function cloneInputValue(nativeNode, clonedNode) { if (isInstanceOfElement(nativeNode, HTMLTextAreaElement)) { clonedNode.innerHTML = nativeNode.value; } if (isInstanceOfElement(nativeNode, HTMLInputElement)) { clonedNode.setAttribute("value", nativeNode.value); } } function cloneSelectValue(nativeNode, clonedNode) { if (isInstanceOfElement(nativeNode, HTMLSelectElement)) { const clonedSelect = clonedNode; const selectedOption = Array.from(clonedSelect.children).find((child) => nativeNode.value === child.getAttribute("value")); if (selectedOption) { selectedOption.setAttribute("selected", ""); } } } function decorate(nativeNode, clonedNode) { if (isInstanceOfElement(clonedNode, Element)) { cloneCSSStyle(nativeNode, clonedNode); clonePseudoElements(nativeNode, clonedNode); cloneInputValue(nativeNode, clonedNode); cloneSelectValue(nativeNode, clonedNode); } return clonedNode; } async function ensureSVGSymbols(clone, options) { const uses = clone.querySelectorAll ? clone.querySelectorAll("use") : []; if (uses.length === 0) { return clone; } const processedDefs = {}; for (let i = 0; i < uses.length; i++) { const use = uses[i]; const id = use.getAttribute("xlink:href"); if (id) { const exist = clone.querySelector(id); const definition = document.querySelector(id); if (!exist && definition && !processedDefs[id]) { processedDefs[id] = await cloneNode(definition, options, true); } } } const nodes = Object.values(processedDefs); if (nodes.length) { const ns = "http://www.w3.org/1999/xhtml"; const svg = document.createElementNS(ns, "svg"); svg.setAttribute("xmlns", ns); svg.style.position = "absolute"; svg.style.width = "0"; svg.style.height = "0"; svg.style.overflow = "hidden"; svg.style.display = "none"; const defs = document.createElementNS(ns, "defs"); svg.appendChild(defs); for (let i = 0; i < nodes.length; i++) { defs.appendChild(nodes[i]); } clone.appendChild(svg); } return clone; } async function cloneNode(node, options, isRoot) { if (!isRoot && options.filter && !options.filter(node)) { return null; } return Promise.resolve(node).then((clonedNode) => cloneSingleNode(clonedNode, options)).then((clonedNode) => cloneChildren(node, clonedNode, options)).then((clonedNode) => decorate(node, clonedNode)).then((clonedNode) => ensureSVGSymbols(clonedNode, options)); } // node_modules/html-to-image/es/embed-resources.js var URL_REGEX = /url\((['"]?)([^'"]+?)\1\)/g; var URL_WITH_FORMAT_REGEX = /url\([^)]+\)\s*format\((["']?)([^"']+)\1\)/g; var FONT_SRC_REGEX = /src:\s*(?:url\([^)]+\)\s*format\([^)]+\)[,;]\s*)+/g; function toRegex(url) { const escaped = url.replace(/([.*+?^${}()|\[\]\/\\])/g, "\\$1"); return new RegExp(`(url\\(['"]?)(${escaped})(['"]?\\))`, "g"); } function parseURLs(cssText) { const urls = []; cssText.replace(URL_REGEX, (raw, quotation, url) => { urls.push(url); return raw; }); return urls.filter((url) => !isDataUrl(url)); } async function embed(cssText, resourceURL, baseURL, options, getContentFromUrl) { try { const resolvedURL = baseURL ? resolveUrl(resourceURL, baseURL) : resourceURL; const contentType = getMimeType(resourceURL); let dataURL; if (getContentFromUrl) { const content = await getContentFromUrl(resolvedURL); dataURL = makeDataUrl(content, contentType); } else { dataURL = await resourceToDataURL(resolvedURL, contentType, options); } return cssText.replace(toRegex(resourceURL), `$1${dataURL}$3`); } catch (error) { } return cssText; } function filterPreferredFontFormat(str, { preferredFontFormat }) { return !preferredFontFormat ? str : str.replace(FONT_SRC_REGEX, (match) => { while (true) { const [src, , format] = URL_WITH_FORMAT_REGEX.exec(match) || []; if (!format) { return ""; } if (format === preferredFontFormat) { return `src: ${src};`; } } }); } function shouldEmbed(url) { return url.search(URL_REGEX) !== -1; } async function embedResources(cssText, baseUrl, options) { if (!shouldEmbed(cssText)) { return cssText; } const filteredCSSText = filterPreferredFontFormat(cssText, options); const urls = parseURLs(filteredCSSText); return urls.reduce((deferred, url) => deferred.then((css) => embed(css, url, baseUrl, options)), Promise.resolve(filteredCSSText)); } // node_modules/html-to-image/es/embed-images.js async function embedProp(propName, node, options) { var _a; const propValue = (_a = node.style) === null || _a === void 0 ? void 0 : _a.getPropertyValue(propName); if (propValue) { const cssString = await embedResources(propValue, null, options); node.style.setProperty(propName, cssString, node.style.getPropertyPriority(propName)); return true; } return false; } async function embedBackground(clonedNode, options) { if (!await embedProp("background", clonedNode, options)) { await embedProp("background-image", clonedNode, options); } if (!await embedProp("mask", clonedNode, options)) { await embedProp("mask-image", clonedNode, options); } } async function embedImageNode(clonedNode, options) { const isImageElement = isInstanceOfElement(clonedNode, HTMLImageElement); if (!(isImageElement && !isDataUrl(clonedNode.src)) && !(isInstanceOfElement(clonedNode, SVGImageElement) && !isDataUrl(clonedNode.href.baseVal))) { return; } const url = isImageElement ? clonedNode.src : clonedNode.href.baseVal; const dataURL = await resourceToDataURL(url, getMimeType(url), options); await new Promise((resolve, reject) => { clonedNode.onload = resolve; clonedNode.onerror = reject; const image = clonedNode; if (image.decode) { image.decode = resolve; } if (image.loading === "lazy") { image.loading = "eager"; } if (isImageElement) { clonedNode.srcset = ""; clonedNode.src = dataURL; } else { clonedNode.href.baseVal = dataURL; } }); } async function embedChildren(clonedNode, options) { const children = toArray(clonedNode.childNodes); const deferreds = children.map((child) => embedImages(child, options)); await Promise.all(deferreds).then(() => clonedNode); } async function embedImages(clonedNode, options) { if (isInstanceOfElement(clonedNode, Element)) { await embedBackground(clonedNode, options); await embedImageNode(clonedNode, options); await embedChildren(clonedNode, options); } } // node_modules/html-to-image/es/apply-style.js function applyStyle(node, options) { const { style } = node; if (options.backgroundColor) { style.backgroundColor = options.backgroundColor; } if (options.width) { style.width = `${options.width}px`; } if (options.height) { style.height = `${options.height}px`; } const manual = options.style; if (manual != null) { Object.keys(manual).forEach((key) => { style[key] = manual[key]; }); } return node; } // node_modules/html-to-image/es/embed-webfonts.js var cssFetchCache = {}; async function fetchCSS(url) { let cache2 = cssFetchCache[url]; if (cache2 != null) { return cache2; } const res = await fetch(url); const cssText = await res.text(); cache2 = { url, cssText }; cssFetchCache[url] = cache2; return cache2; } async function embedFonts(data, options) { let cssText = data.cssText; const regexUrl = /url\(["']?([^"')]+)["']?\)/g; const fontLocs = cssText.match(/url\([^)]+\)/g) || []; const loadFonts = fontLocs.map(async (loc) => { let url = loc.replace(regexUrl, "$1"); if (!url.startsWith("https://")) { url = new URL(url, data.url).href; } return fetchAsDataURL(url, options.fetchRequestInit, ({ result }) => { cssText = cssText.replace(loc, `url(${result})`); return [loc, result]; }); }); return Promise.all(loadFonts).then(() => cssText); } function parseCSS(source) { if (source == null) { return []; } const result = []; const commentsRegex = /(\/\*[\s\S]*?\*\/)/gi; let cssText = source.replace(commentsRegex, ""); const keyframesRegex = new RegExp("((@.*?keyframes [\\s\\S]*?){([\\s\\S]*?}\\s*?)})", "gi"); while (true) { const matches = keyframesRegex.exec(cssText); if (matches === null) { break; } result.push(matches[0]); } cssText = cssText.replace(keyframesRegex, ""); const importRegex = /@import[\s\S]*?url\([^)]*\)[\s\S]*?;/gi; const combinedCSSRegex = "((\\s*?(?:\\/\\*[\\s\\S]*?\\*\\/)?\\s*?@media[\\s\\S]*?){([\\s\\S]*?)}\\s*?})|(([\\s\\S]*?){([\\s\\S]*?)})"; const unifiedRegex = new RegExp(combinedCSSRegex, "gi"); while (true) { let matches = importRegex.exec(cssText); if (matches === null) { matches = unifiedRegex.exec(cssText); if (matches === null) { break; } else { importRegex.lastIndex = unifiedRegex.lastIndex; } } else { unifiedRegex.lastIndex = importRegex.lastIndex; } result.push(matches[0]); } return result; } async function getCSSRules(styleSheets, options) { const ret = []; const deferreds = []; styleSheets.forEach((sheet) => { if ("cssRules" in sheet) { try { toArray(sheet.cssRules || []).forEach((item, index) => { if (item.type === CSSRule.IMPORT_RULE) { let importIndex = index + 1; const url = item.href; const deferred = fetchCSS(url).then((metadata) => embedFonts(metadata, options)).then((cssText) => parseCSS(cssText).forEach((rule) => { try { sheet.insertRule(rule, rule.startsWith("@import") ? importIndex += 1 : sheet.cssRules.length); } catch (error) { console.error("Error inserting rule from remote css", { rule, error }); } })).catch((e) => { console.error("Error loading remote css", e.toString()); }); deferreds.push(deferred); } }); } catch (e) { const inline = styleSheets.find((a) => a.href == null) || document.styleSheets[0]; if (sheet.href != null) { deferreds.push(fetchCSS(sheet.href).then((metadata) => embedFonts(metadata, options)).then((cssText) => parseCSS(cssText).forEach((rule) => { inline.insertRule(rule, sheet.cssRules.length); })).catch((err) => { console.error("Error loading remote stylesheet", err); })); } console.error("Error inlining remote css file", e); } } }); return Promise.all(deferreds).then(() => { styleSheets.forEach((sheet) => { if ("cssRules" in sheet) { try { toArray(sheet.cssRules || []).forEach((item) => { ret.push(item); }); } catch (e) { console.error(`Error while reading CSS rules from ${sheet.href}`, e); } } }); return ret; }); } function getWebFontRules(cssRules) { return cssRules.filter((rule) => rule.type === CSSRule.FONT_FACE_RULE).filter((rule) => shouldEmbed(rule.style.getPropertyValue("src"))); } async function parseWebFontRules(node, options) { if (node.ownerDocument == null) { throw new Error("Provided element is not within a Document"); } const styleSheets = toArray(node.ownerDocument.styleSheets); const cssRules = await getCSSRules(styleSheets, options); return getWebFontRules(cssRules); } async function getWebFontCSS(node, options) { const rules = await parseWebFontRules(node, options); const cssTexts = await Promise.all(rules.map((rule) => { const baseUrl = rule.parentStyleSheet ? rule.parentStyleSheet.href : null; return embedResources(rule.cssText, baseUrl, options); })); return cssTexts.join("\n"); } async function embedWebFonts(clonedNode, options) { const cssText = options.fontEmbedCSS != null ? options.fontEmbedCSS : options.skipFonts ? null : await getWebFontCSS(clonedNode, options); if (cssText) { const styleNode = document.createElement("style"); const sytleContent = document.createTextNode(cssText); styleNode.appendChild(sytleContent); if (clonedNode.firstChild) { clonedNode.insertBefore(styleNode, clonedNode.firstChild); } else { clonedNode.appendChild(styleNode); } } } // node_modules/html-to-image/es/index.js async function toSvg(node, options = {}) { const { width, height } = getImageSize(node, options); const clonedNode = await cloneNode(node, options, true); await embedWebFonts(clonedNode, options); await embedImages(clonedNode, options); applyStyle(clonedNode, options); const datauri = await nodeToDataURL(clonedNode, width, height); return datauri; } async function toCanvas(node, options = {}) { const { width, height } = getImageSize(node, options); const svg = await toSvg(node, options); const img = await createImage(svg); const canvas = document.createElement("canvas"); const context = canvas.getContext("2d"); const ratio = options.pixelRatio || getPixelRatio(); const canvasWidth = options.canvasWidth || width; const canvasHeight = options.canvasHeight || height; canvas.width = canvasWidth * ratio; canvas.height = canvasHeight * ratio; if (!options.skipAutoScale) { checkCanvasDimensions(canvas); } canvas.style.width = `${canvasWidth}`; canvas.style.height = `${canvasHeight}`; if (options.backgroundColor) { context.fillStyle = options.backgroundColor; context.fillRect(0, 0, canvas.width, canvas.height); } context.drawImage(img, 0, 0, canvas.width, canvas.height); return canvas; } async function toPng(node, options = {}) { const canvas = await toCanvas(node, options); return canvas.toDataURL(); } // src/canvas-extensions/export-canvas-extension.ts var import_obsidian16 = require("obsidian"); var MAX_ALLOWED_LOADING_TIME = 1e4; var ExportCanvasExtension = class extends CanvasExtension { isEnabled() { return "betterExportFeatureEnabled"; } init() { this.plugin.registerEvent(this.plugin.app.workspace.on( "advanced-canvas:node-breakpoint-changed", (canvas, node, breakpointRef) => { if (canvas.screenshotting) breakpointRef.value = true; } )); this.plugin.addCommand({ id: "export-all-as-image", name: "Export canvas as image", checkCallback: CanvasHelper.canvasCommand( this.plugin, (canvas) => canvas.nodes.size > 0, (canvas) => this.showExportImageSettingsModal(canvas, null) ) }); this.plugin.addCommand({ id: "export-selected-as-image", name: "Export selected nodes as image", checkCallback: CanvasHelper.canvasCommand( this.plugin, (canvas) => canvas.selection.size > 0, (canvas) => this.showExportImageSettingsModal( canvas, canvas.getSelectionData().nodes.map((nodeData) => canvas.nodes.get(nodeData.id)).filter((node) => node !== void 0) ) ) }); } async showExportImageSettingsModal(canvas, nodesToExport) { const modal = new import_obsidian16.Modal(this.plugin.app); modal.setTitle("Export image settings"); let pixelRatioSetting = null; let noFontExportSetting = null; let transparentBackgroundSetting = null; const updateDynamicSettings = () => { var _a, _b, _c, _d, _e, _f; if (svg) { (_a = pixelRatioSetting == null ? void 0 : pixelRatioSetting.settingEl) == null ? void 0 : _a.hide(); (_b = noFontExportSetting == null ? void 0 : noFontExportSetting.settingEl) == null ? void 0 : _b.show(); (_c = transparentBackgroundSetting == null ? void 0 : transparentBackgroundSetting.settingEl) == null ? void 0 : _c.hide(); } else { (_d = pixelRatioSetting == null ? void 0 : pixelRatioSetting.settingEl) == null ? void 0 : _d.show(); (_e = noFontExportSetting == null ? void 0 : noFontExportSetting.settingEl) == null ? void 0 : _e.hide(); (_f = transparentBackgroundSetting == null ? void 0 : transparentBackgroundSetting.settingEl) == null ? void 0 : _f.show(); } }; let svg = false; new import_obsidian16.Setting(modal.contentEl).setName("Export file format").setDesc("Choose the file format to export the canvas as.").addDropdown( (dropdown) => dropdown.addOptions({ png: "PNG", svg: "SVG" }).setValue(svg ? "svg" : "png").onChange((value) => { svg = value === "svg"; updateDynamicSettings(); }) ); let pixelRatioFactor = 1; pixelRatioSetting = new import_obsidian16.Setting(modal.contentEl).setName("Pixel ratio").setDesc("Higher pixel ratios result in higher resolution images but also larger file sizes.").addSlider( (slider) => slider.setDynamicTooltip().setLimits(0.2, 5, 0.1).setValue(pixelRatioFactor).onChange((value) => pixelRatioFactor = value) ); let noFontExport = true; noFontExportSetting = new import_obsidian16.Setting(modal.contentEl).setName("Skip font export").setDesc("This will not include the fonts in the exported SVG. This will make the SVG file smaller.").addToggle( (toggle) => toggle.setValue(noFontExport).onChange((value) => noFontExport = value) ); let watermark = false; new import_obsidian16.Setting(modal.contentEl).setName("Show logo").setDesc("This will add an Obsidian + Advanced Canvas logo to the bottom left.").addToggle( (toggle) => toggle.setValue(watermark).onChange((value) => watermark = value) ); let garbledText = false; new import_obsidian16.Setting(modal.contentEl).setName("Privacy mode").setDesc("This will obscure any text on your canvas.").addToggle( (toggle) => toggle.setValue(garbledText).onChange((value) => garbledText = value) ); let transparentBackground = false; transparentBackgroundSetting = new import_obsidian16.Setting(modal.contentEl).setName("Transparent background").setDesc("This will make the background of the image transparent.").addToggle( (toggle) => toggle.setValue(transparentBackground).onChange((value) => transparentBackground = value) ); new import_obsidian16.Setting(modal.contentEl).addButton( (button) => button.setButtonText("Save").setCta().onClick(async () => { modal.close(); this.exportImage( canvas, nodesToExport, svg, svg ? 1 : pixelRatioFactor, svg ? noFontExport : false, watermark, garbledText, svg ? true : transparentBackground ); }) ); updateDynamicSettings(); modal.open(); } async exportImage(canvas, nodesToExport, svg, pixelRatioFactor, noFontExport, watermark, garbledText, transparentBackground) { var _a, _b, _c; const isWholeCanvas = nodesToExport === null; if (!nodesToExport) nodesToExport = [...canvas.nodes.values()]; const nodesToExportIds = nodesToExport.map((node) => node.getData().id); const edgesToExport = [...canvas.edges.values()].filter((edge) => { const edgeData = edge.getData(); return nodesToExportIds.includes(edgeData.fromNode) && nodesToExportIds.includes(edgeData.toNode); }); const backgroundColor = transparentBackground ? void 0 : window.getComputedStyle(canvas.canvasEl).getPropertyValue("--canvas-background"); new import_obsidian16.Notice("Exporting the canvas. Please wait..."); const interactionBlocker = this.getInteractionBlocker(); document.body.appendChild(interactionBlocker); canvas.screenshotting = true; canvas.canvasEl.classList.add("is-exporting"); if (garbledText) canvas.canvasEl.classList.add("is-text-garbled"); let watermarkEl = null; const cachedSelection = new Set(canvas.selection); canvas.deselectAll(); const cachedViewport = { x: canvas.x, y: canvas.y, zoom: canvas.zoom }; try { const targetBoundingBox = CanvasHelper.getBBox([...nodesToExport, ...edgesToExport]); let enlargedTargetBoundingBox = BBoxHelper.scaleBBox(targetBoundingBox, 1.1); const enlargedTargetBoundingBoxSize = { width: enlargedTargetBoundingBox.maxX - enlargedTargetBoundingBox.minX, height: enlargedTargetBoundingBox.maxY - enlargedTargetBoundingBox.minY }; const canvasElSize = { width: canvas.canvasEl.clientWidth, height: canvas.canvasEl.clientHeight }; const requiredPixelRatio = Math.max(enlargedTargetBoundingBoxSize.width / canvasElSize.width, enlargedTargetBoundingBoxSize.height / canvasElSize.height); const pixelRatio = svg ? void 0 : Math.round(requiredPixelRatio * pixelRatioFactor); watermarkEl = watermark ? this.getWatermark(enlargedTargetBoundingBox) : null; if (watermarkEl) canvas.canvasEl.appendChild(watermarkEl); const actualAspectRatio = canvas.canvasRect.width / canvas.canvasRect.height; const targetAspectRatio = (enlargedTargetBoundingBox.maxX - enlargedTargetBoundingBox.minX) / (enlargedTargetBoundingBox.maxY - enlargedTargetBoundingBox.minY); let adjustedBoundingBox = { ...enlargedTargetBoundingBox }; if (actualAspectRatio > targetAspectRatio) { const targetHeight = enlargedTargetBoundingBox.maxY - enlargedTargetBoundingBox.minY; const actualWidth = targetHeight * actualAspectRatio; adjustedBoundingBox.maxX = enlargedTargetBoundingBox.minX + actualWidth; } else { const targetWidth = enlargedTargetBoundingBox.maxX - enlargedTargetBoundingBox.minX; const actualHeight = targetWidth / actualAspectRatio; adjustedBoundingBox.maxY = enlargedTargetBoundingBox.minY + actualHeight; } canvas.zoomToRealBbox(adjustedBoundingBox); canvas.setViewport(canvas.tx, canvas.ty, canvas.tZoom); await sleep(10); let canvasScale = parseFloat(((_a = canvas.canvasEl.style.transform.match(/scale\((\d+(\.\d+)?)\)/)) == null ? void 0 : _a[1]) || "1"); const edgePathsBBox = BBoxHelper.combineBBoxes(edgesToExport.map((edge) => { const edgeCenter = edge.getCenter(); const labelWidth = edge.labelElement ? edge.labelElement.wrapperEl.getBoundingClientRect().width / canvasScale : 0; return { minX: edgeCenter.x - labelWidth / 2, minY: edgeCenter.y, maxX: edgeCenter.x + labelWidth / 2, maxY: edgeCenter.y }; })); const enlargedEdgePathsBBox = BBoxHelper.enlargeBBox(edgePathsBBox, 1.1); enlargedTargetBoundingBox = BBoxHelper.combineBBoxes([enlargedTargetBoundingBox, enlargedEdgePathsBBox]); adjustedBoundingBox = BBoxHelper.combineBBoxes([adjustedBoundingBox, enlargedEdgePathsBBox]); canvas.zoomToRealBbox(adjustedBoundingBox); canvas.setViewport(canvas.tx, canvas.ty, canvas.tZoom); await sleep(10); const canvasViewportBBox = canvas.getViewportBBox(); canvasScale = parseFloat(((_b = canvas.canvasEl.style.transform.match(/scale\((\d+(\.\d+)?)\)/)) == null ? void 0 : _b[1]) || "1"); let width = (canvasViewportBBox.maxX - canvasViewportBBox.minX) * canvasScale; let height = (canvasViewportBBox.maxY - canvasViewportBBox.minY) * canvasScale; if (actualAspectRatio > targetAspectRatio) width = height * targetAspectRatio; else height = width / targetAspectRatio; let unloadedNodes = nodesToExport.filter((node) => node.initialized === false || node.isContentMounted === false); const startTimestamp = performance.now(); while (unloadedNodes.length > 0 && performance.now() - startTimestamp < MAX_ALLOWED_LOADING_TIME) { await sleep(10); unloadedNodes = nodesToExport.filter((node) => node.initialized === false || node.isContentMounted === false); console.info(`Waiting for ${unloadedNodes.length} nodes to finish loading...`); } if (unloadedNodes.length === 0) { const nodeElements = nodesToExport.map((node) => node.nodeEl); const edgePathAndArrowElements = edgesToExport.map((edge) => [edge.lineGroupEl, edge.lineEndGroupEl]).flat(); const edgeLabelElements = edgesToExport.map((edge) => { var _a2; return (_a2 = edge.labelElement) == null ? void 0 : _a2.wrapperEl; }).filter((labelElement) => labelElement !== void 0); const filter = (element) => { var _a2, _b2, _c2, _d; if (((_a2 = element.classList) == null ? void 0 : _a2.contains("canvas-node")) && !nodeElements.includes(element)) return false; if (((_c2 = (_b2 = element.parentElement) == null ? void 0 : _b2.classList) == null ? void 0 : _c2.contains("canvas-edges")) && !edgePathAndArrowElements.includes(element)) return false; if (((_d = element.classList) == null ? void 0 : _d.contains("canvas-path-label-wrapper")) && !edgeLabelElements.includes(element)) return false; return true; }; const options = { pixelRatio, backgroundColor, height, width, filter }; if (noFontExport) options.fontEmbedCSS = ""; const imageDataUri = svg ? await toSvg(canvas.canvasEl, options) : await toPng(canvas.canvasEl, options); let baseFilename = `${((_c = canvas.view.file) == null ? void 0 : _c.basename) || "Untitled"}`; if (!isWholeCanvas) baseFilename += ` - Selection of ${nodesToExport.length}`; const filename = `${baseFilename}.${svg ? "svg" : "png"}`; const downloadEl = document.createElement("a"); downloadEl.href = imageDataUri; downloadEl.download = filename; downloadEl.click(); } else { const ERROR_MESSAGE = "Export cancelled: Nodes did not finish loading in time"; new import_obsidian16.Notice(ERROR_MESSAGE); console.error(ERROR_MESSAGE); } } finally { canvas.screenshotting = false; canvas.canvasEl.classList.remove("is-exporting"); if (garbledText) canvas.canvasEl.classList.remove("is-text-garbled"); if (watermarkEl) canvas.canvasEl.removeChild(watermarkEl); canvas.updateSelection(() => canvas.selection = cachedSelection); canvas.setViewport(cachedViewport.x, cachedViewport.y, cachedViewport.zoom); interactionBlocker.remove(); } } getInteractionBlocker() { const interactionBlocker = document.createElement("div"); interactionBlocker.classList.add("progress-bar-container"); const progressBar = document.createElement("div"); progressBar.classList.add("progress-bar"); interactionBlocker.appendChild(progressBar); const progressBarMessage = document.createElement("div"); progressBarMessage.classList.add("progress-bar-message", "u-center-text"); progressBarMessage.innerText = "Generating image..."; progressBar.appendChild(progressBarMessage); const progressBarIndicator = document.createElement("div"); progressBarIndicator.classList.add("progress-bar-indicator"); progressBar.appendChild(progressBarIndicator); const progressBarLine = document.createElement("div"); progressBarLine.classList.add("progress-bar-line"); progressBarIndicator.appendChild(progressBarLine); const progressBarSublineIncrease = document.createElement("div"); progressBarSublineIncrease.classList.add("progress-bar-subline", "mod-increase"); progressBarIndicator.appendChild(progressBarSublineIncrease); const progressBarSublineDecrease = document.createElement("div"); progressBarSublineDecrease.classList.add("progress-bar-subline", "mod-decrease"); progressBarIndicator.appendChild(progressBarSublineDecrease); return interactionBlocker; } getWatermark(bbox) { const bboxWidth = bbox.maxX - bbox.minX; const width = Math.max(200, bboxWidth * 0.3); const WATERMARK_SIZE = { width: 215, height: 25 }; const height = WATERMARK_SIZE.height / WATERMARK_SIZE.width * width; const watermarkPadding = { x: bboxWidth * 0.02, y: bboxWidth * 0.014 }; bbox.maxY += height + watermarkPadding.y; const watermarkEl = document.createElementNS("http://www.w3.org/2000/svg", "svg"); watermarkEl.id = "watermark-ac"; watermarkEl.style.transform = `translate(${bbox.minX + watermarkPadding.x}px, ${bbox.maxY - height - watermarkPadding.y}px)`; watermarkEl.setAttrs({ viewBox: `0 0 ${WATERMARK_SIZE.width} ${WATERMARK_SIZE.height}`, width: width.toString(), fill: "currentColor" }); watermarkEl.innerHTML = ''; return watermarkEl; } }; // src/canvas-extensions/floating-edge-canvas-extension.ts var FloatingEdgeCanvasExtension = class extends CanvasExtension { isEnabled() { return "floatingEdgeFeatureEnabled"; } init() { this.plugin.registerEvent(this.plugin.app.workspace.on( "advanced-canvas:data-loaded:after", (canvas, data, setData) => this.onLoadData(canvas, data) )); this.plugin.registerEvent(this.plugin.app.workspace.on( "advanced-canvas:node-moved", (canvas, node) => this.onNodeMoved(canvas, node) )); if (this.plugin.settings.getSetting("allowFloatingEdgeCreation")) { this.plugin.registerEvent(this.plugin.app.workspace.on( "advanced-canvas:edge-connection-dragging:before", (canvas, edge, event, newEdge, side) => this.onEdgeStartedDragging(canvas, edge, event, newEdge, side) )); } this.plugin.registerEvent(this.plugin.app.workspace.on( "advanced-canvas:edge-connection-dragging:after", (canvas, edge, event, newEdge, side) => this.onEdgeStoppedDragging(canvas, edge, event, newEdge, side) )); } onLoadData(canvas, data) { for (const edgeData of data.edges) { const edge = canvas.edges.get(edgeData.id); if (!edge) return console.warn("Imported edge is not yet loaded :("); this.updateEdgeConnectionSide(edge); } } onNodeMoved(canvas, node) { const affectedEdges = canvas.getEdgesForNode(node); for (const edge of affectedEdges) this.updateEdgeConnectionSide(edge); } updateEdgeConnectionSide(edge) { const edgeData = edge.getData(); if (edgeData.fromFloating) { const fixedNodeConnectionPoint = BBoxHelper.getCenterOfBBoxSide(edge.to.node.getBBox(), edge.to.side); const bestSide = CanvasHelper.getBestSideForFloatingEdge(fixedNodeConnectionPoint, edge.from.node); if (bestSide !== edge.from.side) { edge.setData({ ...edgeData, fromSide: bestSide }); } } if (edgeData.toFloating) { const fixedNodeConnectionPoint = BBoxHelper.getCenterOfBBoxSide(edge.from.node.getBBox(), edge.from.side); const bestSide = CanvasHelper.getBestSideForFloatingEdge(fixedNodeConnectionPoint, edge.to.node); if (bestSide !== edge.to.side) { edge.setData({ ...edgeData, toSide: bestSide }); } } } onEdgeStartedDragging(canvas, edge, _event, newEdge, _side) { if (newEdge && this.plugin.settings.getSetting("newEdgeFromSideFloating")) edge.setData({ ...edge.getData(), fromFloating: true // New edges can only get dragged from the "from" side }); let cachedViewportNodes = null; let hasNaNFloatingEdgeDropZones = false; this.onPointerMove = (event) => { if (cachedViewportNodes === null || hasNaNFloatingEdgeDropZones || canvas.viewportChanged) { hasNaNFloatingEdgeDropZones = false; cachedViewportNodes = canvas.getViewportNodes().map((node) => { const nodeFloatingEdgeDropZone = this.getFloatingEdgeDropZoneForNode(node); if (isNaN(nodeFloatingEdgeDropZone.minX) || isNaN(nodeFloatingEdgeDropZone.minY) || isNaN(nodeFloatingEdgeDropZone.maxX) || isNaN(nodeFloatingEdgeDropZone.maxY)) hasNaNFloatingEdgeDropZones = true; return [node, nodeFloatingEdgeDropZone]; }); } for (const [node, nodeFloatingEdgeDropZoneClientRect] of cachedViewportNodes) { const hovering = BBoxHelper.insideBBox({ x: event.clientX, y: event.clientY }, nodeFloatingEdgeDropZoneClientRect, true); node.nodeEl.classList.toggle("hovering-floating-edge-zone", hovering); } }; document.addEventListener("pointermove", this.onPointerMove); } onEdgeStoppedDragging(_canvas, edge, event, _newEdge, side) { document.removeEventListener("pointermove", this.onPointerMove); const dropZoneNode = side === "from" ? edge.from.node : edge.to.node; const floatingEdgeDropZone = this.getFloatingEdgeDropZoneForNode(dropZoneNode); const wasDroppedInFloatingEdgeDropZone = this.plugin.settings.getSetting("allowFloatingEdgeCreation") ? BBoxHelper.insideBBox({ x: event.clientX, y: event.clientY }, floatingEdgeDropZone, true) : false; const edgeData = edge.getData(); if (side === "from" && wasDroppedInFloatingEdgeDropZone == edgeData.fromFloating) return; if (side === "to" && wasDroppedInFloatingEdgeDropZone == edgeData.toFloating) return; if (side === "from") edgeData.fromFloating = wasDroppedInFloatingEdgeDropZone; else edgeData.toFloating = wasDroppedInFloatingEdgeDropZone; edge.setData(edgeData); this.updateEdgeConnectionSide(edge); } getFloatingEdgeDropZoneForNode(node) { const nodeElClientBoundingRect = node.nodeEl.getBoundingClientRect(); const nodeFloatingEdgeDropZoneElStyle = window.getComputedStyle(node.nodeEl, ":after"); const nodeFloatingEdgeDropZoneSize = { width: parseFloat(nodeFloatingEdgeDropZoneElStyle.getPropertyValue("width")), height: parseFloat(nodeFloatingEdgeDropZoneElStyle.getPropertyValue("height")) }; return { minX: nodeElClientBoundingRect.left + (nodeElClientBoundingRect.width - nodeFloatingEdgeDropZoneSize.width) / 2, minY: nodeElClientBoundingRect.top + (nodeElClientBoundingRect.height - nodeFloatingEdgeDropZoneSize.height) / 2, maxX: nodeElClientBoundingRect.right - (nodeElClientBoundingRect.width - nodeFloatingEdgeDropZoneSize.width) / 2, maxY: nodeElClientBoundingRect.bottom - (nodeElClientBoundingRect.height - nodeFloatingEdgeDropZoneSize.height) / 2 }; } }; // src/canvas-extensions/edge-highlight-canvas-extension.ts var EdgeHighlightCanvasExtension = class extends CanvasExtension { isEnabled() { return "edgeHighlightEnabled"; } init() { this.plugin.registerEvent(this.plugin.app.workspace.on( "advanced-canvas:selection-changed", (canvas, oldSelection, updateSelection) => this.onSelectionChanged(canvas, oldSelection) )); } onSelectionChanged(canvas, oldSelection) { const connectedEdgesToBeHighlighted = new Set(canvas.getSelectionData().nodes.flatMap((nodeData) => { var _a, _b; return [ ...(_a = canvas.edgeFrom.get(canvas.nodes.get(nodeData.id))) != null ? _a : [], ...this.plugin.settings.getSetting("highlightIncomingEdges") ? (_b = canvas.edgeTo.get(canvas.nodes.get(nodeData.id))) != null ? _b : [] : [] ]; })); for (const edge of canvas.edges.values()) { edge.lineGroupEl.classList.toggle( "is-focused", canvas.selection.has(edge) || connectedEdgesToBeHighlighted.has(edge) ); } } }; // src/managers/css-styles-config-manager.ts var import_obsidian17 = require("obsidian"); var CssStylesConfigManager = class { constructor(plugin, trigger, validate) { this.plugin = plugin; this.validate = validate; this.cachedConfig = null; this.configRegex = new RegExp(`\\/\\*\\s*@${trigger}\\s*\\n([\\s\\S]*?)\\*\\/`, "g"); this.plugin.registerEvent(this.plugin.app.workspace.on( "css-change", () => { this.cachedConfig = null; } )); } getStyles() { if (this.cachedConfig) return this.cachedConfig; this.cachedConfig = []; const styleSheets = document.styleSheets; for (let i = 0; i < styleSheets.length; i++) { const sheet = styleSheets.item(i); if (!sheet) continue; const styleSheetConfigs = this.parseStyleConfigsFromCSS(sheet); for (const config of styleSheetConfigs) { const validConfig = this.validate(config); if (!validConfig) continue; this.cachedConfig.push(validConfig); } } return this.cachedConfig; } parseStyleConfigsFromCSS(sheet) { var _a, _b; const textContent = (_b = (_a = sheet == null ? void 0 : sheet.ownerNode) == null ? void 0 : _a.textContent) == null ? void 0 : _b.trim(); if (!textContent) return []; const configs = []; const matches = textContent.matchAll(this.configRegex); for (const match of matches) { const yamlString = match[1]; const configYaml = (0, import_obsidian17.parseYaml)(yamlString); configs.push(configYaml); } return configs; } }; // src/canvas-extensions/advanced-styles/node-styles.ts var NodeStylesExtension = class extends CanvasExtension { isEnabled() { return "nodeStylingFeatureEnabled"; } init() { this.cssStylesManager = new CssStylesConfigManager(this.plugin, "advanced-canvas-node-style", styleAttributeValidator); this.plugin.registerEvent(this.plugin.app.workspace.on( "advanced-canvas:popup-menu-created", (canvas) => this.onPopupMenuCreated(canvas) )); } onPopupMenuCreated(canvas) { var _a; const selectionNodeData = canvas.getSelectionData().nodes; if (canvas.readonly || selectionNodeData.length === 0 || selectionNodeData.length !== canvas.selection.size) return; const selectedNodeTypes = new Set(selectionNodeData.map((node) => node.type)); const availableNodeStyles = [ ...BUILTIN_NODE_STYLE_ATTRIBUTES, /* Legacy */ ...this.plugin.settings.getSetting("customNodeStyleAttributes"), ...this.cssStylesManager.getStyles() ].filter((style) => !style.nodeTypes || style.nodeTypes.some((type) => selectedNodeTypes.has(type))); CanvasHelper.addStyleAttributesToPopup( this.plugin, canvas, availableNodeStyles, (_a = selectionNodeData[0].styleAttributes) != null ? _a : {}, (attribute, value) => this.setStyleAttributeForSelection(canvas, attribute, value) ); } setStyleAttributeForSelection(canvas, attribute, value) { const selectionNodeData = canvas.getSelectionData().nodes; for (const nodeData of selectionNodeData) { const node = canvas.nodes.get(nodeData.id); if (!node) continue; if (attribute.nodeTypes && !attribute.nodeTypes.includes(nodeData.type)) continue; node.setData({ ...nodeData, styleAttributes: { ...nodeData.styleAttributes, [attribute.key]: value } }); } canvas.pushHistory(canvas.getData()); } }; // src/utils/svg-path-helper.ts var SvgPathHelper = class { static smoothenPathArray(positions, tension) { let newPositions = [...positions]; if (positions.length <= 2) return newPositions; newPositions = [positions[0]]; for (let i = 1; i < positions.length - 2; i++) { const p1 = positions[i]; const p2 = positions[i + 1]; const p3 = positions[i + 2]; const t1 = (1 - tension) / 2; const t2 = 1 - t1; const x = t2 * t2 * t2 * p1.x + 3 * t2 * t2 * t1 * p2.x + 3 * t2 * t1 * t1 * p3.x + t1 * t1 * t1 * p2.x; const y = t2 * t2 * t2 * p1.y + 3 * t2 * t2 * t1 * p2.y + 3 * t2 * t1 * t1 * p3.y + t1 * t1 * t1 * p2.y; newPositions.push({ x, y }); } const lastPoint = positions[positions.length - 1]; newPositions.push(lastPoint); return newPositions; } static pathArrayToSvgPath(positions) { for (let i = 0; i < positions.length - 2; i++) { const p1 = positions[i]; const p2 = positions[i + 1]; const p3 = positions[i + 2]; const currentDirection = { x: p2.x - p1.x, y: p2.y - p1.y }; const nextDirection = { x: p3.x - p2.x, y: p3.y - p2.y }; if (currentDirection.x !== nextDirection.x && currentDirection.y !== nextDirection.y) continue; positions.splice(i + 1, 1); i--; } return positions.map( (position, index) => `${index === 0 ? "M" : "L"} ${position.x} ${position.y}` ).join(" "); } static pathArrayToRoundedSvgPath(pathArray, targetRadius) { if (pathArray.length < 3) return this.pathArrayToSvgPath(pathArray); pathArray = pathArray.filter((position, index) => { if (index === 0) return true; const previous = pathArray[index - 1]; return !(position.x === previous.x && position.y === previous.y); }); const commands = []; commands.push(`M ${pathArray[0].x} ${pathArray[0].y}`); for (let i = 1; i < pathArray.length - 1; i++) { const previous = pathArray[i - 1]; const current = pathArray[i]; const next = pathArray[i + 1]; const prevDelta = { x: current.x - previous.x, y: current.y - previous.y }; const nextDelta = { x: next.x - current.x, y: next.y - current.y }; const prevLen = Math.sqrt(prevDelta.x * prevDelta.x + prevDelta.y * prevDelta.y); const nextLen = Math.sqrt(nextDelta.x * nextDelta.x + nextDelta.y * nextDelta.y); const prevUnit = prevLen ? { x: prevDelta.x / prevLen, y: prevDelta.y / prevLen } : { x: 0, y: 0 }; const nextUnit = nextLen ? { x: nextDelta.x / nextLen, y: nextDelta.y / nextLen } : { x: 0, y: 0 }; let dot = prevUnit.x * nextUnit.x + prevUnit.y * nextUnit.y; dot = Math.max(-1, Math.min(1, dot)); const angle = Math.acos(dot); if (angle < 0.01 || Math.abs(Math.PI - angle) < 0.01) { commands.push(`L ${current.x} ${current.y}`); continue; } const desiredOffset = targetRadius * Math.tan(angle / 2); const d = Math.min(desiredOffset, prevLen / 2, nextLen / 2); const effectiveRadius = d / Math.tan(angle / 2); const firstAnchor = { x: current.x - prevUnit.x * d, y: current.y - prevUnit.y * d }; const secondAnchor = { x: current.x + nextUnit.x * d, y: current.y + nextUnit.y * d }; commands.push(`L ${firstAnchor.x} ${firstAnchor.y}`); const cross = prevDelta.x * nextDelta.y - prevDelta.y * nextDelta.x; const sweepFlag = cross < 0 ? 0 : 1; commands.push(`A ${effectiveRadius} ${effectiveRadius} 0 0 ${sweepFlag} ${secondAnchor.x} ${secondAnchor.y}`); } const last = pathArray[pathArray.length - 1]; commands.push(`L ${last.x} ${last.y}`); return commands.join(" "); } }; // src/canvas-extensions/advanced-styles/edge-pathfinding-methods/edge-pathfinding-method.ts var EdgePathfindingMethod = class { constructor(plugin, canvas, fromNodeBBox, fromPos, fromBBoxSidePos, fromSide, toNodeBBox, toPos, toBBoxSidePos, toSide) { this.plugin = plugin; this.canvas = canvas; this.fromNodeBBox = fromNodeBBox; this.fromPos = fromPos; this.fromBBoxSidePos = fromBBoxSidePos; this.fromSide = fromSide; this.toNodeBBox = toNodeBBox; this.toPos = toPos; this.toBBoxSidePos = toBBoxSidePos; this.toSide = toSide; } }; // src/canvas-extensions/advanced-styles/edge-pathfinding-methods/pathfinding-a-star.ts var MAX_MS_CALCULATION = 100; var BASIC_DIRECTIONS = [ { dx: 1, dy: 0 }, { dx: -1, dy: 0 }, { dx: 0, dy: 1 }, { dx: 0, dy: -1 } ]; var DIAGONAL_DIRECTIONS = [ { dx: 1, dy: 1 }, { dx: -1, dy: 1 }, { dx: 1, dy: -1 }, { dx: -1, dy: -1 } ]; var DIAGONAL_COST = Math.sqrt(2); var ROUND_PATH_RADIUS = 5; var SMOOTHEN_PATH_TENSION = 0.2; var Node = class { constructor(x, y) { this.x = x; this.y = y; this.gCost = 0; this.hCost = 0; this.fCost = 0; this.parent = null; } // Only check for x and y, not gCost, hCost, fCost, or parent inList(nodes) { return nodes.some((n) => n.x === this.x && n.y === this.y); } }; var EdgePathfindingAStar = class extends EdgePathfindingMethod { getPath() { const nodeBBoxes = [...this.canvas.nodes.values()].filter((node) => { const nodeData = node.getData(); if (nodeData.portal === true) return false; const nodeBBox = node.getBBox(); const nodeContainsFromPos = BBoxHelper.insideBBox(this.fromPos, nodeBBox, true); const nodeContainsToPos = BBoxHelper.insideBBox(this.toPos, nodeBBox, true); return !nodeContainsFromPos && !nodeContainsToPos; }).map((node) => node.getBBox()); const fromPosWithMargin = BBoxHelper.moveInDirection(this.fromPos, this.fromSide, 10); const toPosWithMargin = BBoxHelper.moveInDirection(this.toPos, this.toSide, 10); const allowDiagonal = this.plugin.settings.getSetting("edgeStylePathfinderAllowDiagonal"); let pathArray = this.aStarAlgorithm(fromPosWithMargin, toPosWithMargin, nodeBBoxes, CanvasHelper.GRID_SIZE / 2, allowDiagonal); if (!pathArray) return null; pathArray.splice(0, 0, this.fromPos); pathArray.splice(pathArray.length, 0, this.toPos); let svgPath; const roundPath = this.plugin.settings.getSetting("edgeStylePathfinderPathRounded"); if (roundPath) { if (allowDiagonal) svgPath = SvgPathHelper.pathArrayToSvgPath(SvgPathHelper.smoothenPathArray(pathArray, SMOOTHEN_PATH_TENSION)); else svgPath = SvgPathHelper.pathArrayToRoundedSvgPath(pathArray, ROUND_PATH_RADIUS); } else svgPath = SvgPathHelper.pathArrayToSvgPath(pathArray); return { svgPath, center: pathArray[Math.floor(pathArray.length / 2)], rotateArrows: false }; } aStarAlgorithm(fromPos, toPos, obstacles, gridResolution, allowDiagonal) { const start = new Node( Math.floor(fromPos.x / gridResolution) * gridResolution, Math.floor(fromPos.y / gridResolution) * gridResolution ); if (this.fromSide === "right" && fromPos.x !== start.x) start.x += gridResolution; if (this.fromSide === "bottom" && fromPos.y !== start.y) start.y += gridResolution; const end = new Node( Math.floor(toPos.x / gridResolution) * gridResolution, Math.floor(toPos.y / gridResolution) * gridResolution ); if (this.toSide === "right" && toPos.x !== end.x) end.x += gridResolution; if (this.toSide === "bottom" && toPos.y !== end.y) end.y += gridResolution; if (this.isInsideObstacle(start, obstacles) || this.isInsideObstacle(end, obstacles)) return null; const openSet = [start]; const closedSet = []; const startTimestamp = performance.now(); while (openSet.length > 0) { let current = null; let lowestFCost = Infinity; for (const node of openSet) { if (node.fCost < lowestFCost) { current = node; lowestFCost = node.fCost; } } if (performance.now() - startTimestamp > MAX_MS_CALCULATION) return null; if (!current) return null; openSet.splice(openSet.indexOf(current), 1); closedSet.push(current); if (current.x === end.x && current.y === end.y) return [fromPos, ...this.reconstructPath(current), toPos].map((node) => ({ x: node.x, y: node.y })); if (!(current.x === start.x && current.y === start.y) && this.isTouchingObstacle(current, obstacles)) continue; for (const neighbor of this.getPossibleNeighbors(current, obstacles, gridResolution, allowDiagonal)) { if (neighbor.inList(closedSet)) continue; const tentativeGCost = current.gCost + (allowDiagonal ? this.getMovementCost({ dx: neighbor.x - current.x, dy: neighbor.y - current.y }) : 1); if (!neighbor.inList(openSet) || tentativeGCost < neighbor.gCost) { neighbor.parent = current; neighbor.gCost = tentativeGCost; neighbor.hCost = this.heuristic(neighbor, end); neighbor.fCost = neighbor.gCost + neighbor.hCost; openSet.push(neighbor); } } } return null; } // Manhattan distance heuristic(node, end) { return Math.abs(node.x - end.x) + Math.abs(node.y - end.y); } // Define a function to check if a position isn't inside any obstacle isTouchingObstacle(node, obstacles) { return obstacles.some((obstacle) => BBoxHelper.insideBBox(node, obstacle, true)); } isInsideObstacle(node, obstacles) { return obstacles.some((obstacle) => BBoxHelper.insideBBox(node, obstacle, false)); } // Define a function to calculate movement cost based on direction getMovementCost(direction) { return direction.dx !== 0 && direction.dy !== 0 ? DIAGONAL_COST : 1; } getPossibleNeighbors(node, obstacles, gridResolution, allowDiagonal) { const neighbors = []; const availableDirections = allowDiagonal ? [...BASIC_DIRECTIONS, ...DIAGONAL_DIRECTIONS] : BASIC_DIRECTIONS; for (const direction of availableDirections) { const neighbor = new Node( node.x + direction.dx * gridResolution, node.y + direction.dy * gridResolution ); neighbor.gCost = node.gCost + this.getMovementCost(direction); if (this.isInsideObstacle(neighbor, obstacles)) continue; neighbors.push(neighbor); } return neighbors; } reconstructPath(node) { const path = []; while (node) { path.push(node); node = node.parent; } return path.reverse(); } }; // src/canvas-extensions/advanced-styles/edge-pathfinding-methods/pathfinding-direct.ts var EdgePathfindingDirect = class extends EdgePathfindingMethod { getPath() { return { svgPath: SvgPathHelper.pathArrayToSvgPath([this.fromPos, this.toPos]), center: { x: (this.fromPos.x + this.toPos.x) / 2, y: (this.fromPos.y + this.toPos.y) / 2 }, rotateArrows: true }; } }; // src/canvas-extensions/advanced-styles/edge-pathfinding-methods/pathfinding-square.ts var ROUNDED_EDGE_RADIUS = 5; var EdgePathfindingSquare = class extends EdgePathfindingMethod { getPath() { const pathArray = []; let center = { x: (this.fromPos.x + this.toPos.x) / 2, y: (this.fromPos.y + this.toPos.y) / 2 }; const idealCenter = BBoxHelper.isHorizontal(this.fromSide) ? { x: this.toBBoxSidePos.x, y: this.fromBBoxSidePos.y } : { x: this.fromBBoxSidePos.x, y: this.toBBoxSidePos.y }; const isPathCollidingAtFrom = this.fromSide === "top" && idealCenter.y > this.fromPos.y || this.fromSide === "bottom" && idealCenter.y < this.fromPos.y || this.fromSide === "left" && idealCenter.x > this.fromPos.x || this.fromSide === "right" && idealCenter.x < this.fromPos.x; const isPathCollidingAtTo = this.toSide === "top" && idealCenter.y > this.toPos.y || this.toSide === "bottom" && idealCenter.y < this.toPos.y || this.toSide === "left" && idealCenter.x > this.toPos.x || this.toSide === "right" && idealCenter.x < this.toPos.x; if (this.fromSide === this.toSide) { const uPath = this.getUPath(this.fromPos, this.toPos, this.fromSide, this.toSide); pathArray.push(...uPath.pathArray); center = uPath.center; } else if (BBoxHelper.isHorizontal(this.fromSide) === BBoxHelper.isHorizontal(this.toSide)) { let zPath; if (!isPathCollidingAtFrom || !isPathCollidingAtTo) { zPath = this.getZPath(this.fromPos, this.toPos, this.fromSide, this.toSide); pathArray.push(...zPath.pathArray); } else { const fromDirection = BBoxHelper.direction(this.fromSide); const firstFromDetourPoint = BBoxHelper.isHorizontal(this.fromSide) ? { x: CanvasHelper.alignToGrid(this.fromBBoxSidePos.x + fromDirection * CanvasHelper.GRID_SIZE), y: this.fromBBoxSidePos.y } : { x: this.fromBBoxSidePos.x, y: CanvasHelper.alignToGrid(this.fromBBoxSidePos.y + fromDirection * CanvasHelper.GRID_SIZE) }; const toDirection = BBoxHelper.direction(this.toSide); const firstToDetourPoint = BBoxHelper.isHorizontal(this.toSide) ? { x: CanvasHelper.alignToGrid(this.toBBoxSidePos.x + toDirection * CanvasHelper.GRID_SIZE), y: this.toBBoxSidePos.y } : { x: this.toBBoxSidePos.x, y: CanvasHelper.alignToGrid(this.toBBoxSidePos.y + toDirection * CanvasHelper.GRID_SIZE) }; const newFromSide = BBoxHelper.isHorizontal(this.fromSide) ? firstFromDetourPoint.y < this.fromPos.y ? "top" : "bottom" : firstFromDetourPoint.x < firstToDetourPoint.x ? "right" : "left"; zPath = this.getZPath(firstFromDetourPoint, firstToDetourPoint, newFromSide, BBoxHelper.getOppositeSide(newFromSide)); pathArray.push(this.fromPos); pathArray.push(...zPath.pathArray); pathArray.push(this.toPos); } center = zPath.center; } else { if (isPathCollidingAtFrom || isPathCollidingAtTo) { if (isPathCollidingAtFrom && isPathCollidingAtTo) { const direction = BBoxHelper.direction(this.fromSide); let firstFromDetourPoint; let secondFromDetourPoint; if (BBoxHelper.isHorizontal(this.fromSide)) { const combinedBBoxes = BBoxHelper.combineBBoxes([this.fromNodeBBox, this.toNodeBBox]); firstFromDetourPoint = { x: CanvasHelper.alignToGrid((direction > 0 ? combinedBBoxes.maxX : combinedBBoxes.minX) + direction * CanvasHelper.GRID_SIZE), y: this.fromBBoxSidePos.y }; secondFromDetourPoint = { x: firstFromDetourPoint.x, y: BBoxHelper.getCenterOfBBoxSide(this.fromNodeBBox, this.toSide).y }; } else { const combinedBBoxes = BBoxHelper.combineBBoxes([this.fromNodeBBox, this.toNodeBBox]); firstFromDetourPoint = { x: this.fromBBoxSidePos.x, y: CanvasHelper.alignToGrid((direction > 0 ? combinedBBoxes.maxY : combinedBBoxes.minY) + direction * CanvasHelper.GRID_SIZE) }; secondFromDetourPoint = { x: BBoxHelper.getCenterOfBBoxSide(this.fromNodeBBox, this.toSide).x, y: firstFromDetourPoint.y }; } const uPath = this.getUPath(secondFromDetourPoint, this.toPos, this.toSide, this.toSide); pathArray.push(this.fromPos); pathArray.push(firstFromDetourPoint); pathArray.push(...uPath.pathArray); center = pathArray[Math.floor(pathArray.length / 2)]; } else { if (isPathCollidingAtFrom) { const direction = BBoxHelper.direction(this.fromSide); const firstFromDetourPoint = BBoxHelper.isHorizontal(this.fromSide) ? { x: CanvasHelper.alignToGrid(this.fromBBoxSidePos.x + direction * CanvasHelper.GRID_SIZE), y: this.fromBBoxSidePos.y } : { x: this.fromBBoxSidePos.x, y: CanvasHelper.alignToGrid(this.fromBBoxSidePos.y + direction * CanvasHelper.GRID_SIZE) }; const useUPath = BBoxHelper.isHorizontal(this.fromSide) ? this.toPos.y > BBoxHelper.getCenterOfBBoxSide(this.fromNodeBBox, BBoxHelper.getOppositeSide(this.toSide)).y === BBoxHelper.direction(this.toSide) > 0 : this.toPos.x > BBoxHelper.getCenterOfBBoxSide(this.fromNodeBBox, BBoxHelper.getOppositeSide(this.toSide)).x === BBoxHelper.direction(this.toSide) > 0; const connectionSide = useUPath ? this.toSide : BBoxHelper.getOppositeSide(this.toSide); const secondFromDetourPoint = BBoxHelper.isHorizontal(this.fromSide) ? { x: firstFromDetourPoint.x, y: BBoxHelper.getCenterOfBBoxSide(this.fromNodeBBox, connectionSide).y } : { x: BBoxHelper.getCenterOfBBoxSide(this.fromNodeBBox, connectionSide).x, y: firstFromDetourPoint.y }; const path = useUPath ? this.getUPath(secondFromDetourPoint, this.toPos, this.toSide, this.toSide) : this.getZPath(secondFromDetourPoint, this.toPos, this.toSide, this.toSide); pathArray.push(this.fromPos); pathArray.push(firstFromDetourPoint); pathArray.push(...path.pathArray); center = path.center; } if (isPathCollidingAtTo) { const direction = BBoxHelper.direction(this.toSide); const firstToDetourPoint = BBoxHelper.isHorizontal(this.toSide) ? { x: CanvasHelper.alignToGrid(this.toBBoxSidePos.x + direction * CanvasHelper.GRID_SIZE), y: this.toBBoxSidePos.y } : { x: this.toBBoxSidePos.x, y: CanvasHelper.alignToGrid(this.toBBoxSidePos.y + direction * CanvasHelper.GRID_SIZE) }; const useUPath = BBoxHelper.isHorizontal(this.toSide) ? this.fromPos.y > BBoxHelper.getCenterOfBBoxSide(this.toNodeBBox, BBoxHelper.getOppositeSide(this.fromSide)).y === BBoxHelper.direction(this.fromSide) > 0 : this.fromPos.x > BBoxHelper.getCenterOfBBoxSide(this.toNodeBBox, BBoxHelper.getOppositeSide(this.fromSide)).x === BBoxHelper.direction(this.fromSide) > 0; const connectionSide = useUPath ? this.fromSide : BBoxHelper.getOppositeSide(this.fromSide); const secondToDetourPoint = BBoxHelper.isHorizontal(this.toSide) ? { x: firstToDetourPoint.x, y: BBoxHelper.getCenterOfBBoxSide(this.toNodeBBox, connectionSide).y } : { x: BBoxHelper.getCenterOfBBoxSide(this.toNodeBBox, connectionSide).x, y: firstToDetourPoint.y }; const path = useUPath ? this.getUPath(this.fromPos, secondToDetourPoint, this.fromSide, this.fromSide) : this.getZPath(this.fromPos, secondToDetourPoint, this.fromSide, this.fromSide); pathArray.push(...path.pathArray); pathArray.push(secondToDetourPoint); pathArray.push(firstToDetourPoint); pathArray.push(this.toPos); center = path.center; } } } else { pathArray.push( this.fromPos, idealCenter, this.toPos ); center = { x: pathArray[1].x, y: pathArray[1].y }; } } const svgPath = this.plugin.settings.getSetting("edgeStyleSquarePathRounded") ? SvgPathHelper.pathArrayToRoundedSvgPath(pathArray, ROUNDED_EDGE_RADIUS) : SvgPathHelper.pathArrayToSvgPath(pathArray); return { svgPath, center, rotateArrows: false }; } getUPath(fromPos, toPos, fromSide, toSide) { const direction = BBoxHelper.direction(fromSide); if (BBoxHelper.isHorizontal(fromSide)) { const xExtremum = direction > 0 ? Math.max(fromPos.x, toPos.x) : Math.min(fromPos.x, toPos.x); const x = CanvasHelper.alignToGrid(xExtremum + direction * CanvasHelper.GRID_SIZE); return { pathArray: [ fromPos, { x, y: fromPos.y }, { x, y: toPos.y }, toPos ], center: { x, y: (fromPos.y + toPos.y) / 2 } }; } else { const yExtremum = direction > 0 ? Math.max(fromPos.y, toPos.y) : Math.min(fromPos.y, toPos.y); const y = CanvasHelper.alignToGrid(yExtremum + direction * CanvasHelper.GRID_SIZE); return { pathArray: [ fromPos, { x: fromPos.x, y }, { x: toPos.x, y }, toPos ], center: { x: (fromPos.x + toPos.x) / 2, y } }; } } getZPath(fromPos, toPos, fromSide, toSide) { if (BBoxHelper.isHorizontal(fromSide)) { const midX = fromPos.x + (toPos.x - fromPos.x) / 2; return { pathArray: [ fromPos, { x: midX, y: fromPos.y }, { x: midX, y: toPos.y }, toPos ], center: { x: midX, y: (fromPos.y + toPos.y) / 2 } }; } else { const midY = fromPos.y + (toPos.y - fromPos.y) / 2; return { pathArray: [ fromPos, { x: fromPos.x, y: midY }, { x: toPos.x, y: midY }, toPos ], center: { x: (fromPos.x + toPos.x) / 2, y: midY } }; } } }; // src/canvas-extensions/advanced-styles/edge-styles.ts var EDGE_PATHFINDING_METHODS = { "direct": EdgePathfindingDirect, "square": EdgePathfindingSquare, "a-star": EdgePathfindingAStar }; var MAX_LIVE_UPDATE_SELECTION_SIZE = 5; var EdgeStylesExtension = class extends CanvasExtension { isEnabled() { return "edgesStylingFeatureEnabled"; } init() { this.cssStylesManager = new CssStylesConfigManager(this.plugin, "advanced-canvas-edge-style", styleAttributeValidator); this.plugin.registerEvent(this.plugin.app.workspace.on( "advanced-canvas:popup-menu-created", (canvas) => this.onPopupMenuCreated(canvas) )); this.plugin.registerEvent(this.plugin.app.workspace.on( "advanced-canvas:edge-changed", (canvas, edge) => this.onEdgeChanged(canvas, edge) )); this.plugin.registerEvent(this.plugin.app.workspace.on( "advanced-canvas:edge-center-requested", (canvas, edge, center) => this.onEdgeCenterRequested(canvas, edge, center) )); this.plugin.registerEvent(this.plugin.app.workspace.on( "advanced-canvas:node-added", (canvas, node) => { if (canvas.dirty.size > 1 && !canvas.isPasting) return; this.updateAllEdgesInArea(canvas, node.getBBox()); } )); this.plugin.registerEvent(this.plugin.app.workspace.on( "advanced-canvas:node-moved", // Only update edges this way if a node got moved with the arrow keys (canvas, node, keyboard) => node.initialized && keyboard ? this.updateAllEdgesInArea(canvas, node.getBBox()) : void 0 )); this.plugin.registerEvent(this.plugin.app.workspace.on( "advanced-canvas:node-removed", (canvas, node) => this.updateAllEdgesInArea(canvas, node.getBBox()) )); this.plugin.registerEvent(this.plugin.app.workspace.on( "advanced-canvas:dragging-state-changed", (canvas, isDragging) => { if (isDragging) return; const selectedNodes = canvas.getSelectionData().nodes.map((nodeData) => canvas.nodes.get(nodeData.id)).filter((node) => node !== void 0); const selectedNodeBBoxes = selectedNodes.map((node) => node.getBBox()); const selectedNodeBBox = BBoxHelper.combineBBoxes(selectedNodeBBoxes); this.updateAllEdgesInArea(canvas, selectedNodeBBox); } )); } // Skip if isDragging and setting isn't enabled and not connecting an edge shouldUpdateEdge(canvas) { return !canvas.isDragging || this.plugin.settings.getSetting("edgeStyleUpdateWhileDragging") || canvas.canvasEl.hasClass("is-connecting"); } onPopupMenuCreated(canvas) { var _a; const selectedEdges = [...canvas.selection].filter((item) => item.path !== void 0); if (canvas.readonly || selectedEdges.length === 0 || selectedEdges.length !== canvas.selection.size) return; CanvasHelper.addStyleAttributesToPopup( this.plugin, canvas, [ ...BUILTIN_EDGE_STYLE_ATTRIBUTES, /* Legacy */ ...this.plugin.settings.getSetting("customEdgeStyleAttributes"), ...this.cssStylesManager.getStyles() ], (_a = selectedEdges[0].getData().styleAttributes) != null ? _a : {}, (attribute, value) => this.setStyleAttributeForSelection(canvas, attribute, value) ); } setStyleAttributeForSelection(canvas, attribute, value) { const selectedEdges = [...canvas.selection].filter((item) => item.path !== void 0); for (const edge of selectedEdges) { const edgeData = edge.getData(); edge.setData({ ...edgeData, styleAttributes: { ...edgeData.styleAttributes, [attribute.key]: value } }); } canvas.pushHistory(canvas.getData()); } updateAllEdgesInArea(canvas, bbox) { if (!this.shouldUpdateEdge(canvas)) return; for (const edge of canvas.edges.values()) { if (!BBoxHelper.isColliding(edge.getBBox(), bbox)) continue; canvas.markDirty(edge); } } onEdgeChanged(canvas, edge) { var _a, _b, _c, _d, _e, _f, _g; if (!canvas.dirty.has(edge) && !canvas.selection.has(edge)) return; if (!this.shouldUpdateEdge(canvas)) { const tooManySelected = canvas.selection.size > MAX_LIVE_UPDATE_SELECTION_SIZE; if (tooManySelected) return; const groupNodesSelected = [...canvas.selection].some((item) => { var _a2; return ((_a2 = item.getData()) == null ? void 0 : _a2.type) === "group"; }); if (groupNodesSelected) return; } const edgeData = edge.getData(); if (!edge.bezier) return; edge.center = void 0; edge.updatePath(); const pathfindingMethod = (_a = edgeData.styleAttributes) == null ? void 0 : _a.pathfindingMethod; if (pathfindingMethod && pathfindingMethod in EDGE_PATHFINDING_METHODS) { const fromNodeBBox = edge.from.node.getBBox(); const fromBBoxSidePos = BBoxHelper.getCenterOfBBoxSide(fromNodeBBox, edge.from.side); const fromPos = edge.from.end === "none" ? fromBBoxSidePos : edge.bezier.from; const toNodeBBox = edge.to.node.getBBox(); const toBBoxSidePos = BBoxHelper.getCenterOfBBoxSide(toNodeBBox, edge.to.side); const toPos = edge.to.end === "none" ? toBBoxSidePos : edge.bezier.to; const path = new EDGE_PATHFINDING_METHODS[pathfindingMethod]( this.plugin, canvas, fromNodeBBox, fromPos, fromBBoxSidePos, edge.from.side, toNodeBBox, toPos, toBBoxSidePos, edge.to.side ).getPath(); if (!path) return; edge.center = path.center; edge.path.interaction.setAttr("d", path == null ? void 0 : path.svgPath); edge.path.display.setAttr("d", path == null ? void 0 : path.svgPath); } (_b = edge.labelElement) == null ? void 0 : _b.render(); const arrowPolygonPoints = this.getArrowPolygonPoints((_c = edgeData.styleAttributes) == null ? void 0 : _c.arrow); if ((_d = edge.fromLineEnd) == null ? void 0 : _d.el) (_e = edge.fromLineEnd.el.querySelector("polygon")) == null ? void 0 : _e.setAttribute("points", arrowPolygonPoints); if ((_f = edge.toLineEnd) == null ? void 0 : _f.el) (_g = edge.toLineEnd.el.querySelector("polygon")) == null ? void 0 : _g.setAttribute("points", arrowPolygonPoints); } onEdgeCenterRequested(_canvas, edge, center) { var _a, _b, _c, _d; center.x = (_b = (_a = edge.center) == null ? void 0 : _a.x) != null ? _b : center.x; center.y = (_d = (_c = edge.center) == null ? void 0 : _c.y) != null ? _d : center.y; } getArrowPolygonPoints(arrowStyle) { if (arrowStyle === "halved-triangle") return `-2,0 7.5,12 -2,12`; else if (arrowStyle === "thin-triangle") return `0,0 7,10 0,0 0,10 0,0 -7,10`; else if (arrowStyle === "diamond" || arrowStyle === "diamond-outline") return `0,0 5,10 0,20 -5,10`; else if (arrowStyle === "circle" || arrowStyle === "circle-outline") return `0 0, 4.95 1.8, 7.5 6.45, 6.6 11.7, 2.7 15, -2.7 15, -6.6 11.7, -7.5 6.45, -4.95 1.8`; else if (arrowStyle === "blunt") return `-10,8 10,8 10,6 -10,6`; else return `0,0 6.5,10.4 -6.5,10.4`; } }; // src/canvas-extensions/dataset-exposers/canvas-metadata-exposer.ts var CanvasMetadataExposerExtension = class extends CanvasExtension { isEnabled() { return true; } init() { this.plugin.registerEvent(this.plugin.app.workspace.on( "advanced-canvas:canvas-metadata-changed", (canvas) => this.updateExposedSettings(canvas) )); this.plugin.registerEvent(this.plugin.app.workspace.on( "advanced-canvas:canvas-changed", (canvas) => this.updateExposedSettings(canvas) )); } updateExposedSettings(canvas) { const startNodeId = canvas.metadata["startNode"]; for (const [nodeId, node] of canvas.nodes) { if (nodeId === startNodeId) node.nodeEl.dataset.isStartNode = "true"; else delete node.nodeEl.dataset.isStartNode; } } }; // src/canvas-extensions/dataset-exposers/node-exposer.ts function getExposedNodeData(settings) { const exposedData = []; if (settings.getSetting("nodeStylingFeatureEnabled")) exposedData.push("styleAttributes"); if (settings.getSetting("collapsibleGroupsFeatureEnabled")) exposedData.push("collapsed"); if (settings.getSetting("portalsFeatureEnabled")) exposedData.push("isPortalLoaded"); return exposedData; } var NodeExposerExtension = class extends CanvasExtension { isEnabled() { return true; } init() { this.plugin.registerEvent(this.plugin.app.workspace.on( "advanced-canvas:node-changed", (_canvas, node) => { const nodeData = node == null ? void 0 : node.getData(); if (!nodeData) return; for (const exposedDataKey of getExposedNodeData(this.plugin.settings)) { const datasetPairs = nodeData[exposedDataKey] instanceof Object ? Object.entries(nodeData[exposedDataKey]) : [[exposedDataKey, nodeData[exposedDataKey]]]; for (const [key, value] of datasetPairs) { if (!value) delete node.nodeEl.dataset[key]; else node.nodeEl.dataset[key] = value; } } } )); } }; // src/canvas-extensions/dataset-exposers/node-interaction-exposer.ts var TARGET_NODE_DATASET_PREFIX = "target"; var NodeInteractionExposerExtension = class extends CanvasExtension { isEnabled() { return true; } init() { this.plugin.registerEvent(this.plugin.app.workspace.on( "advanced-canvas:node-interaction", (canvas, node) => { const nodeData = node == null ? void 0 : node.getData(); if (!nodeData) return; const interactionEl = canvas.nodeInteractionLayer.interactionEl; if (!interactionEl) return; for (const exposedDataKey of getExposedNodeData(this.plugin.settings)) { const datasetPairs = nodeData[exposedDataKey] instanceof Object ? Object.entries(nodeData[exposedDataKey]) : [[exposedDataKey, nodeData[exposedDataKey]]]; for (const [key, value] of datasetPairs) { const modifiedKey = TARGET_NODE_DATASET_PREFIX + key.toString().charAt(0).toUpperCase() + key.toString().slice(1); if (!value) delete interactionEl.dataset[modifiedKey]; else interactionEl.dataset[modifiedKey] = value; } } if (PortalsCanvasExtension.isPortalElement(node)) interactionEl.dataset.isFromPortal = "true"; else delete interactionEl.dataset.isFromPortal; } )); } }; // src/canvas-extensions/dataset-exposers/edge-exposer.ts function getExposedEdgeData(settings) { const exposedData = []; if (settings.getSetting("edgesStylingFeatureEnabled")) exposedData.push("styleAttributes"); return exposedData; } var EdgeExposerExtension = class extends CanvasExtension { isEnabled() { return true; } init() { this.plugin.registerEvent(this.plugin.app.workspace.on( "advanced-canvas:edge-changed", (_canvas, edge) => { var _a, _b, _c, _d; const edgeData = edge == null ? void 0 : edge.getData(); if (!edgeData) return; for (const exposedDataKey of getExposedEdgeData(this.plugin.settings)) { const datasetPairs = edgeData[exposedDataKey] instanceof Object ? Object.entries(edgeData[exposedDataKey]) : [[exposedDataKey, edgeData[exposedDataKey]]]; for (const [key, value] of datasetPairs) { const stringifiedKey = key == null ? void 0 : key.toString(); if (!stringifiedKey) continue; if (!value) { delete edge.path.display.dataset[stringifiedKey]; if ((_a = edge.fromLineEnd) == null ? void 0 : _a.el) delete edge.fromLineEnd.el.dataset[stringifiedKey]; if ((_b = edge.toLineEnd) == null ? void 0 : _b.el) delete edge.toLineEnd.el.dataset[stringifiedKey]; } else { edge.path.display.dataset[stringifiedKey] = value.toString(); if ((_c = edge.fromLineEnd) == null ? void 0 : _c.el) edge.fromLineEnd.el.dataset[stringifiedKey] = value.toString(); if ((_d = edge.toLineEnd) == null ? void 0 : _d.el) edge.toLineEnd.el.dataset[stringifiedKey] = value.toString(); } } } } )); } }; // src/canvas-extensions/dataset-exposers/canvas-wrapper-exposer.ts var EXPOSED_SETTINGS = [ "disableFontSizeRelativeToZoom", "hideBackgroundGridWhenInReadonly", "collapsibleGroupsFeatureEnabled", "collapsedGroupPreviewOnDrag", "allowFloatingEdgeCreation" ]; var CanvasWrapperExposerExtension = class extends CanvasExtension { isEnabled() { return true; } init() { this.plugin.registerEvent(this.plugin.app.workspace.on( "advanced-canvas:settings-changed", () => this.updateExposedSettings(this.plugin.getCurrentCanvas()) )); this.plugin.registerEvent(this.plugin.app.workspace.on( "advanced-canvas:canvas-changed", (canvas) => this.updateExposedSettings(canvas) )); this.plugin.registerEvent(this.plugin.app.workspace.on( "advanced-canvas:dragging-state-changed", (canvas, dragging) => { if (dragging) canvas.wrapperEl.dataset.isDragging = "true"; else delete canvas.wrapperEl.dataset.isDragging; } )); } updateExposedSettings(canvas) { if (!canvas) return; for (const setting of EXPOSED_SETTINGS) { canvas.wrapperEl.dataset[setting] = this.plugin.settings.getSetting(setting).toString(); } } }; // src/main.ts var PATCHERS = [ CanvasPatcher, LinkSuggestionsPatcher, EmbedPatcher, MetadataCachePatcher, BacklinksPatcher, OutgoingLinksPatcher, PropertiesPatcher, SearchPatcher, SearchCommandPatcher ]; var CANVAS_EXTENSIONS = [ // Advanced JSON Canvas Extensions MetadataCanvasExtension, NodeStylesExtension, EdgeStylesExtension, NodeRatioCanvasExtension, FloatingEdgeCanvasExtension, AutoResizeNodeCanvasExtension, CollapsibleGroupsCanvasExtension, ColorPaletteCanvasExtension, PresentationCanvasExtension, PortalsCanvasExtension, // UI Extensions (Non-savable data) CanvasMetadataExposerExtension, CanvasWrapperExposerExtension, NodeExposerExtension, EdgeExposerExtension, NodeInteractionExposerExtension, FrontmatterControlButtonCanvasExtension, BetterDefaultSettingsCanvasExtension, CommandsCanvasExtension, BetterReadonlyCanvasExtension, GroupCanvasExtension, VariableBreakpointCanvasExtension, EdgeHighlightCanvasExtension, AutoFileNodeEdgesCanvasExtension, FlipEdgeCanvasExtension, ZOrderingCanvasExtension, ExportCanvasExtension, FocusModeCanvasExtension, EncapsulateCanvasExtension ]; var AdvancedCanvasPlugin = class extends import_obsidian18.Plugin { async onload() { IconsHelper.addIcons(); this.settings = new SettingsManager(this); await this.settings.loadSettings(); this.settings.addSettingsTab(); this.windowsManager = new WindowsManager(this); this.patchers = PATCHERS.map((Patcher2) => { try { return new Patcher2(this); } catch (e) { console.error(`Error initializing patcher ${Patcher2.name}:`, e); } }); this.canvasExtensions = CANVAS_EXTENSIONS.map((Extension) => { try { return new Extension(this); } catch (e) { console.error(`Error initializing ac-extension ${Extension.name}:`, e); } }); } onunload() { } getCanvases() { return this.app.workspace.getLeavesOfType("canvas").map((leaf) => { var _a; return (_a = leaf.view) == null ? void 0 : _a.canvas; }).filter((canvas) => canvas); } getCurrentCanvasView() { const canvasView = this.app.workspace.getActiveViewOfType(import_obsidian18.ItemView); if ((canvasView == null ? void 0 : canvasView.getViewType()) !== "canvas") return null; return canvasView; } getCurrentCanvas() { var _a; return ((_a = this.getCurrentCanvasView()) == null ? void 0 : _a.canvas) || null; } createFileSnapshot(path, content) { var _a; const fileRecoveryPlugin = (_a = this.app.internalPlugins.plugins["file-recovery"]) == null ? void 0 : _a.instance; if (!fileRecoveryPlugin) return; fileRecoveryPlugin.forceAdd(path, content); } // this.app.plugins.plugins["advanced-canvas"].enableDebugMode() enableDebugMode() { if (this.debugHelper) return; this.debugHelper = new DebugHelper(this); } }; /* nosourcemap */