Obsidean_VM/.obsidian/plugins/advanced-canvas/main.js

8644 lines
392 KiB
JavaScript

/*
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<define>[0]} */
fn,
"length",
length,
true,
true
);
} else {
define(
/** @type {Parameters<define>[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<typeof callBindBasic>[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<typeof cmpOpt>} */
cmpOpt.length > 2 && /** @type {import('.').Getter['get']} */
function get2(k) {
return node[k];
}
);
return function(a, b) {
return (
/** @type {NonNullable<typeof cmpOpt>} */
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": `<rect rx="31.25" height="62.5" width="93.75" y="18.75" x="3.125" stroke-width="8.333" stroke="currentColor" fill="transparent"/>`,
"shape-parallelogram": `<rect transform="skewX(-20)" rx="5" height="50" width="70" y="25" x="35" stroke-width="8.333" stroke="currentColor" fill="transparent"/>`,
"shape-predefined-process": `
<g stroke-width="2" stroke="currentColor" fill="none" transform="matrix(4.166667,0,0,4.166667,0,0)">
<path d="M 4.999687 3 L 19.000312 3 C 20.104688 3 21 3.895312 21 4.999687 L 21 19.000312 C 21 20.104688 20.104688 21 19.000312 21 L 4.999687 21 C 3.895312 21 3 20.104688 3 19.000312 L 3 4.999687 C 3 3.895312 3.895312 3 4.999687 3 Z M 4.999687 3 "/>
<path d="M 7 3 L 7 21 "/>
<path d="M 17 3 L 17 21 "/>
</g>
`,
"shape-document": `<path transform="translate(0, 5)" stroke="currentColor" fill="none" stroke-width="8.333" d="M83.75 25C85.82 25 87.5 26.68 87.5 28.75L87.5 64.375Q68.75 54.25 50 64.375 31.25 74.5 12.5 64.375L12.5 30.625 12.5 28.75C12.5 26.68 14.18 25 16.25 25Z"/>`,
"shape-database": `
<g transform="translate(20, 20)" stroke-width="8.333" stroke="currentColor" fill="none">
<path d="M 1 51 L 1 11 C 1 5.48 14.43 1 31 1 C 47.57 1 61 5.48 61 11 L 61 51 C 61 56.52 47.57 61 31 61 C 14.43 61 1 56.52 1 51 Z"/>
<path d="M 1 11 C 1 16.52 14.43 21 31 21 C 47.57 21 61 16.52 61 11"/>
</g>
`,
"border-solid": `<path stroke="currentColor" fill="none" stroke-width="8.333" d="M91.6667 45.8333v4.1667c0 2.0833-2.0833 4.1667-4.1667 4.1667H12.5c-2.0833 0-4.1667-2.0833-4.1667-4.1667v-4.1667"/>`,
"border-dashed": `<path stroke="currentColor" fill="none" stroke-width="8.333" stroke-dasharray="13.7" d="M91.6667 45.8333v4.1667c0 2.0833-2.0833 4.1667-4.1667 4.1667H12.5c-2.0833 0-4.1667-2.0833-4.1667-4.1667v-4.1667"/>`,
"border-dotted": `<path stroke="currentColor" fill="none" stroke-width="8.333" stroke-dasharray="8.7" d="M91.6667 45.8333v4.1667c0 2.0833-2.0833 4.1667-4.1667 4.1667H12.5c-2.0833 0-4.1667-2.0833-4.1667-4.1667v-4.1667"/>`,
"path-solid": `<path stroke="currentColor" fill="none" stroke-width="8.5" d="M37.5 79.1667h35.4167a14.5833 14.5833 90 000-29.1667h-45.8333a14.5833 14.5833 90 010-29.1667H62.5"/>`,
"path-dotted": `<path stroke="currentColor" fill="none" stroke-width="8.5" stroke-dasharray="8.8" d="M37.5 79.1667h35.4167a14.5833 14.5833 90 000-29.1667h-45.8333a14.5833 14.5833 90 010-29.1667H62.5"/>`,
"path-short-dashed": `<path stroke="currentColor" fill="none" stroke-width="8.5" stroke-dasharray="15" d="M37.5 79.1667h35.4167a14.5833 14.5833 90 000-29.1667h-45.8333a14.5833 14.5833 90 010-29.1667H62.5"/>`,
"path-long-dashed": `<path stroke="currentColor" fill="none" stroke-width="8.5" stroke-dasharray="23" d="M37.5 79.1667h35.4167a14.5833 14.5833 90 000-29.1667h-45.8333a14.5833 14.5833 90 010-29.1667H62.5"/>`,
"arrow-triangle": `<path stroke="currentColor" fill="currentColor" d="M 15 10 L 85 50 L 15 90 Z"/>`,
"arrow-triangle-outline": `<path stroke="currentColor" stroke-width="8.5" fill="none" d="M 15 10 L 85 50 L 15 90 Z"/>`,
"arrow-thin-triangle": `<path stroke="currentColor" stroke-width="8.5" fill="none" d="M 15 10 L 85 50 L 15 90"/>`,
"arrow-halved-triangle": `<path stroke="currentColor" fill="currentColor" d="M 15 50 L 85 50 L 15 90 Z"/>`,
"arrow-diamond": `<path stroke="currentColor" fill="currentColor" d="M 50 0 L 100 50 L 50 100 L 0 50 Z"/>`,
"arrow-diamond-outline": `<path stroke="currentColor" stroke-width="8.5" fill="none" d="M 50 0 L 100 50 L 50 100 L 0 50 Z"/>`,
"arrow-circle": `<circle stroke="currentColor" fill="currentColor" cx="50" cy="50" r="45"/>`,
"arrow-circle-outline": `<circle stroke="currentColor" stroke-width="8.5" fill="none" cx="50" cy="50" r="45"/>`,
"pathfinding-method-bezier": `<path stroke="currentColor" fill="none" stroke-width="8.5" d="M37.5 79.1667h35.4167a14.5833 14.5833 90 000-29.1667h-45.8333a14.5833 14.5833 90 010-29.1667H62.5"/>`,
"pathfinding-method-square": `<path stroke="currentColor" fill="none" stroke-width="8.5" d="M72.9167 79.1667 72.9167 50 27.0833 50 27.0833 20.8333"/>`
};
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,UklGRrosAABXRUJQVlA4TK4sAAAv1wNDEL/CoJEkRXUCbvwrekfM/BYQspGkHsCNw/nbvcAzahtJkue7R/GnubUAykDaNvFv9r2CqU3bgHHKGHIH7H9DeOynEYZHCKFOj1neMfXZ0SmmUzuYgs6P2cH0fjuY11JBq5hO7ejVDqZTnWJ29Op+1twlRYq6rzLHZ6dIkSJFCnjb/mlP41jbjKzG2JjQKAiRUTrz/JCnNasnK3MmnnWm07aORtgyyHpA3/+r2BiOqvpXifW0bRH9h4ZtO9DqlUuZ7LSRz/d9JOv8Ofs/iSZZzKPZdHr9ykynsyheLEGwfD6k6WTvcCZ7h/M/ZfHNZ9ejcOBthqPJLJaMLokmw8DraK6m8fJ/tMJGk5FXbvfL/7NYgjyYXQXEg5nE/zP12uw6GPCaYBQlrD5vRzzHchX9VwTLOJpcj4bhixmOriazeIFImh44snA0mkzni1MR8SQcyJjhZMF1XCPGQwmvk/9qlDKhZ1kyjWFOVvNn0tT7yE5An2AgacIoYQjPflwjQ4IvkyRZxHE8j17MbLpvJtdSZnrARHsmfjHPR7a0rJRBp+liKvEYXp9yHslzZpc31zF1TeYkpfTksYijaPZyuhi9EKPBQJV5Ia1HL6ecaB7Hiigl8fQSXC/gi7HwBKkPitLlWPl/FsgdiZ6TSBw9VyqvhuHAGBM+n12ms7neU0t8hU7TLd8O94qWE26FowTHXomHktQH+tstF9Hs+uqZFjDQBKOraRQvDStmwgi+xhlGJ9ka9sryM+kjeYvLV/ZhQtkY3UQNdzoZs38kVwk8cXqdnJhr4l97DJBpwwTxtclwYKZRy52WSZFv4aucYXRarkmnqxlG/pmBfdyzZ22fPjCj2QIZiyH4mT8ZydGMJxEiplwlna6WVygH8hmUz6BHTHg9hwJIITBjKsckP+qr5cmDxet8he2ZAFWchwm0wMH2qgCkx3IEfuafB8IJ8MRYIHhoAtybYxYhCozqjt1Gl77IQjq1DJcce52Uiz8PDTrUIgA7joU4W9m+NWktQyDMA+wz/wzh2x+dMPhMC2kawB3Hol/j1it8mmGTdMkIhMlzsuiqahIt4S2SIuBeNCOMqN9i19XmMCXM7DTB54HlZG4iWZ/vyZUIxwLUvcHJ0yA5VYL10cJTkzyJArwF4tYSydMTIIwVopO027WvzK5LwfD6iLpUnAnLWJM8bd7u8/3DB617x69O6yepF7/AK93V22Ll7o4aty7KZiePtK0eDh9Stt7WLAfzmYjv6bSywDr6zz3ZgEBeJ8ZbLQLW3F64O5rJ1ts2FfSp1pnfwbjHlqGEwPHtN2mbaGGDVPcGr3V+dpLFv3vJ7UxmXXUiaNekQ3GPHZlX02ucSd1agUsW2zVVuS2Ksmw4ypKRTK0z3e0f2basyUeWnBKWK7Nv3R2vWdWdwBrZUFdGnJzJXjdvBTCmlzJPx0qZFZ2mm7ETIGm9XXGWVtenlU2f/Hw48j/vGsCRzHRrB6Tdntm1B0xTs5n2iOn2jSEii7f0CpsATRckrDZ9WvsmwNPn5c8Z8zr0SrplOxBXi3stxCupXde2dV2VZVEUD+v1yjmX3eGa7PmoVuv1+oXuLav6RdwBUbGOmANRM3smk+JGr5hJwil+6/+3Tk8mW++tga/sWKmQh47ihRpH2rV1VRbF2rk7E8zzGebhpXrbdjp4WiEJFe1MmlWUPzg+YMlnK+Ln7/25BydCAxOGNYA89MSAirmkdTtKOmVQrmYXI5bFwzMZYJjJVutt1e5EQkH4dfRyZt0Rjvu5HONak1nik0BeTj5ZtyuMgq2jouQ/kIrg4KhrdfX2WeRgqFk9VNwyzXAB4Fdnogku+hyjjHGpJyanghoMS0kA7llCHUcMYdP6sGaAqUG3TYqnEBZKp5bMn4ShM1dax1UX7MdNQInoE1JJuSVapGXEYvn4yla/1DIK2oT9HtkqKDshmcYj3+fceP7di97HFZGHtgJL6CnBCpna3xG27b2ZRD9Rb6jFiT4JSJZt6STQvP7y5bxm/QixDFY9l2Aqlp0cp2rH78w4wq/uTDV8KoGimiNjipXJ8XyiVgAWz+UJE3v6TAXrWLqjNWiEdLr0xpyF7dsrZl3zLGL7MOf49UFwiVoBjio8XWLYOcwkzlHgQKTTqb/AgXGtP4JvO/FlhFJlq44DjDxtPQuVXseIT3QCHVl9+DBQ3i/0FjjQ2b79ZDiivhahIxv+qlrK+m4onNt5rweC4owLck2Fs3GWcgYecogR+3rlM+pbgFTZHhm1FVYw5OKsz/2wrBxTtsaUxk8FOJMm7IX8VT/R35TuQpQBLV8cOKXKpMcRErCFTt0PHi6iM/S6IBIvZ7KH3q6WUowZUUsbuV0Aa52706KN6FuSxTbtURfTWYpxJvt7pwWv2wknN0yBbu2FixNEHb2EF/scdTGdyIMzyaAd0POeYcIqM3fyao6ACb48KaIa0yy646EKAxjJxEcRhvwx977nkJPvU0uzVjFTwPaUQKQ5f60pMnOcCuOQLDE/fuR96bnjjnzsHaO4LBQywRd+x3Fq7NOqSNjdwW0Ek3K8MLY/fhVt+eY+LZHQsv0a2N7d++HEcDunK1l3GEdRMTCgIoI1XQsdr3IdJMSkCZFUUqIFpBVPC8XV1CkhRL32hiP+IiZB4sOdeQa1ZQBXM50hXn2pItoTEW9Jb6hjE6tS7egaMW855Ii9GkXHJj1fEFzBTSrTFG+jp10YFqu4nDO/u4N94ZplnxKsr9JP+bMp9s2mPGpqX1OVPmZTvDL5nnHPBm1h6xV4DMjezMiykFMwyFv/QOqqlxmKvI7a7HeMJy/P3Kf7YlNWL72Ne/Uujtsl+u6lG/SX802euwx0uWKoNHXCKWVH11wAk5v3s6te1rR6lUlgqA6/1HRE+x4ka7i8KKtm1w2MMOmubaqyyJ3YQm+nMycQkoAvNKApb8iYC1+bZQ/EAuKHQAnuUFASMQbgTGb5pmq6gV1m12zyDCWykE5dSROShfeJHZRSvGAYm+fkehQeLVnD4ctQV+2+243Q30+ROSCjx90xOOQK00SfNvXhfS0Lytxx65pjlwCyxHG4yT3lbW+yiCZXDBeaGV5ZPGD6yAKNrw4fA7Jb89AHRZ0OTDVdfS8vPw+Wvtsw/FVYie6Kr43wMp7wDuMxGM1iUzH0TY13/YREkCbKG2t82Ppbv+eUYdNy4Rg0aXqRXA+4CW/uNTJ6saFwGt9HYt43kKaJsvII1W/t7o6pD1mqE4AKJBtUGWfNoOm4jOl3xNIHN0Mw9t6np+Dt0tfSge2mzXn6kKU5MSG09I6obXM78oVGDvj0m8fS9wNzKrFTECSW+ZDzQyEMD15whPF3/MocmNP/1qvOCfvKBeAIwsIoMS40govDOO2gIxKkibJmYKmR7XymJTkhKkO38JL84Lb8xxzDo23BR55YacOro0XWhxnSYnY94ctxVWUhr4DwfTkArI8BpnFu56/as5yFiMP9Mbbz01Zda6bDlQ5obYjI1+XqJagHd9oSlN0i2LS54mwXIK8EsHw9hMfeXJnZ0FByffBwsbUhRvzl3dPAToPRrejOv53opR82CHDH1VaB976AHphnGNkpNO/UditQAbNrphSaqKbbfvF0IupuC99YHQQ81SpBe7gO0AffZuX2ozo0B6odwNoQlO2cZHvIpPcSu0yPSy+QhCaQnKRC67D6FjZuO3XoXqf2DFgbgrC9I+3RT2Yj4AQzP1QYgGx03ykeS7oxe8vHjEax57CvDCgaAo+kq0P3lCkFnABYD/IwgxgqtFbPmX3KMLk6VIcKH+z+jeeeyGgFTl+tguTGOwwgtllslQ+13Q7MfUNr3D6wibo9ISjD1H0XiJ9t0/KhBQEgI2mlfiScduiky25jkmz3CCIbQsihHx4Y/v5eimyFcN3cDRYqqB76tJuRFZ6hDduNTPHDXbwn/iKHlJIwe810GfOF7oETZybYM4thpUA4NwELG7YdVjp1HfcrDcHtOVPLyxRTrCS3hrsm7AkQKhLdhk0DrbxLeGXiWcXtV5ennrXW9YqD61f6Xvz+NvaH2rpevR7S7l6HmKnFocYm6K4WQoQlpXjnlpq7vnVZGKMtHVDngBUcXdrJfQttVawy0l02VG1q69sO/ZCx+8ER7Dtxdg2hcejACzuC23+mkt7MkTi1DrhoYhyaJ95QOIPYIql5C+sy5twNYIKKCDyMmiAz70HjhCVUGRC9XsIWTWw32rBiPv+VfGPPnBnUo1qlDE9+PWHiJahkLyRrXWdtM0VfFc/10TXjfRfVskT0DqadEZhfJeCTyQy9bWdg9FMDYn30TKwZGhf2+owQcuWdMk2m5w9/WdlDLVnUVyxogHrUWd1pfYv0SfCIV3Vn3XIJ+QrGBS4qsRiJV8G5ZJUS7cTw5Z+//+HHn25ubn784fs/f8WIr755/+OPz3/tTz++/+Z3XwihlBiHaSnKzN7AVP6EqFKGxKJhEL2PHctiTMidrvVUx/ioQ8qH3ELt/dX3Nx9vj5iPP339JQN+9/fjf+6/fvyzwEudJ+dNKpJMUci7tlO6T7uGYDW2hi1LLVJzmfaXj1BHEe2DlSC5F8AXf/9w62l++jPxz/3+xv/P5cajDAOr4HoBmpjcPULtw72mY+WtKSE3epBVxAwCZENSxxUblFd+9/MtxfzyNeUk9JH25/JiJVNHb7mEi9DEJFThVUutiUdj1DJTEFK0f9EN/6tkN2b9kFvuyvxeWU9b8Y3mu701lBXK9yGyudUT0kH58Q6gXNPKTB0onGmNvv47oBzGNa0lrHeGSnnxXNgzmB+8z0IMJyI+SJWfD3KS89KiUXywCSv0jYQz1rknckiM6/HUDmMAZAlNlogQ8st/3d7eipwZ/vbxlsf8nQ1Sd/FRyQV8QAGkH8/YmHV5BokVezZq1pi+/5wtDtJxTGlE0Y5XG8afhucyv/75CP5xu2d4PDkhUOp3cgHtGYbXlstX60g4FSJQqeWWFQcqzTCeqwMHIjA8hlZeUvOPW07z9UH8eHvLuHzFBpkw3jmM4YpJ9vilLHE+gMuJKWZoRFyFvMSkLj6RBpnQpnDXqXM1240JjziJopIPP97ymm8P8N9vblnNr1+LI0v56fiajJ05YAm0c4rZCp/piwtzz3R/ZCVlkX/KDo/U6H5z4K7v+FdIKSHfS/k0PyIqb1ENrxVZ/Zn/72WBlLOROqE2WiHa8q3O4MlfWlr93IS+Eh3WKTsFua/itM59v8PNXlWCjfQ652QnN3yv8puvXp2G+M3vpJFRsplUBagyBsXABrnBkyERzIRrbMoaVnbHaxVZXnLwB8JECi2/5WS+Sf29v34lXdFu/dFK6fltzH2vR/U8w6EBrcg6bIhH2zZluTdmwpptcFcLOnOyEMWfbkXMzTPn/lbE/PIFGWJJvZMSnOdGBdI/NuaHlBKGa452X6Zo92p0wFy9mjPFBKHzpRahMY8qw6tjNOBExyMv/0UGt//+5Uehv/dGGCv2v9eZGlfFYFcmjF03Jk4BH8P4toIR6/C2LjHRqgI9Bmz8eCtlfrmVMt/K4i7ljiqzNK4tj7VgCZeEKT7lnk7BpdQlwWoAWGKx8fWtOvPrl7LYvYCVPUvmspgSiMfqWji9llJzvzqcxCJqbiUADLGi4PHTZ25kURMoeRm0psTAaNXswOcVXwWi0zJH9DgHhR0WHP+41Wh+J4qSwHmTQW0IdgxvpLA+whMhYcwOIDMmHGBKTlozLDi+vFWJG1FswVAaGkOpUjmHxD4GGwrTVQyqvmpah99BdCYNln10OpIowLCxU7+ttKVJW7DEm6LG0esVDhLkAQ16hyIBj1+U4sYO5FbgfmCU+ny2I+2y/AxxbA48FYu8D3CxPJMHRyxaHTOwsrLxWOfM+UAWkDPV9XZ5dBJK+wCEyR7Ax41a/GAGMjvUVhlPe1ZEPhxhUsUvOx2oWfQZBjME0EOrxa9fWLGbEffYzGBLu/iIgJ4H7re65zD4HAAM23o35VBhobMBLUMg5Sc7baRxsjdrbeCoTNgNPsiNYvwghwYLOyO10dUEMuK6cmESBwN0lDZElIDjo2L8Aqi/uhJBa0sPDsRbq+snL/8BgPULKNr90PjjrWbzBQPY2484kfYmtYm2s4DtoMz0E7ju+SbAwfeq8RcprMHah1Ym9nq656fc63RCtz/HdW3bSUV+jtOfw3+oxndSqNiL07UN6quyQ+CqTGAonkJ4mdzO4zPfxRAGGDeq8SMd7IRPK4NCO3KWsseZINfvGxSAPkXmWXEiz6DTiAcbGXxQjf8vhDV/ebplv8iI2qbV1t3rf9UzeGjZx+MkOYVArmbwwuwv8VY1fhFCjda/cW6BtbG/iUwi/3X7ldzXtzrMPWeKKtKKWz9sq6ZN5fGUiU6U47KXcCsDJ5DMGiq0K6Mb5EIM7LVrymLl/OdT8DkTi+fhVCqtEAfcJRmPE54ox88EUdPwziiwdHoANPwPp/xynUyurU7LNaGzq0efGzLVPsV8623TiaDkSmEN2+TCDvsbW5pmi7XNTVw34HLNcPCGwrTa8mfg9mmlbQ74kDqbfuLaZdTbcLScJ9RtuW7L5drhcHCtRMbAxMwV0zZRdDwSEoyJcmTo9bUP4ToJSv7eKrhuYJjrnYAxc7t74hvoh6qJomO0IBPlKIaKht8YBSeTB1shyVBn1xu9Hmu1JVijXoHQ1bhrwh8Foj5DxdKg7JITpWG7/crOG79PZUrUlgr91qZOWvm/wfQBYDgtmmatjY/Bhti2b+eLyeGrJbHCYn2YWmbwME6oOrozzg6cLdjiKuK5nUWz1vZITxpbHHFqsBS6CtqWiP/chzldJq4khhlSSzWVaNWnVaZrJVgX8S7D5hmkj1YxXiqkE/JUCAUR/0+3XjrjNPXlVSpXolaKwXm3I3ZOF1Xlz3pAXrqV5tNnA1hvbP0v7iAyXp3CsnZktGL/9Q7Zp02dilaAd2QYpzG2F9qUwNCtYVqT2trUeBUzl5IjnuI0j/xGNX5PnjoV3t9+wok1gKq1WrtCS1xBdY3dZ0TqzLqiU412QyGI+K1qvFNxxzBbOlRbiwe0VkF/b2uT6j9ZB8ehzFJq4IhTL9vZ1a/aB6gWeoTvd8cPvSPB8U5I5m12DvtkVdmlK7CFK05i4i0PCeFGMX5CQsnXDwFwkhWa9GmOATLZt7nFZvN3mV0sSllZBnFzDjRMhPeK8Q1Sb1aSHc+XGnVWTdyb73tMHXbV6NEumeKjMA+QNq0eMdAwEf5o8yuMqbqzBikznEUosGtPGXRTG2GCHYt+WRM3F6zddnfkF3rglS2p/yxjcPfAi51Nk3oL3hlGaxKZlOHxgnY0lZjED7k/jJKc/4CDSrb7zlJ/92Tmzjhqh12SFza1jG196Te0wCOR4QO0Vm1+BYOdcHfbpWU9++c2ocJmKGY2KQ1sJVWoWPlsryNlRT0gbxq7zSvhqVmgsKUJr5KbeS9sAMtkk06nDo+N2tLmjyrgzBvVwKadv8Gx0p1tFwqLHRtfYfsuc2gqJLVLppiCakRNSB0mVlIXVfiN1r0V2LvaJty1QsqrRuUubCqkMQQNXHpY014YMY8j2CKVmH9qsOsBI2x6q0er0GBz1JxNo+Ct8JSKU5Lk/JJ5HMEWBX6nwN51nLDprVZWocJug5dp51YylcewczWxoDT87uSqtzdWu02GcO2nQjFBqeWuKMwl0VPlykA85XELy9qZURqSpXI3wvNHo92SrCtqGLKOK6R9AWtssbwpjWwA56/J8yLcEsO3Tzkci91uTR+SjHqIcxwaCHza1Luu69oK69oc4Ao7rU2j4D1eLQN9YUhqSObkKrh/NNitMvp1b03DXYUm0Ge5oY22QCzKS2i0ZqEDqQBSAi6YL3jH4VirutquGfTJOGGV14N8bbSDvXegpufRABcnCUUxvRAsld7pUnb7IO52jywDA+OEVV45Yr8RGxQap4cB+N3dkzTd/LAhqVaZouz2F/E1Hk4nK6zyyiA7Ai8xsD0UBBpNv6n2OdKO516oRW88+4OV+7RrpvbVvLDKS/6ggJeif7E+mhxgA14L3Aao48EfTfRrtxlbdyj8MEgrpiNBtPZzj5W9mr7cWCNKPf3IuEuaQozoHSr/h3UNTbqq4COJGwnhu0FaMa0whX4cWDPb5bBF+51JKHxD4p3wQ4nb7Obqpe8/DfHrDpuXaVYvVqz54GlgAaQqKRwJF4BMqhBqLj60DKRQvrMEpSzLk7UJmITgvGbCu4/a/YhpCcJen1szbLQtDTWSH55aNXTLdGdT3861VEgB3eqE0hPqgzBb+mszNGEaUDtIyDCmpWiJywksoRRiHHQVOjPqssQrFKwoLU4SP2wow2+0Isx3TC0jQe30zB6sBCHaziaFQgFNOuX91tLdkaZsIuCkGjO+Wu4NPP6dq2Ukpg1hb+0Mi6YBqUA29G8ViYlcQfMwN0eg/ayPyKH0FJxLTP9Mx4Z3H8DxM9PBp6AZNKEN8sci4XkBUqwN0G96q4Mskg0SnG+Fa6asJ4IJJaqUpM5pQQQfvuBqzi1qSX4m4W4tCx6aEP6mMjPkryG16ZUKm6VzTZqKDSevz/lHCxRhNpDX0rug3Tqp7l0AsWY4XUNhg8zxHuQ9oZXOWsBfkqIqAMat/bUB+m054uBIwoQKi4TnD8j3/wWFFvBLwN1EYX8+YGNIutRIhTBa1veo+Miotir1DeW0jzY+o8GmXXLBPenoFHQujvKRpVZE2h2lXbB/DBTKji1hPOrql4+/ZVQ+FwpGbJc1pQ7eSfsu+tAigOYg6eeVRrjHq9fYPwYKZccUQ6fzvUYrzhNZ7aj3b0GF9l3wvFUA1ak8Br9hg3uchNXwI0SMWQOuB8qXDy8W+JWsJN9vDXmKENTvgganIQjq95ZbeItGKXopkpC6TCxAhqP+XnWT0AxuDrfC5Mw4rLDl5hpuxnyD5nfsmKyIBbLh3MobAlNh2Q64F0CL+4prGe/JZGIU7io0tGxiDpwDy6H5Gyv9TBd6IgWj5hakgB3MbKp/rbcDhw37zIyxPjArU/3dg7PScBs4zj6UDssOsvqd7bBulQZXCtagIyZdG2yQwdzIzW8/wOBf74AHfeE4hn8Y8Uyti/53kKLS9Q5Ys/PI9CCvWrQ8ITN3MxomvIRjy7+8Q1n+SZotR+lyO3/+KHnt2cwfJr1DdQe7+QiAlPXXJQCYErNuZcE6ZvsaWiaJ/FARIuU3v/kZpuWY+DZhGpfY7VlEhyl9rNWwwz7tQLNCKezb4vIX8T6NUguWngmGeAuE6qL/+DX/oTpGH07LMNg2k96hkSXQwV3nO1l1yHNX2GKEEhHugCOlZZNz3hzZiSx/+YAgLsfbzjet2DPmMzcMazA+4prkAvdCUX8SyrZMfVuWcqqscCe5AkrPxhO0Fza0TWVR/Ow9ybSCxZi7L9tUcqIrYj9kVjhgGb8h4AFClYN0D4nsPhVfIuoK6OThOcZ2nZgRCdoW7dYm3wv3tYSznRdl7XHLg3Q1GCY4Kxxbr0dAMQ3fBUOzT5smZf8d03StKcWU+ntqZISdhcw3H3CDsXKpUoz560g4YAnT10HIq0DlQyXDTfbltKqA+/RSNAhdjaIQSiNQtEsOD+oMshdwP/TLO5m3/UFoopdXOMzG6dkZCTZ1G+BDqUsvEhbrag97vc2XxSGzKcu6BvhZQNvNJ3Cf8uVzMQET3s0slfsav5Plv2PortbcCOa+c+FDgUVarIW8eAhX6tuq/9Epmo1EUuH8WST1oCUi9kOaEe8xWMWb3exf+gspdIfyyPQYcd/ZhLM9XO7fdqg3yZQODDAl3Feev/r5Qg2B7089VUD+aizvWX353s2L94wxE9UTypxUGQEuOUkDdiuI7SNQ5hvYCyqT4fVvDGsNLj3JaBLpJurJ6ivmYmyHMf8cklnldCg3cFo1bV1hSafW/YCs2FT1gaf7xiREvjuDpoX3fL54ruP1XbLP+Vx1Z5aTmfVbrJuACmb+BywCNdISldfy7obJF9AtOKVqscgcDZrlrKxCrQ+YaWVrGWhtRFuOO0EDlaF//DPoTUR0OM/s39gLzZ1ZzsYq7PoBpRScJsy4T2id+Df57p9kWTmku2Zbmy6l5kDULKe2CgMFuOhHdJ6gb9YUR9781d/zX3/AvecX6R9MjqFDB0tMhfuBmBoyiM9mdiHHB30zzaiO9HuS+XRw35VD+hn0ZubdHJezMOAW3zfZe+yq4FFbiMg3MNFB3Onnd8BVtVo2HnUNv8HS+YNNaNB9Z0xPY17TVzjClloGng66+uEfjnHkb573EocTHCvWcLaUnutru6jryiak2DhYLkQ0z7YXwND9yMTz0Av4itm7f3vl8fHm/TtsDYcnasEyieV/8LSVXbdivzMJq4EUJOpwyRgarQFIGRD7fuQq2gu8+8Mf3sHcRoTUoIouoiXCz3X6YBg7LOvVV4JJ4pFKLnoNLN2FDX35X7b+gJtrCTcY03yYG5zY5RQWoYXl0vlyZmLvlZ1a4X+BjvlRqRH7ufTJIFT87gXx4SdlV0w3Bo+gknP0xiazS2Gck+pwsechdQC1ajEo6Lf8WGBuJ+sM/R0X754IU3APhNqwuVNIDUIx8L0OfBJdiJH9DCXDFBOpfjie6SyfsDtrc+DuaHUVrIeF59LanyshN1IpffL68SN+w/7aJc9zKB1hYkDHcIpOUq54ZsYy5h9ba2UMSgE5SIL1iyLuLCOxKyNjjQ9PkvzlRcBC8V+OZ/NEta7DgEO4g441U3YaeTO3jfRqaFQSkEu6yxrLNE5SteDuV8Ojm6t4PpuOLy7enJ8Hr3Po+fn5m4vL8WQaRYvXpYFmOCLrkDJYkgodyzMup7wzMcLOaXLPInMnOyM3UcntQuXvgZKhSv/fTKIlW1ti1Ef+hMtJMwt/hOzUET90tgRsgqIbUtZvgXkOoMVrpBIOspSexktNbYm3XA8/XOQvtzIwzANNCsLzI03ZoRBT5pBpLc2M2VvnU+e48ATkgy/D3JZYz6O84q3FuzKmm1p2DsgTjEtvTbtBQYsZ8cYW7PB/HRQ9nc0XflDWlrj2zFCMTktKtZ151mH+pmLnwFyYapBDVp9bA3XSZzrxAFlKK2tL3HgWlL4OexnoLFhqER3Da7N+HLF60PZe4Frrw58JqZhS+eVmZW2JW88c5en472JZ5DWZowGZfsfAVF0DlfdTmxyn9kf6CRDR+IGpLTF6dw6sTkOciwDLrEsx3bMpcFQtVN5/skn69yS6N16VrYQspZW1JeasSc397+iIuNhl7zqiiyY4X+Ews3LIzdIOdNjPYCl/Z/MaSukEWzHdsT7SdCOCF20H7VagrdsEU1pToGQ3KKc9HLFtMV9ofWYWahWltB822GpuMffTHNfeGbAIUHA57s8VuER/Fh4KSFq7NMNVtK1AgJ15ltLcIhtIwX1COqEKnNzcTim2d/SzHGzyPYfdMQObISd3hNCzzA3PtGKHKCiMdf2ulCXvkyOVBEK/0lClEd2agZ+Cm3wvYXdcoRXq7WHHMvda7w/VBtmIi0lkAy02D3mZzDyl11Yfdo6D44vLHJrA7rhGG9PzkznjhH5S9eTiYgiwJTIaVy6GFptfkB8aT1/2hilRVCxfN3CpFMFqphdoFOLamp5knL+rF04WlV8pzXq8sE+Yk8hzaLmhf8IKg4mo6YQJbvOFDVRNLYdMcbl+1Lp+Jl0mAbYG5dEFctukjP9hsR3J9cy61uNZZZJP/irwz3baQNXUugwxB7cmqLhpesYFFQiwd0wPpmeCHNXa/4mc5NqFuW74pMtXphnMNbJ6RYpVU6sg+d4b/fvoilmBAJuhlCbdyCIItgKPqOpsIDjQZAdypXT5uX5ugX9pX+JdW2DR6zkiiZhm+t9C1aN/xiTAxotrzlXydMj93XBoBcnN8u2qhd+L54JNyH60u7bAyv5dhlg2N7r3UecyCbABlczYSp4MAzvvhjuMXvyVwzXySu2YxDj+mICzf2p9F+oTOLPeq95H2IVVdcCjvpd8Pzw8bshLpnJQMNOsa9R4nPhd6C6Bfu/mAJOs2wImumJghtdWmnBDVXVI8WYjhvFBAcANOeV+RHIlyi9Xd4j1eYC70EVvvzBwCGWpnxdU7bPV65cqcGVKSIdGfV8wPg8buNqrc/5HGlhEE/KhgfJpngcYKG9n+L///gatptZA6kxsjIlxECvCHE6AzVi9PIftgqmVKjHjAcBylz2CeKQvY+FGsBMFybOFq6ltIJk6K514Iko7NQvON2h7zhhFNjnqKyEnwSTPmHqod9I+9UPGO3QBzEB8ZF2awdXUVohssk5lmC21QqZZcF6jfZQxY/4tUV+5ZKq60p4EY+ZK3YPYL6DS1dzP5nnWavqN+IeIp/9y4Jn54Y6lVRnIhifk+xyshWjN+Fj1LlBfqAVruEuwx5Z1/Vi1HfOTbu9FH4i2eIl1PGANNV5NrYXUQqkUSsyJlJvuqFIdQusAVHLeiWWu1088ONotjq3WRVk3/jOcnnZdW1fbYuWEjmnP6imSYt9NvJpaBdmXR2nGrFNHCh/8FKAKlmOlvkeYulMr2QcYO6LR5jlECXLQQPx8B/CWZ/wBOeD1LTeQ1b9HjYowFjysuBHWt3rPSn3PMDe3wk13ptROzWwxFdd/DQK85LxFzHg5BFRHXlEfigf1O9ZYaSRmpijFt6UFyGNVD2gB8l3WDZd6FCwGGaBsOV0hIlW0PA0s8KPd2C1WGiEcMCL9t5J/3sBH5vymcZTf7oUndrhItdxhaueE4b3osfJ+Rqkmrpip7zHiZi2vNLgcDgwMlVUDPZZjLKui9V/M5X7gv2ix8n5WqSZWzLyjCLFe1/Geos1+Aq7zjsUq2swlR1OBuWwHhEWHtcOP8qxcqRBuLT1RAbahn4M90/KFAb4sVtNmK5hEiIs4G1Pp+9QIusQqVBNVCLdGeIE778d0nn+xzDPveCzsJpbTDUCXVnHlLaPNLM2ZTnOOk0xqduHWTMkkb12fwS2DUjX7nccq22zlXMwlo/YRjZ0kOoTUYJdqYsdeo1kGaE7nvS2zmLRTVqbqLNPQGO+lxgIJutzTnxATpZKRuSkPwFya4YzMRYCiLPGuwiS3ENXeFKJMB/os09AYu0zWRZvDgFptcuGYMB6lL6Ds3PlhKNHYOnVoV2ECXQa1tvcougG+lWsbXyEQy+wpX/SuK0qF1bKJNQ+YYIuiijCj6uL4VhWxRCuLM9hlUCsKkG061v+nIuzAbLugXKGllDsebUpN25SYHOx5IBRzEBZoIqMIngu1toX4Otn/VUzaQlF9ngFjJTVFEK+ccZSaToL80OfpWjLxZv5z1FnIZOflAKiq2OApIky4Hg0biagF7/ffgspj4E0xCWV7wEK9ZjwaLF8Aq1AiqmJIAGPvAgJHxyiUbzmrPeps0yL+L45AfhUl8Hj3SxnyQxFTJt8NAKxGiaiKawzHMDTaCrP4nAds5U6JGjyvU3Oe9MtlgKBEVgtebxzqgskpxixl5C3ffyaU3p3ZGKGQg3L2rz7fo5CU0ufpJGRM9Xj32J/lVcp5O2aqSh7/BfkukUqp297A131w9YDJWrSZOvn8HHPIbAjtAzDstfyJdszb22Ge4fCAPB7uJEPksqF0rs9qmX4kV6Dnqa50wiEssHK5usukq2oXPDIbhMV1yNWqKXMSbUuAl1zB/b/9E8YKU6ik+NztYK+PltVSxyNF3WX37cAgyzzgQWmaLpL9J0RK7xkrdOQSVD4Ue0W0LnIxmv9+c+BnnFYXDKPHi84xMa3lVlAHBrUrnJxkREVswMVhLWtDcTlWydcfKHiHssuJTDJtOJ4Tb4hnMCqY6XzeJymeTo5kHl6xrMiep6jzEcM+myAQVj+DtckkabqI7ZCFxSBb4Eb05NuNZJwJk01xn+e5O272HiH1sqoPPx2QKnzBa0Rd5aQqwsnZmEf9KCNMeZj81KLkTHQcY9Vs+GKNcOSoupxSTPPxdkWZpXnLrDnYM/83ZcHMpv+6mKbIKCQzraI2ZivTeR8KsVHIejW28v4TaeqAioq1jjHW8Ryay5fWpZPS3osxOinsCkERB9apeh4CQ7Mv7r9l1q7a5O7QZHxw1GxCXtborn59VC6nyyuSJBR4kKWK/JM7/Fy/F75PDjpDyzE7HKIggvYMfQHItpKAQUVUhO6bYpO9Pf9sjc7Yaj+MuTAR+WpTnnzNxpXxvgiMHP1mzZP+G3LzNDIy5yJIkBJoU3zyqWLtJSiOPm9s3kngZtAVRghmZoL/RGE8SW+m8MmitfZfRiltq02Rv5h7nnnnmrH/R+1wHHW5f9R79Bjntwq+U28/R77LEAsT/v+6KXbyIwl1YWLQI15/BVbrVJJA9XUoG9mwchGb8P/FBFWuLuW0FPhKtOVEEwE3N+npE8dKJAleAjWDYxKFBqwZ8f9AhZdCEfP+5Ehq0cZDNcdLdTEdcUJ95wZRqH3NChMBFjxwUQyPMmW0CDytMhPVxfSUEQZ0RRSFutfsWNDoSbxQYSKWWHrqX/FyBPPJCgmwTOWERhcqee8Ta56n6ggrheCFChN9EtIwNu6/mEF1MT1VJ+Aw9t9sMpwaVArNA+AUEoWYB5SM0fcyblGdn6fGyi2XmoIHl3E/JdKLJUlJATTpJRd9osbAzxBXnZ+nIHuo+pImoY7a/Myu1JoMhRnluCerC9L3FIfAa323OlwqJynH+mQX47AXfFSWAMEcly06IaeUC8i1HlzGS+VnM53Vq8X0DSzZ/+xjYSpFljAnE1SNlMUYfa2XqLopQG15bDMvNIkAo30zia1MqlPoBJKMUTVSkmkII+801kx15+cotFpwuYjGAm9DmyoDS8ufMXThmoxhW9fNxwDh1Sm1geRp1fk5GRsuuFzG00vpoOfjA/NiYusKNMmcRCHmETHMRwzTlE1ZnEJ05+d5aHsFaxnPJhcCuwZvxtNo8RzW7HQaQvMf55ewKS+JLgORqpmRPgQRI39+1k2oXFuQEf1nwuT8nEYWnF9cjqfRXG18YEmFI9OfTw9nRLAy/WIuKEmZXQS8dFxkfxKJLnSX0lHYK8zQZeJnlv3z/+Y3H4c0ocJC/qje4MorFjMWnkxwOZn3RVKJx3yyXfVH/V8Jk8x9OBvnl5NoAXtU55dAfJDF/KXeFnjRBm/Gk8gsbosk3cVB0yGriDJUuy6mi7P/kpjlIp5HeyZeJIiZIY73jmm+SEDz2uLluPaPLI6TXiqt6HMddT6eJQpolclFQKpi/Y+PiZ8Jr4vz4BBFdDmZaarkLObPjK83R45ahOo7Aw==";
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 <b>~${RECEIVED_DONATIONS}$</b> in donations with a total of <b>~${SPENT_HOURS} hours</b> 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 <b>${HOURLY_RATE_GOAL}$/hour</b>.`;
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 = '<path d="M7 14.6a12 12 0 0 1 2.8-.6 10 10 0 0 1 .5-8.8l.4-.7a32.9 32.9 0 0 0 .9-2.3v-1c-.1-.4-.3-.7-.7-1.1-.6-.2-1.1 0-1.6.3L4.2 5.1c-.3.2-.5.6-.6 1l-.4 3a14.6 14.6 0 0 1 3.7 5.5Zm-4-4.2-.1.3-2.8 6c-.2.7-.1 1.4.4 1.9L4.8 23a8.7 8.7 0 0 0 .8-8.7c-.7-1.8-1.9-3.2-2.6-4Z"/><path d="M5.8 23.5H6a23.8 23.8 0 0 1 7.4 1.4c1.2.4 2.3-.5 2.5-1.7a7 7 0 0 1 .8-2.7c-.8-2-1.6-3.2-2.6-4a5 5 0 0 0-2.9-1.3c-1.6-.2-3 .2-4 .5.6 2.3.4 5-1.4 7.8Z"/><path d="m17.4 19.3 2-3c0-.4 0-.7-.2-1a18 18 0 0 1-2-3.5c-.7-1.4-.7-3.5-.8-4.6 0-.4 0-.7-.3-1l-3.4-4.3v.6L12 4l-.5 1-.3.6A11 11 0 0 0 10 9.4c0 1.3 0 2.8.9 4.7h.4c1.1.2 2.3.6 3.5 1.6 1 .8 1.8 2 2.5 3.6ZM39.8 4.5c-6 0-10.3 3.7-10.3 8.9 0 5.1 4.3 8.9 10.3 8.9 5.9 0 10.2-3.8 10.2-9 0-5-4.3-8.8-10.2-8.8Zm0 3.5c3.5 0 6.1 2.1 6.1 5.4 0 3.2-2.6 5.4-6.1 5.4-3.6 0-6.2-2.2-6.2-5.4 0-3.3 2.6-5.4 6.2-5.4Zm15.7 12.6c.8.9 2.5 1.7 4.6 1.7 4.3 0 6.8-3 6.8-6.6C67 12 64.4 9 60.1 9c-2.1 0-3.8.8-4.6 1.7v-6h-3.9V22h3.9v-1.4Zm-.1-5c0-2 1.7-3.4 3.9-3.4 2 0 3.9 1.2 3.9 3.5 0 2.2-1.8 3.5-4 3.5-2.1 0-3.8-1.4-3.8-3.4v-.2ZM67.3 20a11 11 0 0 0 7.2 2.3c4 0 7-1.5 7-4.4 0-3-2.9-3.5-6.1-3.8-2.8-.4-3.6-.4-3.6-1.1 0-.7.9-1 2.5-1 2 0 3.7.5 4.8 1.6l2-2.3A9.7 9.7 0 0 0 74.5 9c-4 0-6.5 1.7-6.5 4.3 0 2.7 2.5 3.3 5.6 3.7 2.8.3 4 .3 4 1.2 0 .8-1 1.1-2.8 1.1-2.2 0-4.1-.7-5.7-2l-1.8 2.5ZM82.8 8h4V4.9h-4V8Zm3.9 1.4h-3.8V22h3.8V9.4Zm13.1 11.2V22h3.9V4.8h-3.9v6C99 9.8 97.4 9 95.2 9c-4.3 0-6.8 3-6.8 6.6 0 3.6 2.5 6.6 6.8 6.6 2.2 0 3.8-.8 4.6-1.7Zm.1-5v.2c0 2-1.7 3.4-3.9 3.4-2 0-3.9-1.3-3.9-3.5 0-2.3 1.8-3.5 4-3.5 2.1 0 3.8 1.4 3.8 3.4ZM106 8h4V4.9h-4V8Zm3.9 1.4H106V22h3.9V9.4Zm7 12.9a8 8 0 0 0 5.2-1.7c.6 1.2 2.2 2 5 1.4v-2.8c-1.4.3-1.7 0-1.7-.7v-4.6c0-3.2-2.3-4.8-6.4-4.8-3.5 0-6.2 1.5-7 3.8l3.4 1c.4-1 1.7-1.8 3.5-1.8 2 0 2.8.8 2.8 1.7v.1l-5 .5c-3 .3-5.2 1.5-5.2 4 0 2.4 2.2 3.9 5.4 3.9Zm4.8-5.1c0 1.4-2.2 2.3-4.1 2.3-1.5 0-2.4-.5-2.4-1.3s.7-1.1 2-1.3l4.5-.4v.7Zm6.7 4.8h3.8v-6c0-2.2 1.2-3.5 3.3-3.5 2 0 3 1.3 3 3.4V22h3.8v-7.2c0-3.5-2.2-5.7-5.5-5.7-2 0-3.6.8-4.6 1.8V9.4h-3.8V22Z"/><path fill-rule="evenodd" stroke="currentColor" stroke-width="0.5px" d="M191.822 20.035A3.288 3.288 0 0 0 191.812 19.951A2.225 2.225 0 0 0 191.728 19.825A3.914 3.914 0 0 0 191.649 19.779A2.868 2.868 0 0 0 191.535 19.755Q191.388 19.755 191.329 19.85A9.99 9.99 0 0 0 191.248 20.005A9.059 9.059 0 0 0 191.234 20.042A20.576 20.576 0 0 1 191.04 20.456A15.291 15.291 0 0 1 190.688 20.854A13.176 13.176 0 0 1 190.086 21.116A18.046 18.046 0 0 1 189.778 21.141A16.538 16.538 0 0 1 189.506 21.117A22.39 22.39 0 0 1 189.246 21.057A12.53 12.53 0 0 1 188.825 20.838A15.259 15.259 0 0 1 188.718 20.746Q188.476 20.518 188.315 20.126A19.046 19.046 0 0 1 188.212 19.778Q188.177 19.602 188.163 19.395A41.406 41.406 0 0 1 188.154 19.118A38.021 38.021 0 0 1 188.176 18.694Q188.2 18.485 188.249 18.307A18.247 18.247 0 0 1 188.319 18.1A22.415 22.415 0 0 1 188.472 17.79Q188.57 17.628 188.687 17.506A13.277 13.277 0 0 1 188.732 17.463A15.164 15.164 0 0 1 189.051 17.229A13.142 13.142 0 0 1 189.274 17.134A20.296 20.296 0 0 1 189.592 17.058A16.216 16.216 0 0 1 189.834 17.039Q190.032 17.039 190.179 17.076A8.428 8.428 0 0 1 190.265 17.102A20.826 20.826 0 0 1 190.385 17.15Q190.443 17.176 190.492 17.203A10.532 10.532 0 0 1 190.548 17.235A13.851 13.851 0 0 1 190.796 17.429A16.001 16.001 0 0 1 190.849 17.484Q190.989 17.634 191.087 17.816A28.524 28.524 0 0 0 191.143 17.923A32.076 32.076 0 0 0 191.164 17.96A8.099 8.099 0 0 0 191.246 18.077A7.413 7.413 0 0 0 191.259 18.093A5.796 5.796 0 0 0 191.329 18.16A4.911 4.911 0 0 0 191.371 18.191A2.41 2.41 0 0 0 191.488 18.228A2.956 2.956 0 0 0 191.507 18.229A3.152 3.152 0 0 0 191.589 18.219A2.121 2.121 0 0 0 191.714 18.131A4.225 4.225 0 0 0 191.758 18.048A3.083 3.083 0 0 0 191.78 17.935A2.636 2.636 0 0 0 191.777 17.896Q191.77 17.853 191.751 17.792A15.123 15.123 0 0 0 191.735 17.743A12.471 12.471 0 0 0 191.685 17.624Q191.648 17.544 191.595 17.456Q191.506 17.308 191.365 17.148A29.801 29.801 0 0 0 191.346 17.127A16.118 16.118 0 0 0 191.103 16.907A19.423 19.423 0 0 0 190.972 16.819A20.302 20.302 0 0 0 190.685 16.673A25.928 25.928 0 0 0 190.461 16.591A19.442 19.442 0 0 0 190.11 16.518A25.565 25.565 0 0 0 189.806 16.5A24.519 24.519 0 0 0 189.175 16.579A21.58 21.58 0 0 0 188.868 16.686Q188.441 16.871 188.13 17.207A22.873 22.873 0 0 0 187.739 17.792A27.604 27.604 0 0 0 187.643 18.023A28.76 28.76 0 0 0 187.489 18.699A36.041 36.041 0 0 0 187.468 19.09Q187.468 19.657 187.65 20.189A25.617 25.617 0 0 0 187.925 20.762A21.934 21.934 0 0 0 188.182 21.085Q188.35 21.26 188.553 21.376Q188.756 21.491 188.973 21.558Q189.19 21.624 189.411 21.652Q189.631 21.68 189.841 21.68Q190.33 21.68 190.687 21.519A14.886 14.886 0 0 0 190.758 21.484A23.571 23.571 0 0 0 191.1 21.27A18.016 18.016 0 0 0 191.371 21.019A21.893 21.893 0 0 0 191.572 20.749A16.519 16.519 0 0 0 191.714 20.473A24.164 24.164 0 0 0 191.766 20.326Q191.812 20.183 191.82 20.08A5.511 5.511 0 0 0 191.822 20.035ZM210.729 20.539A10.256 10.256 0 0 0 210.709 20.331Q210.681 20.195 210.613 20.089A6.408 6.408 0 0 0 210.603 20.074Q210.477 19.888 210.285 19.769Q210.092 19.65 209.865 19.58Q209.637 19.51 209.427 19.468Q209.112 19.398 208.909 19.332Q208.769 19.286 208.67 19.234A8.38 8.38 0 0 1 208.591 19.188Q208.506 19.132 208.459 19.069A3.226 3.226 0 0 1 208.43 19.024A4.079 4.079 0 0 1 208.384 18.844A4.773 4.773 0 0 1 208.384 18.831Q208.384 18.614 208.563 18.485A6.016 6.016 0 0 1 208.611 18.453A9.288 9.288 0 0 1 208.884 18.349Q209.018 18.32 209.175 18.32A15.627 15.627 0 0 1 209.378 18.332Q209.479 18.346 209.562 18.373A6.348 6.348 0 0 1 209.714 18.446A8.886 8.886 0 0 1 209.849 18.555Q209.934 18.64 209.98 18.739A5.694 5.694 0 0 1 209.98 18.74A21.387 21.387 0 0 0 210.014 18.808Q210.051 18.879 210.082 18.923A4.301 4.301 0 0 0 210.103 18.95A1.554 1.554 0 0 0 210.167 18.995Q210.193 19.005 210.226 19.01A4.094 4.094 0 0 0 210.281 19.013Q210.34 19.013 210.381 19A1.678 1.678 0 0 0 210.421 18.982A2.886 2.886 0 0 0 210.467 18.945A2.322 2.322 0 0 0 210.498 18.908A2.481 2.481 0 0 0 210.521 18.867A1.908 1.908 0 0 0 210.533 18.824Q210.539 18.79 210.54 18.77A1.657 1.657 0 0 0 210.54 18.761Q210.54 18.719 210.503 18.605A25.229 25.229 0 0 0 210.491 18.569Q210.451 18.451 210.345 18.329A12.347 12.347 0 0 0 210.295 18.275A9.871 9.871 0 0 0 210.149 18.153Q210.034 18.074 209.879 18.005A12.077 12.077 0 0 0 209.651 17.933Q209.534 17.907 209.395 17.895A28.523 28.523 0 0 0 209.161 17.886Q208.923 17.886 208.736 17.922A15.474 15.474 0 0 0 208.692 17.932A15.47 15.47 0 0 0 208.491 17.991A11.956 11.956 0 0 0 208.335 18.061Q208.083 18.201 207.943 18.439A10.425 10.425 0 0 0 207.835 18.69A8.678 8.678 0 0 0 207.803 18.922A8.458 8.458 0 0 0 207.827 19.126A6.855 6.855 0 0 0 207.898 19.304A10.914 10.914 0 0 0 208.01 19.466A8.765 8.765 0 0 0 208.118 19.573A13.929 13.929 0 0 0 208.273 19.684A12.994 12.994 0 0 0 208.276 19.685A9.406 9.406 0 0 0 208.342 19.722Q208.379 19.741 208.423 19.759A19.716 19.716 0 0 0 208.482 19.783Q208.569 19.817 208.683 19.854A61.793 61.793 0 0 0 208.794 19.888Q208.975 19.943 209.246 20.011A175.761 175.761 0 0 0 209.259 20.014Q209.392 20.049 209.543 20.091A11.079 11.079 0 0 1 209.724 20.159A9.425 9.425 0 0 1 209.812 20.207Q209.931 20.28 210.011 20.389A3.951 3.951 0 0 1 210.079 20.538Q210.092 20.597 210.092 20.665A4.625 4.625 0 0 1 209.993 20.949A7.213 7.213 0 0 1 209.879 21.068A6.795 6.795 0 0 1 209.657 21.188Q209.485 21.246 209.245 21.246Q208.982 21.246 208.8 21.18A6.716 6.716 0 0 1 208.611 21.078Q208.398 20.91 208.293 20.665A7.271 7.271 0 0 0 208.241 20.564A5.814 5.814 0 0 0 208.192 20.497A1.892 1.892 0 0 0 208.095 20.437Q208.064 20.429 208.027 20.427A3.869 3.869 0 0 0 208.013 20.427A2.684 2.684 0 0 0 207.902 20.45A2.607 2.607 0 0 0 207.824 20.504A2.794 2.794 0 0 0 207.773 20.573A2.276 2.276 0 0 0 207.747 20.679Q207.747 20.868 207.849 21.029A18.825 18.825 0 0 0 207.938 21.159Q207.996 21.236 208.055 21.295A13.024 13.024 0 0 0 208.518 21.581A14.764 14.764 0 0 0 208.521 21.582A14.51 14.51 0 0 0 208.761 21.645Q208.883 21.667 209.025 21.675A30.93 30.93 0 0 0 209.203 21.68Q209.548 21.68 209.798 21.62A13.282 13.282 0 0 0 210.019 21.547A17.031 17.031 0 0 0 210.226 21.44Q210.382 21.345 210.481 21.229A11.064 11.064 0 0 0 210.597 21.065A7.971 7.971 0 0 0 210.684 20.851A23.38 23.38 0 0 0 210.707 20.737Q210.728 20.629 210.729 20.55A6.492 6.492 0 0 0 210.729 20.539ZM149.486 20.469A20.565 20.565 0 0 0 149.509 20.43Q149.535 20.385 149.569 20.321A90.19 90.19 0 0 0 149.602 20.259Q149.675 20.119 149.749 19.962A37.1 37.1 0 0 0 149.84 19.75A31.562 31.562 0 0 0 149.874 19.657A12.867 12.867 0 0 0 149.902 19.573Q149.927 19.482 149.927 19.419Q149.927 19.3 149.843 19.22Q149.759 19.139 149.64 19.139A2.273 2.273 0 0 0 149.482 19.204Q149.434 19.248 149.395 19.321A14.995 14.995 0 0 0 149.383 19.346Q149.363 19.388 149.329 19.465Q149.283 19.566 149.231 19.682Q149.178 19.797 149.133 19.899A99.51 99.51 0 0 1 149.111 19.946Q149.082 20.011 149.066 20.042Q148.968 19.938 148.891 19.851A68.292 68.292 0 0 1 148.881 19.839A1775.331 1775.331 0 0 1 148.805 19.754Q148.754 19.696 148.695 19.629A79.458 79.458 0 0 1 148.64 19.566Q148.552 19.465 148.44 19.328A466.983 466.983 0 0 1 148.358 19.23Q148.246 19.093 148.095 18.907A1543.854 1543.854 0 0 1 148.044 18.845Q148.506 18.6 148.8 18.303A10.277 10.277 0 0 0 149.021 17.98A9.508 9.508 0 0 0 149.094 17.606Q149.094 17.473 149.047 17.311A16.194 16.194 0 0 0 149.031 17.26A10.364 10.364 0 0 0 148.872 16.958A12.188 12.188 0 0 0 148.825 16.899A10.761 10.761 0 0 0 148.611 16.71A13.818 13.818 0 0 0 148.45 16.616Q148.241 16.511 147.945 16.501A18.707 18.707 0 0 0 147.883 16.5A15.973 15.973 0 0 0 147.614 16.522A11.629 11.629 0 0 0 147.334 16.605A13.053 13.053 0 0 0 147.095 16.742A10.73 10.73 0 0 0 146.945 16.875A10.831 10.831 0 0 0 146.739 17.186A10.281 10.281 0 0 0 146.718 17.239A11.786 11.786 0 0 0 146.65 17.524A10.583 10.583 0 0 0 146.644 17.634A10.236 10.236 0 0 0 146.703 17.97A13.462 13.462 0 0 0 146.788 18.163A32.918 32.918 0 0 0 146.933 18.407Q147.038 18.57 147.176 18.747Q146.98 18.852 146.773 18.985Q146.567 19.118 146.396 19.29Q146.224 19.461 146.112 19.689A10.729 10.729 0 0 0 146.016 20.001A14.179 14.179 0 0 0 146 20.217A12.88 12.88 0 0 0 146.038 20.523A16.369 16.369 0 0 0 146.098 20.714A13.928 13.928 0 0 0 146.374 21.16A15.957 15.957 0 0 0 146.399 21.187A14.894 14.894 0 0 0 146.71 21.434A18.905 18.905 0 0 0 146.914 21.54A15.13 15.13 0 0 0 147.256 21.645Q147.417 21.675 147.602 21.679A26.164 26.164 0 0 0 147.659 21.68Q147.953 21.68 148.181 21.614A20.209 20.209 0 0 0 148.417 21.529A15.925 15.925 0 0 0 148.583 21.446A16.498 16.498 0 0 0 148.784 21.309A13.958 13.958 0 0 0 148.888 21.218A33.819 33.819 0 0 0 149.023 21.079A26.636 26.636 0 0 0 149.115 20.973L149.266 21.124Q149.338 21.196 149.462 21.307A122.767 122.767 0 0 0 149.542 21.379Q149.655 21.479 149.734 21.54A17.292 17.292 0 0 0 149.752 21.554Q149.821 21.606 149.869 21.634A5.331 5.331 0 0 0 149.889 21.645A4.838 4.838 0 0 0 149.916 21.659Q149.95 21.674 149.973 21.677A5.79 5.79 0 0 0 150.011 21.68A4.806 4.806 0 0 0 150.032 21.68A2.48 2.48 0 0 0 150.12 21.663Q150.153 21.651 150.188 21.629A5.246 5.246 0 0 0 150.225 21.603Q150.326 21.526 150.326 21.372A2.778 2.778 0 0 0 150.319 21.308A2.031 2.031 0 0 0 150.284 21.232A5.843 5.843 0 0 0 150.256 21.198Q150.214 21.15 150.144 21.085A119.856 119.856 0 0 1 150.081 21.031Q150.004 20.966 149.948 20.916A37.409 37.409 0 0 1 149.931 20.9Q149.85 20.826 149.784 20.767Q149.717 20.707 149.654 20.641A52.27 52.27 0 0 0 149.62 20.605Q149.565 20.548 149.486 20.469ZM172.432 21.183L172.432 19.279A51.556 51.556 0 0 0 172.432 19.211Q172.431 19.149 172.429 19.073A18.916 18.916 0 0 0 172.409 18.853A21.017 21.017 0 0 0 172.404 18.821Q172.383 18.691 172.334 18.565Q172.285 18.439 172.194 18.334Q172.005 18.117 171.757 18.002A12.033 12.033 0 0 0 171.449 17.908A16.569 16.569 0 0 0 171.172 17.886A16.106 16.106 0 0 0 170.97 17.898Q170.864 17.912 170.773 17.94A9.472 9.472 0 0 0 170.745 17.949Q170.563 18.012 170.427 18.107A14.499 14.499 0 0 0 170.272 18.229A12 12 0 0 0 170.192 18.31Q170.094 18.418 170.024 18.509A59.749 59.749 0 0 0 170.024 18.43Q170.023 18.399 170.022 18.372A28.64 28.64 0 0 0 170.021 18.32Q170.018 18.267 170.016 18.224A56.933 56.933 0 0 0 170.014 18.187Q170.01 18.131 169.996 18.093Q169.982 18.054 169.961 18.019A1.527 1.527 0 0 0 169.935 17.979Q169.912 17.952 169.874 17.928A2.736 2.736 0 0 0 169.733 17.886A3.297 3.297 0 0 0 169.723 17.886A3.514 3.514 0 0 0 169.666 17.891Q169.625 17.897 169.594 17.914A7.268 7.268 0 0 0 169.552 17.938Q169.533 17.95 169.517 17.962A3.925 3.925 0 0 0 169.506 17.97A2.17 2.17 0 0 0 169.455 18.054Q169.444 18.085 169.44 18.122A3.872 3.872 0 0 0 169.44 18.124A16 16 0 0 0 169.433 18.203Q169.431 18.239 169.43 18.281A34.968 34.968 0 0 0 169.429 18.369L169.429 21.183Q169.429 21.294 169.434 21.378A16.104 16.104 0 0 0 169.44 21.439A2.976 2.976 0 0 0 169.455 21.508A2.094 2.094 0 0 0 169.513 21.596A3.572 3.572 0 0 0 169.615 21.658A3.123 3.123 0 0 0 169.73 21.68Q169.849 21.68 169.947 21.596A2.227 2.227 0 0 0 170.009 21.503A3.192 3.192 0 0 0 170.024 21.439Q170.034 21.366 170.037 21.265A29.244 29.244 0 0 0 170.038 21.183L170.038 20.028A136.267 136.267 0 0 1 170.039 19.891Q170.041 19.696 170.049 19.559Q170.059 19.377 170.08 19.258A13.249 13.249 0 0 1 170.096 19.182Q170.112 19.114 170.133 19.066Q170.164 18.992 170.206 18.922Q170.332 18.691 170.57 18.555Q170.808 18.418 171.074 18.418Q171.263 18.418 171.438 18.506Q171.613 18.593 171.711 18.768A5.723 5.723 0 0 1 171.751 18.856Q171.768 18.902 171.781 18.956A12.31 12.31 0 0 1 171.795 19.027Q171.823 19.188 171.823 19.454L171.823 21.183Q171.823 21.294 171.828 21.378A16.104 16.104 0 0 0 171.834 21.439A2.976 2.976 0 0 0 171.849 21.508A2.094 2.094 0 0 0 171.907 21.596A3.143 3.143 0 0 0 172.114 21.68A4.083 4.083 0 0 0 172.131 21.68Q172.25 21.68 172.348 21.596A2.116 2.116 0 0 0 172.409 21.5A3.049 3.049 0 0 0 172.422 21.439A17.011 17.011 0 0 0 172.428 21.359Q172.432 21.282 172.432 21.183ZM199.648 21.183L199.648 19.279A51.556 51.556 0 0 0 199.648 19.211Q199.647 19.149 199.645 19.073A18.916 18.916 0 0 0 199.625 18.853A21.017 21.017 0 0 0 199.62 18.821Q199.599 18.691 199.55 18.565Q199.501 18.439 199.41 18.334Q199.221 18.117 198.973 18.002A12.033 12.033 0 0 0 198.665 17.908A16.569 16.569 0 0 0 198.388 17.886A16.106 16.106 0 0 0 198.186 17.898Q198.08 17.912 197.989 17.94A9.472 9.472 0 0 0 197.961 17.949Q197.779 18.012 197.643 18.107A14.499 14.499 0 0 0 197.488 18.229A12 12 0 0 0 197.408 18.31Q197.31 18.418 197.24 18.509A59.749 59.749 0 0 0 197.24 18.43Q197.239 18.399 197.238 18.372A28.64 28.64 0 0 0 197.237 18.32Q197.234 18.267 197.232 18.224A56.933 56.933 0 0 0 197.23 18.187Q197.226 18.131 197.212 18.093Q197.198 18.054 197.177 18.019A1.527 1.527 0 0 0 197.151 17.979Q197.128 17.952 197.09 17.928A2.736 2.736 0 0 0 196.949 17.886A3.297 3.297 0 0 0 196.939 17.886A3.514 3.514 0 0 0 196.882 17.891Q196.841 17.897 196.81 17.914A7.268 7.268 0 0 0 196.768 17.938Q196.749 17.95 196.733 17.962A3.925 3.925 0 0 0 196.722 17.97A2.17 2.17 0 0 0 196.671 18.054Q196.66 18.085 196.656 18.122A3.872 3.872 0 0 0 196.656 18.124A16 16 0 0 0 196.649 18.203Q196.647 18.239 196.646 18.281A34.968 34.968 0 0 0 196.645 18.369L196.645 21.183Q196.645 21.294 196.65 21.378A16.104 16.104 0 0 0 196.656 21.439A2.976 2.976 0 0 0 196.671 21.508A2.094 2.094 0 0 0 196.729 21.596A3.572 3.572 0 0 0 196.831 21.658A3.123 3.123 0 0 0 196.946 21.68Q197.065 21.68 197.163 21.596A2.227 2.227 0 0 0 197.225 21.503A3.192 3.192 0 0 0 197.24 21.439Q197.25 21.366 197.253 21.265A29.244 29.244 0 0 0 197.254 21.183L197.254 20.028A136.267 136.267 0 0 1 197.255 19.891Q197.257 19.696 197.265 19.559Q197.275 19.377 197.296 19.258A13.249 13.249 0 0 1 197.312 19.182Q197.328 19.114 197.349 19.066Q197.38 18.992 197.422 18.922Q197.548 18.691 197.786 18.555Q198.024 18.418 198.29 18.418Q198.479 18.418 198.654 18.506Q198.829 18.593 198.927 18.768A5.723 5.723 0 0 1 198.967 18.856Q198.984 18.902 198.997 18.956A12.31 12.31 0 0 1 199.011 19.027Q199.039 19.188 199.039 19.454L199.039 21.183Q199.039 21.294 199.044 21.378A16.104 16.104 0 0 0 199.05 21.439A2.976 2.976 0 0 0 199.065 21.508A2.094 2.094 0 0 0 199.123 21.596A3.143 3.143 0 0 0 199.33 21.68A4.083 4.083 0 0 0 199.347 21.68Q199.466 21.68 199.564 21.596A2.116 2.116 0 0 0 199.625 21.5A3.049 3.049 0 0 0 199.638 21.439A17.011 17.011 0 0 0 199.644 21.359Q199.648 21.282 199.648 21.183ZM176.534 20.532A3.117 3.117 0 0 0 176.522 20.444A2.336 2.336 0 0 0 176.443 20.326A3.647 3.647 0 0 0 176.368 20.278A2.675 2.675 0 0 0 176.254 20.252Q176.195 20.252 176.154 20.273A1.457 1.457 0 0 0 176.132 20.287Q176.086 20.322 176.051 20.364A0.884 0.884 0 0 0 176.043 20.373Q176.031 20.389 176.013 20.424Q175.988 20.469 175.96 20.522A19.281 19.281 0 0 1 175.922 20.59A16.39 16.39 0 0 1 175.904 20.62Q175.877 20.664 175.869 20.685A0.832 0.832 0 0 0 175.869 20.686Q175.729 20.938 175.481 21.071Q175.232 21.204 174.938 21.204A11.312 11.312 0 0 1 174.567 21.146A9.482 9.482 0 0 1 174.123 20.823A12.884 12.884 0 0 1 173.909 20.4Q173.825 20.123 173.825 19.762Q173.825 19.265 174.005 18.929A11.724 11.724 0 0 1 174.133 18.737A9.92 9.92 0 0 1 174.858 18.365A13.208 13.208 0 0 1 174.952 18.362Q175.149 18.362 175.297 18.41A7.63 7.63 0 0 1 175.348 18.429A11.407 11.407 0 0 1 175.489 18.497A8.28 8.28 0 0 1 175.621 18.59Q175.729 18.684 175.796 18.782A95.188 95.188 0 0 1 175.827 18.828Q175.857 18.874 175.879 18.908A25.527 25.527 0 0 1 175.897 18.936Q175.946 19.027 175.988 19.076Q176.018 19.111 176.044 19.133A2.786 2.786 0 0 0 176.065 19.15Q176.093 19.169 176.119 19.175A1.041 1.041 0 0 0 176.132 19.178A5.79 5.79 0 0 0 176.17 19.181A4.806 4.806 0 0 0 176.191 19.181A2.779 2.779 0 0 0 176.373 19.113A3.543 3.543 0 0 0 176.38 19.107A2.405 2.405 0 0 0 176.464 18.932A3.241 3.241 0 0 0 176.464 18.915Q176.464 18.824 176.426 18.737A9.75 9.75 0 0 0 176.371 18.629A8.253 8.253 0 0 0 176.338 18.579A16.685 16.685 0 0 0 176.24 18.444A21.161 21.161 0 0 0 176.149 18.338A11.789 11.789 0 0 0 175.991 18.194A14.908 14.908 0 0 0 175.873 18.114A13.143 13.143 0 0 0 175.68 18.017A17.807 17.807 0 0 0 175.481 17.949A16.11 16.11 0 0 0 175.266 17.906Q175.155 17.891 175.03 17.887A28.494 28.494 0 0 0 174.945 17.886Q174.427 17.886 174.095 18.065A15.968 15.968 0 0 0 173.748 18.312A13.867 13.867 0 0 0 173.566 18.523Q173.37 18.803 173.293 19.139Q173.216 19.475 173.216 19.79A33.884 33.884 0 0 0 173.227 20.07Q173.238 20.204 173.26 20.318A15.789 15.789 0 0 0 173.297 20.466Q173.357 20.666 173.426 20.811A13.31 13.31 0 0 0 173.475 20.903A12.835 12.835 0 0 0 173.544 21.018Q173.583 21.076 173.631 21.136A21.776 21.776 0 0 0 173.647 21.155A11.374 11.374 0 0 0 173.779 21.291A15.635 15.635 0 0 0 173.93 21.407Q174.105 21.526 174.361 21.603A16.697 16.697 0 0 0 174.604 21.656Q174.772 21.68 174.973 21.68Q175.414 21.68 175.712 21.53A20.695 20.695 0 0 0 175.965 21.379A14.971 14.971 0 0 0 176.195 21.183A16.44 16.44 0 0 0 176.327 21.025Q176.39 20.939 176.432 20.854A8.98 8.98 0 0 0 176.457 20.798Q176.53 20.62 176.534 20.541A1.736 1.736 0 0 0 176.534 20.532ZM153.742 20.147L155.975 20.147L156.423 21.253Q156.492 21.426 156.55 21.53A10.295 10.295 0 0 0 156.574 21.572A2.117 2.117 0 0 0 156.693 21.663Q156.745 21.68 156.815 21.68A3.648 3.648 0 0 0 156.926 21.664A2.913 2.913 0 0 0 157.06 21.575Q157.151 21.47 157.151 21.372Q157.151 21.295 157.127 21.218Q157.108 21.159 157.071 21.067A48.599 48.599 0 0 0 157.046 21.008L155.401 17.088Q155.352 16.969 155.293 16.833A12.279 12.279 0 0 0 155.259 16.762Q155.217 16.68 155.177 16.64A3.694 3.694 0 0 0 155.091 16.569A4.791 4.791 0 0 0 155.03 16.539Q154.939 16.5 154.841 16.5A6.137 6.137 0 0 0 154.757 16.506Q154.692 16.515 154.642 16.539A4.007 4.007 0 0 0 154.506 16.645A4.629 4.629 0 0 0 154.502 16.651Q154.448 16.717 154.403 16.814A11.485 11.485 0 0 0 154.393 16.836Q154.344 16.948 154.288 17.095L152.699 21.036A43.035 43.035 0 0 0 152.676 21.093Q152.648 21.163 152.631 21.215A13.482 13.482 0 0 0 152.626 21.232Q152.601 21.309 152.601 21.386Q152.601 21.49 152.69 21.583A4.693 4.693 0 0 0 152.692 21.586A3.044 3.044 0 0 0 152.91 21.68A4.049 4.049 0 0 0 152.923 21.68A4.561 4.561 0 0 0 153.008 21.673Q153.057 21.663 153.093 21.643A1.998 1.998 0 0 0 153.165 21.575A9.744 9.744 0 0 0 153.207 21.5Q153.248 21.42 153.293 21.305A35.447 35.447 0 0 0 153.308 21.267L153.742 20.147ZM167.875 21.085A156.604 156.604 0 0 0 167.919 21.236A174.514 174.514 0 0 0 167.935 21.288A9.866 9.866 0 0 0 167.991 21.434A8.679 8.679 0 0 0 168.015 21.481Q168.064 21.568 168.127 21.624Q168.19 21.68 168.281 21.68Q168.4 21.68 168.488 21.607A2.978 2.978 0 0 0 168.535 21.557Q168.567 21.514 168.573 21.467A1.833 1.833 0 0 0 168.575 21.442A5.283 5.283 0 0 0 168.567 21.354Q168.559 21.307 168.544 21.257A113.074 113.074 0 0 1 168.533 21.221Q168.511 21.15 168.505 21.127A9.687 9.687 0 0 1 168.48 21.059Q168.468 21.022 168.456 20.98A21.964 21.964 0 0 1 168.439 20.91Q168.412 20.799 168.408 20.605A35.786 35.786 0 0 1 168.407 20.525Q168.407 20.467 168.41 20.329A329.739 329.739 0 0 1 168.411 20.305Q168.414 20.147 168.418 19.965Q168.421 19.783 168.425 19.619A290.299 290.299 0 0 0 168.426 19.542Q168.428 19.437 168.428 19.384A50.037 50.037 0 0 0 168.415 19.009A40.849 40.849 0 0 0 168.393 18.796A10.854 10.854 0 0 0 168.312 18.497A9.517 9.517 0 0 0 168.211 18.32Q168.064 18.117 167.767 18.002Q167.472 17.887 166.962 17.886A46.251 46.251 0 0 0 166.951 17.886Q166.608 17.886 166.356 17.946A13.799 13.799 0 0 0 166.15 18.012Q165.917 18.108 165.764 18.227A10.032 10.032 0 0 0 165.677 18.303Q165.509 18.467 165.453 18.632A19.398 19.398 0 0 0 165.429 18.708Q165.407 18.782 165.4 18.833A3.082 3.082 0 0 0 165.397 18.873A2.545 2.545 0 0 0 165.417 18.975A2.432 2.432 0 0 0 165.478 19.059Q165.558 19.132 165.67 19.132Q165.76 19.132 165.815 19.096A1.703 1.703 0 0 0 165.866 19.045Q165.922 18.957 165.971 18.838Q166.027 18.698 166.136 18.6Q166.244 18.502 166.381 18.443A11.745 11.745 0 0 1 166.636 18.365A13.202 13.202 0 0 1 166.675 18.359Q166.832 18.334 166.993 18.334Q167.28 18.334 167.443 18.404A5.36 5.36 0 0 1 167.459 18.411A6.24 6.24 0 0 1 167.586 18.489A4.723 4.723 0 0 1 167.7 18.621A7.268 7.268 0 0 1 167.786 18.86A8.677 8.677 0 0 1 167.795 18.922A52.243 52.243 0 0 1 167.815 19.182A58.488 58.488 0 0 1 167.819 19.272A58.673 58.673 0 0 1 167.762 19.292Q167.682 19.319 167.627 19.335Q167.553 19.356 167.476 19.377Q167.425 19.39 167.299 19.415A131.725 131.725 0 0 1 167.277 19.419Q167.133 19.447 166.972 19.475A202.132 202.132 0 0 0 166.738 19.517A176.919 176.919 0 0 0 166.664 19.531A182.46 182.46 0 0 0 166.596 19.544Q166.511 19.561 166.465 19.571A21.283 21.283 0 0 0 166.454 19.573A87.884 87.884 0 0 0 166.304 19.607Q166.228 19.625 166.144 19.646A150.463 150.463 0 0 0 166.087 19.661Q165.88 19.713 165.698 19.829A9.901 9.901 0 0 0 165.422 20.092A11.635 11.635 0 0 0 165.39 20.14Q165.28 20.312 165.266 20.569A14.069 14.069 0 0 0 165.264 20.644Q165.264 20.833 165.334 21.019Q165.404 21.204 165.551 21.351A10.381 10.381 0 0 0 165.782 21.523A13.004 13.004 0 0 0 165.919 21.589A11.509 11.509 0 0 0 166.167 21.659Q166.282 21.678 166.413 21.68A19.554 19.554 0 0 0 166.44 21.68A22.373 22.373 0 0 0 166.719 21.663A16.841 16.841 0 0 0 166.969 21.614Q167.203 21.547 167.382 21.453A21.631 21.631 0 0 0 167.527 21.369Q167.6 21.322 167.661 21.274A12.71 12.71 0 0 0 167.683 21.257A45.541 45.541 0 0 0 167.754 21.196Q167.825 21.135 167.872 21.088A13.449 13.449 0 0 0 167.875 21.085ZM195.091 21.085A156.604 156.604 0 0 0 195.135 21.236A174.514 174.514 0 0 0 195.151 21.288A9.866 9.866 0 0 0 195.207 21.434A8.679 8.679 0 0 0 195.231 21.481Q195.28 21.568 195.343 21.624Q195.406 21.68 195.497 21.68Q195.616 21.68 195.704 21.607A2.978 2.978 0 0 0 195.751 21.557Q195.783 21.514 195.789 21.467A1.833 1.833 0 0 0 195.791 21.442A5.283 5.283 0 0 0 195.783 21.354Q195.775 21.307 195.76 21.257A113.074 113.074 0 0 1 195.749 21.221Q195.727 21.15 195.721 21.127A9.687 9.687 0 0 1 195.696 21.059Q195.684 21.022 195.672 20.98A21.964 21.964 0 0 1 195.655 20.91Q195.628 20.799 195.624 20.605A35.786 35.786 0 0 1 195.623 20.525Q195.623 20.467 195.626 20.329A329.739 329.739 0 0 1 195.627 20.305Q195.63 20.147 195.634 19.965Q195.637 19.783 195.641 19.619A290.299 290.299 0 0 0 195.642 19.542Q195.644 19.437 195.644 19.384A50.037 50.037 0 0 0 195.631 19.009A40.849 40.849 0 0 0 195.609 18.796A10.854 10.854 0 0 0 195.528 18.497A9.517 9.517 0 0 0 195.427 18.32Q195.28 18.117 194.983 18.002Q194.688 17.887 194.178 17.886A46.251 46.251 0 0 0 194.167 17.886Q193.824 17.886 193.572 17.946A13.799 13.799 0 0 0 193.366 18.012Q193.133 18.108 192.98 18.227A10.032 10.032 0 0 0 192.893 18.303Q192.725 18.467 192.669 18.632A19.398 19.398 0 0 0 192.645 18.708Q192.623 18.782 192.616 18.833A3.082 3.082 0 0 0 192.613 18.873A2.545 2.545 0 0 0 192.633 18.975A2.432 2.432 0 0 0 192.694 19.059Q192.774 19.132 192.886 19.132Q192.976 19.132 193.031 19.096A1.703 1.703 0 0 0 193.082 19.045Q193.138 18.957 193.187 18.838Q193.243 18.698 193.352 18.6Q193.46 18.502 193.597 18.443A11.745 11.745 0 0 1 193.852 18.365A13.202 13.202 0 0 1 193.891 18.359Q194.048 18.334 194.209 18.334Q194.496 18.334 194.659 18.404A5.36 5.36 0 0 1 194.675 18.411A6.24 6.24 0 0 1 194.802 18.489A4.723 4.723 0 0 1 194.916 18.621A7.268 7.268 0 0 1 195.002 18.86A8.677 8.677 0 0 1 195.011 18.922A52.243 52.243 0 0 1 195.031 19.182A58.488 58.488 0 0 1 195.035 19.272A58.673 58.673 0 0 1 194.978 19.292Q194.898 19.319 194.843 19.335Q194.769 19.356 194.692 19.377Q194.641 19.39 194.515 19.415A131.725 131.725 0 0 1 194.493 19.419Q194.349 19.447 194.188 19.475A202.132 202.132 0 0 0 193.954 19.517A176.919 176.919 0 0 0 193.88 19.531A182.46 182.46 0 0 0 193.812 19.544Q193.727 19.561 193.681 19.571A21.283 21.283 0 0 0 193.67 19.573A87.884 87.884 0 0 0 193.52 19.607Q193.444 19.625 193.36 19.646A150.463 150.463 0 0 0 193.303 19.661Q193.096 19.713 192.914 19.829A9.901 9.901 0 0 0 192.638 20.092A11.635 11.635 0 0 0 192.606 20.14Q192.496 20.312 192.482 20.569A14.069 14.069 0 0 0 192.48 20.644Q192.48 20.833 192.55 21.019Q192.62 21.204 192.767 21.351A10.381 10.381 0 0 0 192.998 21.523A13.004 13.004 0 0 0 193.135 21.589A11.509 11.509 0 0 0 193.383 21.659Q193.498 21.678 193.629 21.68A19.554 19.554 0 0 0 193.656 21.68A22.373 22.373 0 0 0 193.935 21.663A16.841 16.841 0 0 0 194.185 21.614Q194.419 21.547 194.598 21.453A21.631 21.631 0 0 0 194.743 21.369Q194.816 21.322 194.877 21.274A12.71 12.71 0 0 0 194.899 21.257A45.541 45.541 0 0 0 194.97 21.196Q195.041 21.135 195.088 21.088A13.449 13.449 0 0 0 195.091 21.085ZM206.424 21.085A156.604 156.604 0 0 0 206.468 21.236A174.514 174.514 0 0 0 206.484 21.288A9.866 9.866 0 0 0 206.54 21.434A8.679 8.679 0 0 0 206.564 21.481Q206.613 21.568 206.676 21.624Q206.739 21.68 206.83 21.68Q206.949 21.68 207.037 21.607A2.978 2.978 0 0 0 207.084 21.557Q207.116 21.514 207.122 21.467A1.833 1.833 0 0 0 207.124 21.442A5.283 5.283 0 0 0 207.116 21.354Q207.108 21.307 207.093 21.257A113.074 113.074 0 0 1 207.082 21.221Q207.06 21.15 207.054 21.127A9.687 9.687 0 0 1 207.029 21.059Q207.017 21.022 207.005 20.98A21.964 21.964 0 0 1 206.988 20.91Q206.961 20.799 206.957 20.605A35.786 35.786 0 0 1 206.956 20.525Q206.956 20.467 206.959 20.329A329.739 329.739 0 0 1 206.96 20.305Q206.963 20.147 206.967 19.965Q206.97 19.783 206.974 19.619A290.299 290.299 0 0 0 206.975 19.542Q206.977 19.437 206.977 19.384A50.037 50.037 0 0 0 206.964 19.009A40.849 40.849 0 0 0 206.942 18.796A10.854 10.854 0 0 0 206.861 18.497A9.517 9.517 0 0 0 206.76 18.32Q206.613 18.117 206.316 18.002Q206.021 17.887 205.511 17.886A46.251 46.251 0 0 0 205.5 17.886Q205.157 17.886 204.905 17.946A13.799 13.799 0 0 0 204.699 18.012Q204.466 18.108 204.313 18.227A10.032 10.032 0 0 0 204.226 18.303Q204.058 18.467 204.002 18.632A19.398 19.398 0 0 0 203.978 18.708Q203.956 18.782 203.949 18.833A3.082 3.082 0 0 0 203.946 18.873A2.545 2.545 0 0 0 203.966 18.975A2.432 2.432 0 0 0 204.027 19.059Q204.107 19.132 204.219 19.132Q204.309 19.132 204.364 19.096A1.703 1.703 0 0 0 204.415 19.045Q204.471 18.957 204.52 18.838Q204.576 18.698 204.685 18.6Q204.793 18.502 204.93 18.443A11.745 11.745 0 0 1 205.185 18.365A13.202 13.202 0 0 1 205.224 18.359Q205.381 18.334 205.542 18.334Q205.829 18.334 205.992 18.404A5.36 5.36 0 0 1 206.008 18.411A6.24 6.24 0 0 1 206.135 18.489A4.723 4.723 0 0 1 206.249 18.621A7.268 7.268 0 0 1 206.335 18.86A8.677 8.677 0 0 1 206.344 18.922A52.243 52.243 0 0 1 206.364 19.182A58.488 58.488 0 0 1 206.368 19.272A58.673 58.673 0 0 1 206.311 19.292Q206.231 19.319 206.176 19.335Q206.102 19.356 206.025 19.377Q205.974 19.39 205.848 19.415A131.725 131.725 0 0 1 205.826 19.419Q205.682 19.447 205.521 19.475A202.132 202.132 0 0 0 205.287 19.517A176.919 176.919 0 0 0 205.213 19.531A182.46 182.46 0 0 0 205.145 19.544Q205.06 19.561 205.014 19.571A21.283 21.283 0 0 0 205.003 19.573A87.884 87.884 0 0 0 204.853 19.607Q204.777 19.625 204.693 19.646A150.463 150.463 0 0 0 204.636 19.661Q204.429 19.713 204.247 19.829A9.901 9.901 0 0 0 203.971 20.092A11.635 11.635 0 0 0 203.939 20.14Q203.829 20.312 203.815 20.569A14.069 14.069 0 0 0 203.813 20.644Q203.813 20.833 203.883 21.019Q203.953 21.204 204.1 21.351A10.381 10.381 0 0 0 204.331 21.523A13.004 13.004 0 0 0 204.468 21.589A11.509 11.509 0 0 0 204.716 21.659Q204.831 21.678 204.962 21.68A19.554 19.554 0 0 0 204.989 21.68A22.373 22.373 0 0 0 205.268 21.663A16.841 16.841 0 0 0 205.518 21.614Q205.752 21.547 205.931 21.453A21.631 21.631 0 0 0 206.076 21.369Q206.149 21.322 206.21 21.274A12.71 12.71 0 0 0 206.232 21.257A45.541 45.541 0 0 0 206.303 21.196Q206.374 21.135 206.421 21.088A13.449 13.449 0 0 0 206.424 21.085ZM177.794 19.902L179.971 19.902Q180.062 19.902 180.157 19.895Q180.251 19.888 180.332 19.853Q180.412 19.818 180.461 19.738Q180.51 19.657 180.51 19.51A8.226 8.226 0 0 0 180.508 19.461Q180.504 19.391 180.489 19.283A16.26 16.26 0 0 0 180.46 19.129Q180.442 19.055 180.416 18.973A26.778 26.778 0 0 0 180.409 18.95A17.318 17.318 0 0 0 180.314 18.72A21.358 21.358 0 0 0 180.237 18.579A13.255 13.255 0 0 0 179.998 18.285A15.344 15.344 0 0 0 179.943 18.236Q179.761 18.082 179.502 17.984A14.303 14.303 0 0 0 179.228 17.912Q179.1 17.891 178.954 17.887A24.995 24.995 0 0 0 178.886 17.886Q178.461 17.886 178.146 18.023A13.781 13.781 0 0 0 178.123 18.033Q177.801 18.18 177.591 18.436A16.765 16.765 0 0 0 177.319 18.911A19.805 19.805 0 0 0 177.276 19.038A24.845 24.845 0 0 0 177.174 19.655A28.502 28.502 0 0 0 177.171 19.776Q177.171 20.175 177.273 20.525Q177.374 20.875 177.588 21.131Q177.801 21.386 178.127 21.533A15.933 15.933 0 0 0 178.507 21.648Q178.679 21.678 178.874 21.68A26.983 26.983 0 0 0 178.9 21.68A24.666 24.666 0 0 0 179.157 21.667Q179.289 21.654 179.401 21.625A13.385 13.385 0 0 0 179.478 21.603A19.788 19.788 0 0 0 179.675 21.529Q179.793 21.477 179.887 21.414Q180.055 21.302 180.157 21.176Q180.234 21.08 180.289 21A17.945 17.945 0 0 0 180.321 20.952A14.683 14.683 0 0 0 180.372 20.859A17.681 17.681 0 0 0 180.402 20.798Q180.44 20.714 180.44 20.63A2.258 2.258 0 0 0 180.378 20.474A2.928 2.928 0 0 0 180.374 20.469A2.17 2.17 0 0 0 180.216 20.399A2.698 2.698 0 0 0 180.209 20.399Q180.097 20.399 180.041 20.466A26.352 26.352 0 0 0 180.002 20.513Q179.987 20.532 179.974 20.549A12.788 12.788 0 0 0 179.95 20.581Q179.873 20.7 179.786 20.819Q179.698 20.938 179.583 21.029A8.961 8.961 0 0 1 179.405 21.137A11.002 11.002 0 0 1 179.31 21.176Q179.152 21.232 178.928 21.232Q178.711 21.232 178.512 21.162A9.41 9.41 0 0 1 178.157 20.937A10.742 10.742 0 0 1 178.155 20.935A10.148 10.148 0 0 1 177.998 20.73A13.99 13.99 0 0 1 177.899 20.522A14.497 14.497 0 0 1 177.829 20.268Q177.806 20.143 177.798 20A26.817 26.817 0 0 1 177.794 19.902ZM160.49 21.05L160.49 21.267A12.437 12.437 0 0 0 160.49 21.29Q160.491 21.321 160.493 21.362A37.885 37.885 0 0 0 160.494 21.376A4.031 4.031 0 0 0 160.51 21.469A4.921 4.921 0 0 0 160.525 21.512Q160.553 21.582 160.613 21.631Q160.66 21.67 160.74 21.678A4.425 4.425 0 0 0 160.784 21.68A3.105 3.105 0 0 0 160.895 21.661A2.79 2.79 0 0 0 160.994 21.596A2.175 2.175 0 0 0 161.062 21.48A2.923 2.923 0 0 0 161.068 21.446A13.958 13.958 0 0 0 161.073 21.381Q161.078 21.305 161.078 21.204A44.546 44.546 0 0 0 161.078 21.197L161.078 17.004A44.226 44.226 0 0 0 161.076 16.874A49.881 49.881 0 0 0 161.075 16.829A5.027 5.027 0 0 0 161.062 16.732A4.139 4.139 0 0 0 161.04 16.665Q161.008 16.591 160.945 16.546Q160.882 16.5 160.77 16.5Q160.694 16.5 160.641 16.521A2.056 2.056 0 0 0 160.595 16.546Q160.532 16.591 160.504 16.665A4.762 4.762 0 0 0 160.478 16.766A5.995 5.995 0 0 0 160.473 16.829Q160.469 16.92 160.469 17.011L160.469 18.516A2.504 2.504 0 0 0 160.457 18.498Q160.428 18.459 160.357 18.38A10.281 10.281 0 0 0 160.279 18.302Q160.234 18.262 160.179 18.22A21.748 21.748 0 0 0 160.105 18.166Q159.944 18.054 159.717 17.97A13.078 13.078 0 0 0 159.455 17.905Q159.329 17.886 159.188 17.886Q158.801 17.886 158.524 18.01A11.161 11.161 0 0 0 158.411 18.068A15.529 15.529 0 0 0 158.032 18.379A14.284 14.284 0 0 0 157.918 18.527Q157.732 18.803 157.659 19.132A31.593 31.593 0 0 0 157.6 19.484A24.8 24.8 0 0 0 157.585 19.748A25.356 25.356 0 0 0 157.6 20.012Q157.616 20.17 157.652 20.347Q157.718 20.679 157.9 20.977Q158.082 21.274 158.394 21.477A11.715 11.715 0 0 0 158.748 21.629Q158.901 21.667 159.08 21.677A22.684 22.684 0 0 0 159.202 21.68A19.893 19.893 0 0 0 159.439 21.667Q159.56 21.652 159.664 21.622A11.619 11.619 0 0 0 159.703 21.61Q159.916 21.54 160.07 21.442Q160.224 21.344 160.326 21.236Q160.425 21.13 160.487 21.054A20.372 20.372 0 0 0 160.49 21.05ZM184.01 21.05L184.01 21.267A12.437 12.437 0 0 0 184.01 21.29Q184.011 21.321 184.013 21.362A37.885 37.885 0 0 0 184.014 21.376A4.031 4.031 0 0 0 184.03 21.469A4.921 4.921 0 0 0 184.045 21.512Q184.073 21.582 184.133 21.631Q184.18 21.67 184.26 21.678A4.425 4.425 0 0 0 184.304 21.68A3.105 3.105 0 0 0 184.415 21.661A2.79 2.79 0 0 0 184.514 21.596A2.175 2.175 0 0 0 184.582 21.48A2.923 2.923 0 0 0 184.588 21.446A13.958 13.958 0 0 0 184.593 21.381Q184.598 21.305 184.598 21.204A44.546 44.546 0 0 0 184.598 21.197L184.598 17.004A44.226 44.226 0 0 0 184.596 16.874A49.881 49.881 0 0 0 184.595 16.829A5.027 5.027 0 0 0 184.582 16.732A4.139 4.139 0 0 0 184.56 16.665Q184.528 16.591 184.465 16.546Q184.402 16.5 184.29 16.5Q184.214 16.5 184.161 16.521A2.056 2.056 0 0 0 184.115 16.546Q184.052 16.591 184.024 16.665A4.762 4.762 0 0 0 183.998 16.766A5.995 5.995 0 0 0 183.993 16.829Q183.989 16.92 183.989 17.011L183.989 18.516A2.504 2.504 0 0 0 183.977 18.498Q183.948 18.459 183.877 18.38A10.281 10.281 0 0 0 183.799 18.302Q183.754 18.262 183.699 18.22A21.748 21.748 0 0 0 183.625 18.166Q183.464 18.054 183.237 17.97A13.078 13.078 0 0 0 182.975 17.905Q182.849 17.886 182.708 17.886Q182.321 17.886 182.044 18.01A11.161 11.161 0 0 0 181.931 18.068A15.529 15.529 0 0 0 181.552 18.379A14.284 14.284 0 0 0 181.438 18.527Q181.252 18.803 181.179 19.132A31.593 31.593 0 0 0 181.12 19.484A24.8 24.8 0 0 0 181.105 19.748A25.356 25.356 0 0 0 181.12 20.012Q181.136 20.17 181.172 20.347Q181.238 20.679 181.42 20.977Q181.602 21.274 181.914 21.477A11.715 11.715 0 0 0 182.268 21.629Q182.421 21.667 182.6 21.677A22.684 22.684 0 0 0 182.722 21.68A19.893 19.893 0 0 0 182.959 21.667Q183.08 21.652 183.184 21.622A11.619 11.619 0 0 0 183.223 21.61Q183.436 21.54 183.59 21.442Q183.744 21.344 183.846 21.236Q183.945 21.13 184.007 21.054A20.372 20.372 0 0 0 184.01 21.05ZM164.312 18.264L163.325 20.903L162.331 18.264Q162.271 18.09 162.211 17.993A6.228 6.228 0 0 0 162.205 17.984A2.038 2.038 0 0 0 162.077 17.895Q162.04 17.886 161.995 17.886Q161.848 17.886 161.771 17.977A4.199 4.199 0 0 0 161.73 18.035Q161.694 18.095 161.694 18.152A4.814 4.814 0 0 0 161.699 18.22A3.684 3.684 0 0 0 161.712 18.278A9.92 9.92 0 0 0 161.723 18.311Q161.738 18.355 161.766 18.427A84.529 84.529 0 0 0 161.785 18.474L162.891 21.232Q162.952 21.378 163.01 21.483A12.632 12.632 0 0 0 163.056 21.558A2.582 2.582 0 0 0 163.21 21.666Q163.255 21.678 163.309 21.68A5.626 5.626 0 0 0 163.325 21.68A4.256 4.256 0 0 0 163.424 21.669A2.598 2.598 0 0 0 163.588 21.558Q163.646 21.469 163.706 21.338A30.263 30.263 0 0 0 163.752 21.232L164.858 18.474A79.208 79.208 0 0 0 164.883 18.411Q164.913 18.334 164.927 18.292A7.545 7.545 0 0 0 164.932 18.278A3.771 3.771 0 0 0 164.946 18.209A4.945 4.945 0 0 0 164.949 18.152Q164.949 18.097 164.909 18.032A4.909 4.909 0 0 0 164.872 17.981A2.49 2.49 0 0 0 164.723 17.893A3.793 3.793 0 0 0 164.648 17.886A3.446 3.446 0 0 0 164.568 17.895Q164.513 17.908 164.475 17.941A2.009 2.009 0 0 0 164.438 17.984A7.867 7.867 0 0 0 164.399 18.054Q164.358 18.133 164.318 18.248A26.244 26.244 0 0 0 164.312 18.264ZM202.861 18.264L201.874 20.903L200.88 18.264Q200.82 18.09 200.76 17.993A6.228 6.228 0 0 0 200.754 17.984A2.038 2.038 0 0 0 200.626 17.895Q200.589 17.886 200.544 17.886Q200.397 17.886 200.32 17.977A4.199 4.199 0 0 0 200.279 18.035Q200.243 18.095 200.243 18.152A4.814 4.814 0 0 0 200.248 18.22A3.684 3.684 0 0 0 200.261 18.278A9.92 9.92 0 0 0 200.272 18.311Q200.287 18.355 200.315 18.427A84.529 84.529 0 0 0 200.334 18.474L201.44 21.232Q201.501 21.378 201.559 21.483A12.632 12.632 0 0 0 201.605 21.558A2.582 2.582 0 0 0 201.759 21.666Q201.804 21.678 201.858 21.68A5.626 5.626 0 0 0 201.874 21.68A4.256 4.256 0 0 0 201.973 21.669A2.598 2.598 0 0 0 202.137 21.558Q202.195 21.469 202.255 21.338A30.263 30.263 0 0 0 202.301 21.232L203.407 18.474A79.208 79.208 0 0 0 203.432 18.411Q203.462 18.334 203.476 18.292A7.545 7.545 0 0 0 203.481 18.278A3.771 3.771 0 0 0 203.495 18.209A4.945 4.945 0 0 0 203.498 18.152Q203.498 18.097 203.458 18.032A4.909 4.909 0 0 0 203.421 17.981A2.49 2.49 0 0 0 203.272 17.893A3.793 3.793 0 0 0 203.197 17.886A3.446 3.446 0 0 0 203.117 17.895Q203.062 17.908 203.024 17.941A2.009 2.009 0 0 0 202.987 17.984A7.867 7.867 0 0 0 202.948 18.054Q202.907 18.133 202.867 18.248A26.244 26.244 0 0 0 202.861 18.264ZM159.076 21.172A9.992 9.992 0 0 0 159.321 21.204Q159.524 21.204 159.731 21.134A9.14 9.14 0 0 0 159.831 21.093A9.773 9.773 0 0 0 160.102 20.9A10.93 10.93 0 0 0 160.26 20.697A14.782 14.782 0 0 0 160.371 20.473Q160.437 20.309 160.461 20.094A24.26 24.26 0 0 0 160.476 19.818Q160.476 19.356 160.343 19.073A18.755 18.755 0 0 0 160.322 19.029Q160.196 18.777 160.025 18.632A12.131 12.131 0 0 0 159.883 18.528A9.354 9.354 0 0 0 159.64 18.418A19.608 19.608 0 0 0 159.535 18.392Q159.402 18.362 159.3 18.362A11.478 11.478 0 0 0 159.207 18.366A9.465 9.465 0 0 0 158.845 18.467Q158.642 18.572 158.499 18.761Q158.355 18.95 158.282 19.206A17.995 17.995 0 0 0 158.242 19.373A20.798 20.798 0 0 0 158.208 19.755A27.923 27.923 0 0 0 158.211 19.894Q158.227 20.21 158.317 20.438Q158.371 20.576 158.438 20.688A11.647 11.647 0 0 0 158.586 20.886Q158.747 21.057 158.943 21.131A12.502 12.502 0 0 0 159.076 21.172ZM182.596 21.172A9.992 9.992 0 0 0 182.841 21.204Q183.044 21.204 183.251 21.134A9.14 9.14 0 0 0 183.351 21.093A9.773 9.773 0 0 0 183.622 20.9A10.93 10.93 0 0 0 183.78 20.697A14.782 14.782 0 0 0 183.891 20.473Q183.957 20.309 183.981 20.094A24.26 24.26 0 0 0 183.996 19.818Q183.996 19.356 183.863 19.073A18.755 18.755 0 0 0 183.842 19.029Q183.716 18.777 183.545 18.632A12.131 12.131 0 0 0 183.403 18.528A9.354 9.354 0 0 0 183.16 18.418A19.608 19.608 0 0 0 183.055 18.392Q182.922 18.362 182.82 18.362A11.478 11.478 0 0 0 182.727 18.366A9.465 9.465 0 0 0 182.365 18.467Q182.162 18.572 182.019 18.761Q181.875 18.95 181.802 19.206A17.995 17.995 0 0 0 181.762 19.373A20.798 20.798 0 0 0 181.728 19.755A27.923 27.923 0 0 0 181.731 19.894Q181.747 20.21 181.837 20.438Q181.891 20.576 181.958 20.688A11.647 11.647 0 0 0 182.106 20.886Q182.267 21.057 182.463 21.131A12.502 12.502 0 0 0 182.596 21.172ZM155.772 19.608L153.931 19.608L154.834 17.263L155.772 19.608ZM147.704 19.422A124.043 124.043 0 0 0 147.736 19.461A187.068 187.068 0 0 0 147.977 19.75A209.521 209.521 0 0 0 148.062 19.85Q148.233 20.049 148.405 20.238A280.942 280.942 0 0 0 148.527 20.372Q148.575 20.424 148.619 20.471A146.266 146.266 0 0 0 148.702 20.56A32.139 32.139 0 0 1 148.675 20.594Q148.644 20.633 148.602 20.683A116.402 116.402 0 0 1 148.562 20.732A12.456 12.456 0 0 1 148.433 20.863A15.356 15.356 0 0 1 148.342 20.938A13.22 13.22 0 0 1 148.163 21.051A16.357 16.357 0 0 1 148.041 21.11Q147.869 21.183 147.652 21.183A9.592 9.592 0 0 1 147.375 21.144A8.638 8.638 0 0 1 147.243 21.092Q147.057 21.001 146.921 20.854Q146.784 20.707 146.711 20.525Q146.637 20.343 146.637 20.154A8.237 8.237 0 0 1 146.655 19.979A6.431 6.431 0 0 1 146.711 19.822A10.984 10.984 0 0 1 146.895 19.564A12.277 12.277 0 0 1 146.903 19.556A14.899 14.899 0 0 1 147.147 19.354A16.679 16.679 0 0 1 147.176 19.335Q147.33 19.237 147.491 19.146Q147.572 19.259 147.704 19.422ZM167.826 19.706Q167.826 20.014 167.802 20.256A11.719 11.719 0 0 1 167.753 20.495A9.411 9.411 0 0 1 167.672 20.679Q167.595 20.819 167.469 20.917Q167.343 21.015 167.193 21.078Q167.042 21.141 166.885 21.173A16.044 16.044 0 0 1 166.654 21.202A14.108 14.108 0 0 1 166.58 21.204A10.041 10.041 0 0 1 166.436 21.194Q166.337 21.18 166.258 21.145A7.637 7.637 0 0 1 166.147 21.084A5.572 5.572 0 0 1 166.045 20.998A5.836 5.836 0 0 1 165.939 20.839A5.49 5.49 0 0 1 165.926 20.805A6.447 6.447 0 0 1 165.894 20.689A5.291 5.291 0 0 1 165.887 20.602Q165.887 20.553 165.905 20.476A4.746 4.746 0 0 1 165.935 20.386A6.234 6.234 0 0 1 165.971 20.319A4.921 4.921 0 0 1 166.039 20.232A6.678 6.678 0 0 1 166.111 20.168A5.299 5.299 0 0 1 166.201 20.113Q166.247 20.091 166.302 20.072A10.661 10.661 0 0 1 166.356 20.056A55.947 55.947 0 0 1 166.613 19.996A71.051 71.051 0 0 1 166.832 19.955A87.518 87.518 0 0 0 167.072 19.909Q167.194 19.884 167.329 19.853A147.944 147.944 0 0 0 167.42 19.832Q167.527 19.805 167.61 19.781A25.521 25.521 0 0 0 167.658 19.766A34.628 34.628 0 0 0 167.728 19.742Q167.762 19.731 167.792 19.719A18.009 18.009 0 0 0 167.826 19.706ZM195.042 19.706Q195.042 20.014 195.018 20.256A11.719 11.719 0 0 1 194.969 20.495A9.411 9.411 0 0 1 194.888 20.679Q194.811 20.819 194.685 20.917Q194.559 21.015 194.409 21.078Q194.258 21.141 194.101 21.173A16.044 16.044 0 0 1 193.87 21.202A14.108 14.108 0 0 1 193.796 21.204A10.041 10.041 0 0 1 193.652 21.194Q193.553 21.18 193.474 21.145A7.637 7.637 0 0 1 193.363 21.084A5.572 5.572 0 0 1 193.261 20.998A5.836 5.836 0 0 1 193.155 20.839A5.49 5.49 0 0 1 193.142 20.805A6.447 6.447 0 0 1 193.11 20.689A5.291 5.291 0 0 1 193.103 20.602Q193.103 20.553 193.121 20.476A4.746 4.746 0 0 1 193.151 20.386A6.234 6.234 0 0 1 193.187 20.319A4.921 4.921 0 0 1 193.255 20.232A6.678 6.678 0 0 1 193.327 20.168A5.299 5.299 0 0 1 193.417 20.113Q193.463 20.091 193.518 20.072A10.661 10.661 0 0 1 193.572 20.056A55.947 55.947 0 0 1 193.829 19.996A71.051 71.051 0 0 1 194.048 19.955A87.518 87.518 0 0 0 194.288 19.909Q194.41 19.884 194.545 19.853A147.944 147.944 0 0 0 194.636 19.832Q194.743 19.805 194.826 19.781A25.521 25.521 0 0 0 194.874 19.766A34.628 34.628 0 0 0 194.944 19.742Q194.978 19.731 195.008 19.719A18.009 18.009 0 0 0 195.042 19.706ZM206.375 19.706Q206.375 20.014 206.351 20.256A11.719 11.719 0 0 1 206.302 20.495A9.411 9.411 0 0 1 206.221 20.679Q206.144 20.819 206.018 20.917Q205.892 21.015 205.742 21.078Q205.591 21.141 205.434 21.173A16.044 16.044 0 0 1 205.203 21.202A14.108 14.108 0 0 1 205.129 21.204A10.041 10.041 0 0 1 204.985 21.194Q204.886 21.18 204.807 21.145A7.637 7.637 0 0 1 204.696 21.084A5.572 5.572 0 0 1 204.594 20.998A5.836 5.836 0 0 1 204.488 20.839A5.49 5.49 0 0 1 204.475 20.805A6.447 6.447 0 0 1 204.443 20.689A5.291 5.291 0 0 1 204.436 20.602Q204.436 20.553 204.454 20.476A4.746 4.746 0 0 1 204.484 20.386A6.234 6.234 0 0 1 204.52 20.319A4.921 4.921 0 0 1 204.588 20.232A6.678 6.678 0 0 1 204.66 20.168A5.299 5.299 0 0 1 204.75 20.113Q204.796 20.091 204.851 20.072A10.661 10.661 0 0 1 204.905 20.056A55.947 55.947 0 0 1 205.162 19.996A71.051 71.051 0 0 1 205.381 19.955A87.518 87.518 0 0 0 205.621 19.909Q205.743 19.884 205.878 19.853A147.944 147.944 0 0 0 205.969 19.832Q206.076 19.805 206.159 19.781A25.521 25.521 0 0 0 206.207 19.766A34.628 34.628 0 0 0 206.277 19.742Q206.311 19.731 206.341 19.719A18.009 18.009 0 0 0 206.375 19.706ZM179.887 19.482L177.801 19.482A28.069 28.069 0 0 1 177.814 19.387Q177.827 19.303 177.847 19.202A10.166 10.166 0 0 1 177.92 18.976A12.334 12.334 0 0 1 177.969 18.88Q178.018 18.789 178.095 18.691A8.296 8.296 0 0 1 178.243 18.546A9.616 9.616 0 0 1 178.284 18.516Q178.396 18.439 178.54 18.387Q178.683 18.334 178.865 18.334Q179.166 18.334 179.376 18.464Q179.586 18.593 179.705 18.796A14.726 14.726 0 0 1 179.78 18.94Q179.813 19.014 179.831 19.082A7.079 7.079 0 0 1 179.849 19.164A57.705 57.705 0 0 1 179.879 19.404A51.717 51.717 0 0 1 179.887 19.482ZM147.722 18.46A5.735 5.735 0 0 0 147.714 18.448Q147.698 18.426 147.666 18.383A159.702 159.702 0 0 1 147.622 18.324A204.664 204.664 0 0 1 147.575 18.261Q147.526 18.194 147.484 18.138A28.341 28.341 0 0 0 147.469 18.119Q147.447 18.089 147.435 18.075A1.535 1.535 0 0 0 147.428 18.068Q147.372 17.991 147.313 17.854A6.976 6.976 0 0 1 147.255 17.63A6.56 6.56 0 0 1 147.253 17.578Q147.253 17.466 147.299 17.357Q147.344 17.249 147.428 17.165A6.428 6.428 0 0 1 147.588 17.049A7.566 7.566 0 0 1 147.631 17.029A6.258 6.258 0 0 1 147.86 16.977A7.29 7.29 0 0 1 147.89 16.976A6.985 6.985 0 0 1 148.099 17.006A5.558 5.558 0 0 1 148.342 17.158Q148.513 17.34 148.513 17.585A5.96 5.96 0 0 1 148.479 17.788A5.572 5.572 0 0 1 148.45 17.854A8.463 8.463 0 0 1 148.321 18.039A9.906 9.906 0 0 1 148.279 18.082A14.839 14.839 0 0 1 148.113 18.22A17.789 17.789 0 0 1 148.027 18.278A67.874 67.874 0 0 1 147.801 18.415A77.011 77.011 0 0 1 147.722 18.46Z"/>';
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 */