Files
ITManager-Vault/.obsidian/plugins/folder-notes/main.js
Alex Kogutkiewicz 837d0bb6ac First init.
2025-09-21 21:24:47 -05:00

9105 lines
371 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(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// node_modules/front-matter-plugin-api-provider/lib/contracts/Api.js
var require_Api = __commonJS({
"node_modules/front-matter-plugin-api-provider/lib/contracts/Api.js"(exports) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
}
});
// node_modules/front-matter-plugin-api-provider/lib/contracts/EventDispatcher.js
var require_EventDispatcher = __commonJS({
"node_modules/front-matter-plugin-api-provider/lib/contracts/EventDispatcher.js"(exports) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
}
});
// node_modules/front-matter-plugin-api-provider/lib/contracts/Resolver.js
var require_Resolver = __commonJS({
"node_modules/front-matter-plugin-api-provider/lib/contracts/Resolver.js"(exports) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
}
});
// node_modules/front-matter-plugin-api-provider/lib/index.js
var require_lib = __commonJS({
"node_modules/front-matter-plugin-api-provider/lib/index.js"(exports) {
"use strict";
var __createBinding = exports && exports.__createBinding || (Object.create ? function(o, m, k, k2) {
if (k2 === void 0)
k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() {
return m[k];
} };
}
Object.defineProperty(o, k2, desc);
} : function(o, m, k, k2) {
if (k2 === void 0)
k2 = k;
o[k2] = m[k];
});
var __exportStar = exports && exports.__exportStar || function(m, exports2) {
for (var p in m)
if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports2, p))
__createBinding(exports2, m, p);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getApiSafe = exports.getDefer = exports.isPluginEnabled = exports.PluginNotEnabledError = exports.pluginId = void 0;
__exportStar(require_Api(), exports);
__exportStar(require_EventDispatcher(), exports);
__exportStar(require_Resolver(), exports);
exports.pluginId = "obsidian-front-matter-title-plugin";
var PluginNotEnabledError = class extends Error {
};
exports.PluginNotEnabledError = PluginNotEnabledError;
function isPluginEnabled(app2) {
var _a, _b, _c;
return (_c = (_b = (_a = app2 === null || app2 === void 0 ? void 0 : app2.plugins) === null || _a === void 0 ? void 0 : _a.enabledPlugins) === null || _b === void 0 ? void 0 : _b.has(exports.pluginId)) !== null && _c !== void 0 ? _c : false;
}
exports.isPluginEnabled = isPluginEnabled;
function getDefer3(app2) {
var _a, _b, _c, _d;
const plugin = (_b = (_a = app2 === null || app2 === void 0 ? void 0 : app2.plugins) === null || _a === void 0 ? void 0 : _a.getPlugin(exports.pluginId)) !== null && _b !== void 0 ? _b : null;
const defer = (_d = (_c = plugin === null || plugin === void 0 ? void 0 : plugin.getDefer) === null || _c === void 0 ? void 0 : _c.call(plugin)) !== null && _d !== void 0 ? _d : null;
if (defer === null) {
throw new PluginNotEnabledError(`Plugin ${exports.pluginId} is not enabled or old version`);
}
return defer;
}
exports.getDefer = getDefer3;
function getApiSafe(app2) {
return new ApiWrapper(null, app2);
}
exports.getApiSafe = getApiSafe;
var ApiWrapper = class {
constructor(api, app2) {
this.api = api;
this.app = app2;
}
before() {
if (this.api !== null) {
return;
}
const defer = this.getDeffer();
if (defer === null) {
return;
}
const api = defer.getApi();
if (api === null) {
return defer.awaitPlugin().then(() => {
this.api = defer.getApi();
});
} else {
this.api = api;
}
}
getDeffer() {
try {
return getDefer3(this.app);
} catch (e) {
if (e instanceof PluginNotEnabledError) {
return null;
}
throw e;
}
}
getResolverFactory() {
var _a, _b;
this.before();
return (_b = (_a = this.api) === null || _a === void 0 ? void 0 : _a.getResolverFactory()) !== null && _b !== void 0 ? _b : null;
}
getEventDispatcher() {
var _a, _b;
this.before();
return (_b = (_a = this.api) === null || _a === void 0 ? void 0 : _a.getEventDispatcher()) !== null && _b !== void 0 ? _b : null;
}
getEnabledFeatures() {
var _a, _b;
this.before();
return (_b = (_a = this.api) === null || _a === void 0 ? void 0 : _a.getEnabledFeatures()) !== null && _b !== void 0 ? _b : [];
}
};
}
});
// src/main.ts
var main_exports = {};
__export(main_exports, {
default: () => FolderNotesPlugin
});
module.exports = __toCommonJS(main_exports);
var import_obsidian52 = require("obsidian");
// src/settings/SettingsTab.ts
var import_obsidian40 = require("obsidian");
// src/modals/ExistingNote.ts
var import_obsidian = require("obsidian");
var ExistingFolderNoteModal = class extends import_obsidian.Modal {
constructor(app2, plugin, file, folder, folderNote) {
super(app2);
this.plugin = plugin;
this.app = app2;
this.file = file;
this.folder = folder;
this.folderNote = folderNote;
}
onOpen() {
var _a;
const { contentEl } = this;
contentEl.createEl("h2", { text: "A folder note for this folder already exists" });
const setting = new import_obsidian.Setting(contentEl);
setting.infoEl.createEl("p", { text: "Are you sure you want to turn the note into a folder note and rename the existing folder note?" });
(_a = setting.infoEl.parentElement) == null ? void 0 : _a.classList.add("fn-delete-confirmation-modal");
const buttonContainer = setting.infoEl.createEl("div", { cls: "fn-delete-confirmation-modal-buttons" });
if (import_obsidian.Platform.isMobileApp) {
const confirmButton = buttonContainer.createEl("button", {
text: "Rename and don't ask again"
});
confirmButton.classList.add("mod-warning", "fn-confirmation-modal-button");
confirmButton.addEventListener("click", async () => {
this.plugin.settings.showRenameConfirmation = false;
this.plugin.saveSettings();
this.close();
turnIntoFolderNote(this.plugin, this.file, this.folder, this.folderNote, true);
});
} else {
const checkbox = buttonContainer.createEl("input", { type: "checkbox" });
checkbox.addEventListener("change", (e) => {
const target = e.target;
if (target.checked) {
this.plugin.settings.showRenameConfirmation = false;
} else {
this.plugin.settings.showRenameConfirmation = true;
}
});
const checkBoxText = buttonContainer.createEl("span", { text: "Don't ask again" });
checkBoxText.addEventListener("click", () => {
checkbox.click();
});
}
const button = buttonContainer.createEl("button", { text: "Rename" });
button.classList.add("mod-warning", "fn-confirmation-modal-button");
button.addEventListener("click", async () => {
this.plugin.saveSettings();
this.close();
turnIntoFolderNote(this.plugin, this.file, this.folder, this.folderNote, true);
});
button.focus();
const cancelButton = buttonContainer.createEl("button", { text: "Cancel" });
cancelButton.addEventListener("click", async () => {
this.close();
});
}
onClose() {
const { contentEl } = this;
contentEl.empty();
}
};
// src/template.ts
var import_obsidian2 = require("obsidian");
async function applyTemplate(plugin, file, leaf, templatePath) {
const fileContent = await plugin.app.vault.read(file).catch((err) => {
console.error(`Error reading file ${file.path}:`, err);
});
if (fileContent !== "")
return;
const templateFile = templatePath ? plugin.app.vault.getAbstractFileByPath(templatePath) : null;
if (templateFile && templateFile instanceof import_obsidian2.TFile) {
try {
const {
templatesEnabled,
templaterEnabled,
templatesPlugin,
templaterPlugin
} = getTemplatePlugins(plugin.app);
const templateContent = await plugin.app.vault.read(templateFile);
if (templateContent.includes("==\u26A0 Switch to EXCALIDRAW VIEW in the MORE OPTIONS menu of this document. \u26A0==")) {
return;
}
if (templaterEnabled && templaterPlugin) {
return await templaterPlugin.write_template_to_file(templateFile, file);
} else if (templatesEnabled && templatesPlugin) {
if (leaf instanceof import_obsidian2.WorkspaceLeaf) {
await leaf.openFile(file);
}
return await templatesPlugin.instance.insertTemplate(templateFile);
}
await plugin.app.vault.modify(file, templateContent);
} catch (e) {
console.error(e);
}
}
}
function getTemplatePlugins(app2) {
var _a, _b, _c;
const appAsUnknown = app2;
const templatesPlugin = appAsUnknown.internalPlugins.plugins.templates;
const templatesEnabled = (_a = templatesPlugin == null ? void 0 : templatesPlugin.enabled) != null ? _a : false;
const templaterPlugin = appAsUnknown.plugins.plugins["templater-obsidian"];
const templaterEnabled = appAsUnknown.plugins.enabledPlugins.has("templater-obsidian");
const templaterEmptyFileTemplate = templaterPlugin && ((_b = templaterPlugin.settings) == null ? void 0 : _b.empty_file_template);
const templateFolder = templatesEnabled ? templatesPlugin.instance.options.folder : (_c = templaterPlugin == null ? void 0 : templaterPlugin.settings) == null ? void 0 : _c.template_folder;
return {
templatesPlugin: templatesPlugin || null,
templatesEnabled,
templaterPlugin: (templaterPlugin == null ? void 0 : templaterPlugin.templater) || null,
templaterEnabled,
templaterEmptyFileTemplate,
templateFolder
};
}
// src/functions/folderNoteFunctions.ts
var import_obsidian17 = require("obsidian");
// src/modals/DeleteConfirmation.ts
var import_obsidian3 = require("obsidian");
var DeleteConfirmationModal = class extends import_obsidian3.Modal {
constructor(app2, plugin, file) {
super(app2);
this.plugin = plugin;
this.app = app2;
this.file = file;
}
onOpen() {
const { contentEl, plugin } = this;
const modalTitle = contentEl.createDiv({ cls: "fn-modal-title" });
const modalContent = contentEl.createDiv({ cls: "fn-modal-content" });
modalTitle.createEl("h2", { text: "Delete folder note" });
modalContent.createEl("p", { text: `Are you sure you want to delete the folder note '${this.file.name}' ?` });
switch (plugin.settings.deleteFilesAction) {
case "trash":
modalContent.createEl("p", { text: "It will be moved to your system trash." });
break;
case "obsidianTrash":
modalContent.createEl("p", { text: 'It will be moved to your Obsidian trash, which is located in the ".trash" hidden folder in your vault.' });
break;
case "delete":
modalContent.createEl("p", { text: "It will be permanently deleted." }).setCssStyles({ color: "red" });
break;
}
const buttonContainer = contentEl.createEl("div", { cls: "modal-button-container" });
if (!import_obsidian3.Platform.isMobile) {
const checkbox = buttonContainer.createEl("label", { cls: "mod-checkbox" });
checkbox.tabIndex = -1;
const input = checkbox.createEl("input", { type: "checkbox" });
checkbox.appendText("Don't ask again");
input.addEventListener("change", (e) => {
const target = e.target;
if (target.checked) {
plugin.settings.showDeleteConfirmation = false;
} else {
plugin.settings.showDeleteConfirmation = true;
}
plugin.saveSettings();
});
} else {
const confirmButton = buttonContainer.createEl("button", {
text: "Delete and don't ask again",
cls: "mod-destructive"
});
confirmButton.addEventListener("click", async () => {
plugin.settings.showDeleteConfirmation = false;
plugin.saveSettings();
this.close();
deleteFolderNote(plugin, this.file, false);
});
}
const deleteButton = buttonContainer.createEl("button", {
text: "Delete",
cls: "mod-warning"
});
deleteButton.addEventListener("click", async () => {
this.close();
deleteFolderNote(plugin, this.file, false);
});
deleteButton.focus();
const cancelButton = buttonContainer.createEl("button", {
text: "Cancel",
cls: "mod-cancel"
});
cancelButton.addEventListener("click", async () => {
this.close();
});
}
onClose() {
const { contentEl } = this;
contentEl.empty();
}
};
// src/functions/utils.ts
var import_obsidian4 = require("obsidian");
function getFileNameFromPathString(path) {
return path.substring(path.lastIndexOf("/") >= 0 ? path.lastIndexOf("/") + 1 : 0);
}
function getFolderNameFromPathString(path) {
const PARENT_FOLDER_INDEX = -2;
const LAST_FOLDER_INDEX = -1;
if (path.endsWith(".md") || path.endsWith(".canvas")) {
return path.split("/").slice(PARENT_FOLDER_INDEX)[0];
}
return path.split("/").slice(LAST_FOLDER_INDEX)[0];
}
function removeExtension(name) {
return name.replace(/\.[^/.]+$/, "");
}
function getFolderPathFromString(path) {
const subString = path.lastIndexOf("/") >= 0 ? path.lastIndexOf("/") : 0;
const folderPath = path.substring(0, subString);
if (folderPath === "") {
return "/";
}
return folderPath;
}
function getFileExplorer(plugin) {
const leaf = plugin.app.workspace.getLeavesOfType("file-explorer")[0];
return leaf;
}
function getFileExplorerActiveFolder() {
var _a, _b, _c;
const view = this.app.workspace.getActiveViewOfType(import_obsidian4.View);
if ((view == null ? void 0 : view.getViewType()) !== "file-explorer")
return null;
const fe = view;
const activeFileOrFolder = (_c = (_a = fe.tree.focusedItem) == null ? void 0 : _a.file) != null ? _c : (_b = fe.activeDom) == null ? void 0 : _b.file;
if (!(activeFileOrFolder instanceof import_obsidian4.TFolder))
return null;
return activeFileOrFolder;
}
// src/ExcludeFolders/ExcludePattern.ts
var ExcludePattern = class {
constructor(pattern, position, id, plugin) {
this.type = "pattern";
this.id = id || crypto.randomUUID();
this.string = pattern;
this.position = position;
this.subFolders = plugin.settings.excludePatternDefaultSettings.subFolders;
this.disableSync = plugin.settings.excludePatternDefaultSettings.disableSync;
this.disableAutoCreate = plugin.settings.excludePatternDefaultSettings.disableAutoCreate;
this.disableFolderNote = plugin.settings.excludePatternDefaultSettings.disableFolderNote;
this.enableCollapsing = plugin.settings.excludePatternDefaultSettings.enableCollapsing;
this.excludeFromFolderOverview = plugin.settings.excludePatternDefaultSettings.excludeFromFolderOverview;
this.path = "";
this.hideInSettings = false;
this.showFolderNote = plugin.settings.excludePatternDefaultSettings.showFolderNote;
}
};
// src/ExcludeFolders/functions/folderFunctions.ts
var import_obsidian15 = require("obsidian");
// src/suggesters/FolderSuggester.ts
var import_obsidian6 = require("obsidian");
// src/suggesters/Suggest.ts
var import_obsidian5 = require("obsidian");
// node_modules/@popperjs/core/lib/enums.js
var top = "top";
var bottom = "bottom";
var right = "right";
var left = "left";
var auto = "auto";
var basePlacements = [top, bottom, right, left];
var start = "start";
var end = "end";
var clippingParents = "clippingParents";
var viewport = "viewport";
var popper = "popper";
var reference = "reference";
var variationPlacements = /* @__PURE__ */ basePlacements.reduce(function(acc, placement) {
return acc.concat([placement + "-" + start, placement + "-" + end]);
}, []);
var placements = /* @__PURE__ */ [].concat(basePlacements, [auto]).reduce(function(acc, placement) {
return acc.concat([placement, placement + "-" + start, placement + "-" + end]);
}, []);
var beforeRead = "beforeRead";
var read = "read";
var afterRead = "afterRead";
var beforeMain = "beforeMain";
var main = "main";
var afterMain = "afterMain";
var beforeWrite = "beforeWrite";
var write = "write";
var afterWrite = "afterWrite";
var modifierPhases = [beforeRead, read, afterRead, beforeMain, main, afterMain, beforeWrite, write, afterWrite];
// node_modules/@popperjs/core/lib/dom-utils/getNodeName.js
function getNodeName(element) {
return element ? (element.nodeName || "").toLowerCase() : null;
}
// node_modules/@popperjs/core/lib/dom-utils/getWindow.js
function getWindow(node) {
if (node == null) {
return window;
}
if (node.toString() !== "[object Window]") {
var ownerDocument = node.ownerDocument;
return ownerDocument ? ownerDocument.defaultView || window : window;
}
return node;
}
// node_modules/@popperjs/core/lib/dom-utils/instanceOf.js
function isElement(node) {
var OwnElement = getWindow(node).Element;
return node instanceof OwnElement || node instanceof Element;
}
function isHTMLElement(node) {
var OwnElement = getWindow(node).HTMLElement;
return node instanceof OwnElement || node instanceof HTMLElement;
}
function isShadowRoot(node) {
if (typeof ShadowRoot === "undefined") {
return false;
}
var OwnElement = getWindow(node).ShadowRoot;
return node instanceof OwnElement || node instanceof ShadowRoot;
}
// node_modules/@popperjs/core/lib/modifiers/applyStyles.js
function applyStyles(_ref) {
var state = _ref.state;
Object.keys(state.elements).forEach(function(name) {
var style = state.styles[name] || {};
var attributes = state.attributes[name] || {};
var element = state.elements[name];
if (!isHTMLElement(element) || !getNodeName(element)) {
return;
}
Object.assign(element.style, style);
Object.keys(attributes).forEach(function(name2) {
var value = attributes[name2];
if (value === false) {
element.removeAttribute(name2);
} else {
element.setAttribute(name2, value === true ? "" : value);
}
});
});
}
function effect(_ref2) {
var state = _ref2.state;
var initialStyles = {
popper: {
position: state.options.strategy,
left: "0",
top: "0",
margin: "0"
},
arrow: {
position: "absolute"
},
reference: {}
};
Object.assign(state.elements.popper.style, initialStyles.popper);
state.styles = initialStyles;
if (state.elements.arrow) {
Object.assign(state.elements.arrow.style, initialStyles.arrow);
}
return function() {
Object.keys(state.elements).forEach(function(name) {
var element = state.elements[name];
var attributes = state.attributes[name] || {};
var styleProperties = Object.keys(state.styles.hasOwnProperty(name) ? state.styles[name] : initialStyles[name]);
var style = styleProperties.reduce(function(style2, property) {
style2[property] = "";
return style2;
}, {});
if (!isHTMLElement(element) || !getNodeName(element)) {
return;
}
Object.assign(element.style, style);
Object.keys(attributes).forEach(function(attribute) {
element.removeAttribute(attribute);
});
});
};
}
var applyStyles_default = {
name: "applyStyles",
enabled: true,
phase: "write",
fn: applyStyles,
effect,
requires: ["computeStyles"]
};
// node_modules/@popperjs/core/lib/utils/getBasePlacement.js
function getBasePlacement(placement) {
return placement.split("-")[0];
}
// node_modules/@popperjs/core/lib/utils/math.js
var max = Math.max;
var min = Math.min;
var round = Math.round;
// node_modules/@popperjs/core/lib/utils/userAgent.js
function getUAString() {
var uaData = navigator.userAgentData;
if (uaData != null && uaData.brands && Array.isArray(uaData.brands)) {
return uaData.brands.map(function(item) {
return item.brand + "/" + item.version;
}).join(" ");
}
return navigator.userAgent;
}
// node_modules/@popperjs/core/lib/dom-utils/isLayoutViewport.js
function isLayoutViewport() {
return !/^((?!chrome|android).)*safari/i.test(getUAString());
}
// node_modules/@popperjs/core/lib/dom-utils/getBoundingClientRect.js
function getBoundingClientRect(element, includeScale, isFixedStrategy) {
if (includeScale === void 0) {
includeScale = false;
}
if (isFixedStrategy === void 0) {
isFixedStrategy = false;
}
var clientRect = element.getBoundingClientRect();
var scaleX = 1;
var scaleY = 1;
if (includeScale && isHTMLElement(element)) {
scaleX = element.offsetWidth > 0 ? round(clientRect.width) / element.offsetWidth || 1 : 1;
scaleY = element.offsetHeight > 0 ? round(clientRect.height) / element.offsetHeight || 1 : 1;
}
var _ref = isElement(element) ? getWindow(element) : window, visualViewport = _ref.visualViewport;
var addVisualOffsets = !isLayoutViewport() && isFixedStrategy;
var x = (clientRect.left + (addVisualOffsets && visualViewport ? visualViewport.offsetLeft : 0)) / scaleX;
var y = (clientRect.top + (addVisualOffsets && visualViewport ? visualViewport.offsetTop : 0)) / scaleY;
var width = clientRect.width / scaleX;
var height = clientRect.height / scaleY;
return {
width,
height,
top: y,
right: x + width,
bottom: y + height,
left: x,
x,
y
};
}
// node_modules/@popperjs/core/lib/dom-utils/getLayoutRect.js
function getLayoutRect(element) {
var clientRect = getBoundingClientRect(element);
var width = element.offsetWidth;
var height = element.offsetHeight;
if (Math.abs(clientRect.width - width) <= 1) {
width = clientRect.width;
}
if (Math.abs(clientRect.height - height) <= 1) {
height = clientRect.height;
}
return {
x: element.offsetLeft,
y: element.offsetTop,
width,
height
};
}
// node_modules/@popperjs/core/lib/dom-utils/contains.js
function contains(parent, child) {
var rootNode = child.getRootNode && child.getRootNode();
if (parent.contains(child)) {
return true;
} else if (rootNode && isShadowRoot(rootNode)) {
var next = child;
do {
if (next && parent.isSameNode(next)) {
return true;
}
next = next.parentNode || next.host;
} while (next);
}
return false;
}
// node_modules/@popperjs/core/lib/dom-utils/getComputedStyle.js
function getComputedStyle(element) {
return getWindow(element).getComputedStyle(element);
}
// node_modules/@popperjs/core/lib/dom-utils/isTableElement.js
function isTableElement(element) {
return ["table", "td", "th"].indexOf(getNodeName(element)) >= 0;
}
// node_modules/@popperjs/core/lib/dom-utils/getDocumentElement.js
function getDocumentElement(element) {
return ((isElement(element) ? element.ownerDocument : element.document) || window.document).documentElement;
}
// node_modules/@popperjs/core/lib/dom-utils/getParentNode.js
function getParentNode(element) {
if (getNodeName(element) === "html") {
return element;
}
return element.assignedSlot || element.parentNode || (isShadowRoot(element) ? element.host : null) || getDocumentElement(element);
}
// node_modules/@popperjs/core/lib/dom-utils/getOffsetParent.js
function getTrueOffsetParent(element) {
if (!isHTMLElement(element) || getComputedStyle(element).position === "fixed") {
return null;
}
return element.offsetParent;
}
function getContainingBlock(element) {
var isFirefox = /firefox/i.test(getUAString());
var isIE = /Trident/i.test(getUAString());
if (isIE && isHTMLElement(element)) {
var elementCss = getComputedStyle(element);
if (elementCss.position === "fixed") {
return null;
}
}
var currentNode = getParentNode(element);
if (isShadowRoot(currentNode)) {
currentNode = currentNode.host;
}
while (isHTMLElement(currentNode) && ["html", "body"].indexOf(getNodeName(currentNode)) < 0) {
var css = getComputedStyle(currentNode);
if (css.transform !== "none" || css.perspective !== "none" || css.contain === "paint" || ["transform", "perspective"].indexOf(css.willChange) !== -1 || isFirefox && css.willChange === "filter" || isFirefox && css.filter && css.filter !== "none") {
return currentNode;
} else {
currentNode = currentNode.parentNode;
}
}
return null;
}
function getOffsetParent(element) {
var window2 = getWindow(element);
var offsetParent = getTrueOffsetParent(element);
while (offsetParent && isTableElement(offsetParent) && getComputedStyle(offsetParent).position === "static") {
offsetParent = getTrueOffsetParent(offsetParent);
}
if (offsetParent && (getNodeName(offsetParent) === "html" || getNodeName(offsetParent) === "body" && getComputedStyle(offsetParent).position === "static")) {
return window2;
}
return offsetParent || getContainingBlock(element) || window2;
}
// node_modules/@popperjs/core/lib/utils/getMainAxisFromPlacement.js
function getMainAxisFromPlacement(placement) {
return ["top", "bottom"].indexOf(placement) >= 0 ? "x" : "y";
}
// node_modules/@popperjs/core/lib/utils/within.js
function within(min2, value, max2) {
return max(min2, min(value, max2));
}
function withinMaxClamp(min2, value, max2) {
var v = within(min2, value, max2);
return v > max2 ? max2 : v;
}
// node_modules/@popperjs/core/lib/utils/getFreshSideObject.js
function getFreshSideObject() {
return {
top: 0,
right: 0,
bottom: 0,
left: 0
};
}
// node_modules/@popperjs/core/lib/utils/mergePaddingObject.js
function mergePaddingObject(paddingObject) {
return Object.assign({}, getFreshSideObject(), paddingObject);
}
// node_modules/@popperjs/core/lib/utils/expandToHashMap.js
function expandToHashMap(value, keys) {
return keys.reduce(function(hashMap, key) {
hashMap[key] = value;
return hashMap;
}, {});
}
// node_modules/@popperjs/core/lib/modifiers/arrow.js
var toPaddingObject = function toPaddingObject2(padding, state) {
padding = typeof padding === "function" ? padding(Object.assign({}, state.rects, {
placement: state.placement
})) : padding;
return mergePaddingObject(typeof padding !== "number" ? padding : expandToHashMap(padding, basePlacements));
};
function arrow(_ref) {
var _state$modifiersData$;
var state = _ref.state, name = _ref.name, options = _ref.options;
var arrowElement = state.elements.arrow;
var popperOffsets2 = state.modifiersData.popperOffsets;
var basePlacement = getBasePlacement(state.placement);
var axis = getMainAxisFromPlacement(basePlacement);
var isVertical = [left, right].indexOf(basePlacement) >= 0;
var len = isVertical ? "height" : "width";
if (!arrowElement || !popperOffsets2) {
return;
}
var paddingObject = toPaddingObject(options.padding, state);
var arrowRect = getLayoutRect(arrowElement);
var minProp = axis === "y" ? top : left;
var maxProp = axis === "y" ? bottom : right;
var endDiff = state.rects.reference[len] + state.rects.reference[axis] - popperOffsets2[axis] - state.rects.popper[len];
var startDiff = popperOffsets2[axis] - state.rects.reference[axis];
var arrowOffsetParent = getOffsetParent(arrowElement);
var clientSize = arrowOffsetParent ? axis === "y" ? arrowOffsetParent.clientHeight || 0 : arrowOffsetParent.clientWidth || 0 : 0;
var centerToReference = endDiff / 2 - startDiff / 2;
var min2 = paddingObject[minProp];
var max2 = clientSize - arrowRect[len] - paddingObject[maxProp];
var center = clientSize / 2 - arrowRect[len] / 2 + centerToReference;
var offset2 = within(min2, center, max2);
var axisProp = axis;
state.modifiersData[name] = (_state$modifiersData$ = {}, _state$modifiersData$[axisProp] = offset2, _state$modifiersData$.centerOffset = offset2 - center, _state$modifiersData$);
}
function effect2(_ref2) {
var state = _ref2.state, options = _ref2.options;
var _options$element = options.element, arrowElement = _options$element === void 0 ? "[data-popper-arrow]" : _options$element;
if (arrowElement == null) {
return;
}
if (typeof arrowElement === "string") {
arrowElement = state.elements.popper.querySelector(arrowElement);
if (!arrowElement) {
return;
}
}
if (!contains(state.elements.popper, arrowElement)) {
return;
}
state.elements.arrow = arrowElement;
}
var arrow_default = {
name: "arrow",
enabled: true,
phase: "main",
fn: arrow,
effect: effect2,
requires: ["popperOffsets"],
requiresIfExists: ["preventOverflow"]
};
// node_modules/@popperjs/core/lib/utils/getVariation.js
function getVariation(placement) {
return placement.split("-")[1];
}
// node_modules/@popperjs/core/lib/modifiers/computeStyles.js
var unsetSides = {
top: "auto",
right: "auto",
bottom: "auto",
left: "auto"
};
function roundOffsetsByDPR(_ref, win) {
var x = _ref.x, y = _ref.y;
var dpr = win.devicePixelRatio || 1;
return {
x: round(x * dpr) / dpr || 0,
y: round(y * dpr) / dpr || 0
};
}
function mapToStyles(_ref2) {
var _Object$assign2;
var popper2 = _ref2.popper, popperRect = _ref2.popperRect, placement = _ref2.placement, variation = _ref2.variation, offsets = _ref2.offsets, position = _ref2.position, gpuAcceleration = _ref2.gpuAcceleration, adaptive = _ref2.adaptive, roundOffsets = _ref2.roundOffsets, isFixed = _ref2.isFixed;
var _offsets$x = offsets.x, x = _offsets$x === void 0 ? 0 : _offsets$x, _offsets$y = offsets.y, y = _offsets$y === void 0 ? 0 : _offsets$y;
var _ref3 = typeof roundOffsets === "function" ? roundOffsets({
x,
y
}) : {
x,
y
};
x = _ref3.x;
y = _ref3.y;
var hasX = offsets.hasOwnProperty("x");
var hasY = offsets.hasOwnProperty("y");
var sideX = left;
var sideY = top;
var win = window;
if (adaptive) {
var offsetParent = getOffsetParent(popper2);
var heightProp = "clientHeight";
var widthProp = "clientWidth";
if (offsetParent === getWindow(popper2)) {
offsetParent = getDocumentElement(popper2);
if (getComputedStyle(offsetParent).position !== "static" && position === "absolute") {
heightProp = "scrollHeight";
widthProp = "scrollWidth";
}
}
offsetParent = offsetParent;
if (placement === top || (placement === left || placement === right) && variation === end) {
sideY = bottom;
var offsetY = isFixed && offsetParent === win && win.visualViewport ? win.visualViewport.height : offsetParent[heightProp];
y -= offsetY - popperRect.height;
y *= gpuAcceleration ? 1 : -1;
}
if (placement === left || (placement === top || placement === bottom) && variation === end) {
sideX = right;
var offsetX = isFixed && offsetParent === win && win.visualViewport ? win.visualViewport.width : offsetParent[widthProp];
x -= offsetX - popperRect.width;
x *= gpuAcceleration ? 1 : -1;
}
}
var commonStyles = Object.assign({
position
}, adaptive && unsetSides);
var _ref4 = roundOffsets === true ? roundOffsetsByDPR({
x,
y
}, getWindow(popper2)) : {
x,
y
};
x = _ref4.x;
y = _ref4.y;
if (gpuAcceleration) {
var _Object$assign;
return Object.assign({}, commonStyles, (_Object$assign = {}, _Object$assign[sideY] = hasY ? "0" : "", _Object$assign[sideX] = hasX ? "0" : "", _Object$assign.transform = (win.devicePixelRatio || 1) <= 1 ? "translate(" + x + "px, " + y + "px)" : "translate3d(" + x + "px, " + y + "px, 0)", _Object$assign));
}
return Object.assign({}, commonStyles, (_Object$assign2 = {}, _Object$assign2[sideY] = hasY ? y + "px" : "", _Object$assign2[sideX] = hasX ? x + "px" : "", _Object$assign2.transform = "", _Object$assign2));
}
function computeStyles(_ref5) {
var state = _ref5.state, options = _ref5.options;
var _options$gpuAccelerat = options.gpuAcceleration, gpuAcceleration = _options$gpuAccelerat === void 0 ? true : _options$gpuAccelerat, _options$adaptive = options.adaptive, adaptive = _options$adaptive === void 0 ? true : _options$adaptive, _options$roundOffsets = options.roundOffsets, roundOffsets = _options$roundOffsets === void 0 ? true : _options$roundOffsets;
var commonStyles = {
placement: getBasePlacement(state.placement),
variation: getVariation(state.placement),
popper: state.elements.popper,
popperRect: state.rects.popper,
gpuAcceleration,
isFixed: state.options.strategy === "fixed"
};
if (state.modifiersData.popperOffsets != null) {
state.styles.popper = Object.assign({}, state.styles.popper, mapToStyles(Object.assign({}, commonStyles, {
offsets: state.modifiersData.popperOffsets,
position: state.options.strategy,
adaptive,
roundOffsets
})));
}
if (state.modifiersData.arrow != null) {
state.styles.arrow = Object.assign({}, state.styles.arrow, mapToStyles(Object.assign({}, commonStyles, {
offsets: state.modifiersData.arrow,
position: "absolute",
adaptive: false,
roundOffsets
})));
}
state.attributes.popper = Object.assign({}, state.attributes.popper, {
"data-popper-placement": state.placement
});
}
var computeStyles_default = {
name: "computeStyles",
enabled: true,
phase: "beforeWrite",
fn: computeStyles,
data: {}
};
// node_modules/@popperjs/core/lib/modifiers/eventListeners.js
var passive = {
passive: true
};
function effect3(_ref) {
var state = _ref.state, instance = _ref.instance, options = _ref.options;
var _options$scroll = options.scroll, scroll = _options$scroll === void 0 ? true : _options$scroll, _options$resize = options.resize, resize = _options$resize === void 0 ? true : _options$resize;
var window2 = getWindow(state.elements.popper);
var scrollParents = [].concat(state.scrollParents.reference, state.scrollParents.popper);
if (scroll) {
scrollParents.forEach(function(scrollParent) {
scrollParent.addEventListener("scroll", instance.update, passive);
});
}
if (resize) {
window2.addEventListener("resize", instance.update, passive);
}
return function() {
if (scroll) {
scrollParents.forEach(function(scrollParent) {
scrollParent.removeEventListener("scroll", instance.update, passive);
});
}
if (resize) {
window2.removeEventListener("resize", instance.update, passive);
}
};
}
var eventListeners_default = {
name: "eventListeners",
enabled: true,
phase: "write",
fn: function fn() {
},
effect: effect3,
data: {}
};
// node_modules/@popperjs/core/lib/utils/getOppositePlacement.js
var hash = {
left: "right",
right: "left",
bottom: "top",
top: "bottom"
};
function getOppositePlacement(placement) {
return placement.replace(/left|right|bottom|top/g, function(matched) {
return hash[matched];
});
}
// node_modules/@popperjs/core/lib/utils/getOppositeVariationPlacement.js
var hash2 = {
start: "end",
end: "start"
};
function getOppositeVariationPlacement(placement) {
return placement.replace(/start|end/g, function(matched) {
return hash2[matched];
});
}
// node_modules/@popperjs/core/lib/dom-utils/getWindowScroll.js
function getWindowScroll(node) {
var win = getWindow(node);
var scrollLeft = win.pageXOffset;
var scrollTop = win.pageYOffset;
return {
scrollLeft,
scrollTop
};
}
// node_modules/@popperjs/core/lib/dom-utils/getWindowScrollBarX.js
function getWindowScrollBarX(element) {
return getBoundingClientRect(getDocumentElement(element)).left + getWindowScroll(element).scrollLeft;
}
// node_modules/@popperjs/core/lib/dom-utils/getViewportRect.js
function getViewportRect(element, strategy) {
var win = getWindow(element);
var html = getDocumentElement(element);
var visualViewport = win.visualViewport;
var width = html.clientWidth;
var height = html.clientHeight;
var x = 0;
var y = 0;
if (visualViewport) {
width = visualViewport.width;
height = visualViewport.height;
var layoutViewport = isLayoutViewport();
if (layoutViewport || !layoutViewport && strategy === "fixed") {
x = visualViewport.offsetLeft;
y = visualViewport.offsetTop;
}
}
return {
width,
height,
x: x + getWindowScrollBarX(element),
y
};
}
// node_modules/@popperjs/core/lib/dom-utils/getDocumentRect.js
function getDocumentRect(element) {
var _element$ownerDocumen;
var html = getDocumentElement(element);
var winScroll = getWindowScroll(element);
var body = (_element$ownerDocumen = element.ownerDocument) == null ? void 0 : _element$ownerDocumen.body;
var width = max(html.scrollWidth, html.clientWidth, body ? body.scrollWidth : 0, body ? body.clientWidth : 0);
var height = max(html.scrollHeight, html.clientHeight, body ? body.scrollHeight : 0, body ? body.clientHeight : 0);
var x = -winScroll.scrollLeft + getWindowScrollBarX(element);
var y = -winScroll.scrollTop;
if (getComputedStyle(body || html).direction === "rtl") {
x += max(html.clientWidth, body ? body.clientWidth : 0) - width;
}
return {
width,
height,
x,
y
};
}
// node_modules/@popperjs/core/lib/dom-utils/isScrollParent.js
function isScrollParent(element) {
var _getComputedStyle = getComputedStyle(element), overflow = _getComputedStyle.overflow, overflowX = _getComputedStyle.overflowX, overflowY = _getComputedStyle.overflowY;
return /auto|scroll|overlay|hidden/.test(overflow + overflowY + overflowX);
}
// node_modules/@popperjs/core/lib/dom-utils/getScrollParent.js
function getScrollParent(node) {
if (["html", "body", "#document"].indexOf(getNodeName(node)) >= 0) {
return node.ownerDocument.body;
}
if (isHTMLElement(node) && isScrollParent(node)) {
return node;
}
return getScrollParent(getParentNode(node));
}
// node_modules/@popperjs/core/lib/dom-utils/listScrollParents.js
function listScrollParents(element, list) {
var _element$ownerDocumen;
if (list === void 0) {
list = [];
}
var scrollParent = getScrollParent(element);
var isBody = scrollParent === ((_element$ownerDocumen = element.ownerDocument) == null ? void 0 : _element$ownerDocumen.body);
var win = getWindow(scrollParent);
var target = isBody ? [win].concat(win.visualViewport || [], isScrollParent(scrollParent) ? scrollParent : []) : scrollParent;
var updatedList = list.concat(target);
return isBody ? updatedList : updatedList.concat(listScrollParents(getParentNode(target)));
}
// node_modules/@popperjs/core/lib/utils/rectToClientRect.js
function rectToClientRect(rect) {
return Object.assign({}, rect, {
left: rect.x,
top: rect.y,
right: rect.x + rect.width,
bottom: rect.y + rect.height
});
}
// node_modules/@popperjs/core/lib/dom-utils/getClippingRect.js
function getInnerBoundingClientRect(element, strategy) {
var rect = getBoundingClientRect(element, false, strategy === "fixed");
rect.top = rect.top + element.clientTop;
rect.left = rect.left + element.clientLeft;
rect.bottom = rect.top + element.clientHeight;
rect.right = rect.left + element.clientWidth;
rect.width = element.clientWidth;
rect.height = element.clientHeight;
rect.x = rect.left;
rect.y = rect.top;
return rect;
}
function getClientRectFromMixedType(element, clippingParent, strategy) {
return clippingParent === viewport ? rectToClientRect(getViewportRect(element, strategy)) : isElement(clippingParent) ? getInnerBoundingClientRect(clippingParent, strategy) : rectToClientRect(getDocumentRect(getDocumentElement(element)));
}
function getClippingParents(element) {
var clippingParents2 = listScrollParents(getParentNode(element));
var canEscapeClipping = ["absolute", "fixed"].indexOf(getComputedStyle(element).position) >= 0;
var clipperElement = canEscapeClipping && isHTMLElement(element) ? getOffsetParent(element) : element;
if (!isElement(clipperElement)) {
return [];
}
return clippingParents2.filter(function(clippingParent) {
return isElement(clippingParent) && contains(clippingParent, clipperElement) && getNodeName(clippingParent) !== "body";
});
}
function getClippingRect(element, boundary, rootBoundary, strategy) {
var mainClippingParents = boundary === "clippingParents" ? getClippingParents(element) : [].concat(boundary);
var clippingParents2 = [].concat(mainClippingParents, [rootBoundary]);
var firstClippingParent = clippingParents2[0];
var clippingRect = clippingParents2.reduce(function(accRect, clippingParent) {
var rect = getClientRectFromMixedType(element, clippingParent, strategy);
accRect.top = max(rect.top, accRect.top);
accRect.right = min(rect.right, accRect.right);
accRect.bottom = min(rect.bottom, accRect.bottom);
accRect.left = max(rect.left, accRect.left);
return accRect;
}, getClientRectFromMixedType(element, firstClippingParent, strategy));
clippingRect.width = clippingRect.right - clippingRect.left;
clippingRect.height = clippingRect.bottom - clippingRect.top;
clippingRect.x = clippingRect.left;
clippingRect.y = clippingRect.top;
return clippingRect;
}
// node_modules/@popperjs/core/lib/utils/computeOffsets.js
function computeOffsets(_ref) {
var reference2 = _ref.reference, element = _ref.element, placement = _ref.placement;
var basePlacement = placement ? getBasePlacement(placement) : null;
var variation = placement ? getVariation(placement) : null;
var commonX = reference2.x + reference2.width / 2 - element.width / 2;
var commonY = reference2.y + reference2.height / 2 - element.height / 2;
var offsets;
switch (basePlacement) {
case top:
offsets = {
x: commonX,
y: reference2.y - element.height
};
break;
case bottom:
offsets = {
x: commonX,
y: reference2.y + reference2.height
};
break;
case right:
offsets = {
x: reference2.x + reference2.width,
y: commonY
};
break;
case left:
offsets = {
x: reference2.x - element.width,
y: commonY
};
break;
default:
offsets = {
x: reference2.x,
y: reference2.y
};
}
var mainAxis = basePlacement ? getMainAxisFromPlacement(basePlacement) : null;
if (mainAxis != null) {
var len = mainAxis === "y" ? "height" : "width";
switch (variation) {
case start:
offsets[mainAxis] = offsets[mainAxis] - (reference2[len] / 2 - element[len] / 2);
break;
case end:
offsets[mainAxis] = offsets[mainAxis] + (reference2[len] / 2 - element[len] / 2);
break;
default:
}
}
return offsets;
}
// node_modules/@popperjs/core/lib/utils/detectOverflow.js
function detectOverflow(state, options) {
if (options === void 0) {
options = {};
}
var _options = options, _options$placement = _options.placement, placement = _options$placement === void 0 ? state.placement : _options$placement, _options$strategy = _options.strategy, strategy = _options$strategy === void 0 ? state.strategy : _options$strategy, _options$boundary = _options.boundary, boundary = _options$boundary === void 0 ? clippingParents : _options$boundary, _options$rootBoundary = _options.rootBoundary, rootBoundary = _options$rootBoundary === void 0 ? viewport : _options$rootBoundary, _options$elementConte = _options.elementContext, elementContext = _options$elementConte === void 0 ? popper : _options$elementConte, _options$altBoundary = _options.altBoundary, altBoundary = _options$altBoundary === void 0 ? false : _options$altBoundary, _options$padding = _options.padding, padding = _options$padding === void 0 ? 0 : _options$padding;
var paddingObject = mergePaddingObject(typeof padding !== "number" ? padding : expandToHashMap(padding, basePlacements));
var altContext = elementContext === popper ? reference : popper;
var popperRect = state.rects.popper;
var element = state.elements[altBoundary ? altContext : elementContext];
var clippingClientRect = getClippingRect(isElement(element) ? element : element.contextElement || getDocumentElement(state.elements.popper), boundary, rootBoundary, strategy);
var referenceClientRect = getBoundingClientRect(state.elements.reference);
var popperOffsets2 = computeOffsets({
reference: referenceClientRect,
element: popperRect,
strategy: "absolute",
placement
});
var popperClientRect = rectToClientRect(Object.assign({}, popperRect, popperOffsets2));
var elementClientRect = elementContext === popper ? popperClientRect : referenceClientRect;
var overflowOffsets = {
top: clippingClientRect.top - elementClientRect.top + paddingObject.top,
bottom: elementClientRect.bottom - clippingClientRect.bottom + paddingObject.bottom,
left: clippingClientRect.left - elementClientRect.left + paddingObject.left,
right: elementClientRect.right - clippingClientRect.right + paddingObject.right
};
var offsetData = state.modifiersData.offset;
if (elementContext === popper && offsetData) {
var offset2 = offsetData[placement];
Object.keys(overflowOffsets).forEach(function(key) {
var multiply = [right, bottom].indexOf(key) >= 0 ? 1 : -1;
var axis = [top, bottom].indexOf(key) >= 0 ? "y" : "x";
overflowOffsets[key] += offset2[axis] * multiply;
});
}
return overflowOffsets;
}
// node_modules/@popperjs/core/lib/utils/computeAutoPlacement.js
function computeAutoPlacement(state, options) {
if (options === void 0) {
options = {};
}
var _options = options, placement = _options.placement, boundary = _options.boundary, rootBoundary = _options.rootBoundary, padding = _options.padding, flipVariations = _options.flipVariations, _options$allowedAutoP = _options.allowedAutoPlacements, allowedAutoPlacements = _options$allowedAutoP === void 0 ? placements : _options$allowedAutoP;
var variation = getVariation(placement);
var placements2 = variation ? flipVariations ? variationPlacements : variationPlacements.filter(function(placement2) {
return getVariation(placement2) === variation;
}) : basePlacements;
var allowedPlacements = placements2.filter(function(placement2) {
return allowedAutoPlacements.indexOf(placement2) >= 0;
});
if (allowedPlacements.length === 0) {
allowedPlacements = placements2;
}
var overflows = allowedPlacements.reduce(function(acc, placement2) {
acc[placement2] = detectOverflow(state, {
placement: placement2,
boundary,
rootBoundary,
padding
})[getBasePlacement(placement2)];
return acc;
}, {});
return Object.keys(overflows).sort(function(a, b) {
return overflows[a] - overflows[b];
});
}
// node_modules/@popperjs/core/lib/modifiers/flip.js
function getExpandedFallbackPlacements(placement) {
if (getBasePlacement(placement) === auto) {
return [];
}
var oppositePlacement = getOppositePlacement(placement);
return [getOppositeVariationPlacement(placement), oppositePlacement, getOppositeVariationPlacement(oppositePlacement)];
}
function flip(_ref) {
var state = _ref.state, options = _ref.options, name = _ref.name;
if (state.modifiersData[name]._skip) {
return;
}
var _options$mainAxis = options.mainAxis, checkMainAxis = _options$mainAxis === void 0 ? true : _options$mainAxis, _options$altAxis = options.altAxis, checkAltAxis = _options$altAxis === void 0 ? true : _options$altAxis, specifiedFallbackPlacements = options.fallbackPlacements, padding = options.padding, boundary = options.boundary, rootBoundary = options.rootBoundary, altBoundary = options.altBoundary, _options$flipVariatio = options.flipVariations, flipVariations = _options$flipVariatio === void 0 ? true : _options$flipVariatio, allowedAutoPlacements = options.allowedAutoPlacements;
var preferredPlacement = state.options.placement;
var basePlacement = getBasePlacement(preferredPlacement);
var isBasePlacement = basePlacement === preferredPlacement;
var fallbackPlacements = specifiedFallbackPlacements || (isBasePlacement || !flipVariations ? [getOppositePlacement(preferredPlacement)] : getExpandedFallbackPlacements(preferredPlacement));
var placements2 = [preferredPlacement].concat(fallbackPlacements).reduce(function(acc, placement2) {
return acc.concat(getBasePlacement(placement2) === auto ? computeAutoPlacement(state, {
placement: placement2,
boundary,
rootBoundary,
padding,
flipVariations,
allowedAutoPlacements
}) : placement2);
}, []);
var referenceRect = state.rects.reference;
var popperRect = state.rects.popper;
var checksMap = /* @__PURE__ */ new Map();
var makeFallbackChecks = true;
var firstFittingPlacement = placements2[0];
for (var i = 0; i < placements2.length; i++) {
var placement = placements2[i];
var _basePlacement = getBasePlacement(placement);
var isStartVariation = getVariation(placement) === start;
var isVertical = [top, bottom].indexOf(_basePlacement) >= 0;
var len = isVertical ? "width" : "height";
var overflow = detectOverflow(state, {
placement,
boundary,
rootBoundary,
altBoundary,
padding
});
var mainVariationSide = isVertical ? isStartVariation ? right : left : isStartVariation ? bottom : top;
if (referenceRect[len] > popperRect[len]) {
mainVariationSide = getOppositePlacement(mainVariationSide);
}
var altVariationSide = getOppositePlacement(mainVariationSide);
var checks = [];
if (checkMainAxis) {
checks.push(overflow[_basePlacement] <= 0);
}
if (checkAltAxis) {
checks.push(overflow[mainVariationSide] <= 0, overflow[altVariationSide] <= 0);
}
if (checks.every(function(check) {
return check;
})) {
firstFittingPlacement = placement;
makeFallbackChecks = false;
break;
}
checksMap.set(placement, checks);
}
if (makeFallbackChecks) {
var numberOfChecks = flipVariations ? 3 : 1;
var _loop = function _loop2(_i2) {
var fittingPlacement = placements2.find(function(placement2) {
var checks2 = checksMap.get(placement2);
if (checks2) {
return checks2.slice(0, _i2).every(function(check) {
return check;
});
}
});
if (fittingPlacement) {
firstFittingPlacement = fittingPlacement;
return "break";
}
};
for (var _i = numberOfChecks; _i > 0; _i--) {
var _ret = _loop(_i);
if (_ret === "break")
break;
}
}
if (state.placement !== firstFittingPlacement) {
state.modifiersData[name]._skip = true;
state.placement = firstFittingPlacement;
state.reset = true;
}
}
var flip_default = {
name: "flip",
enabled: true,
phase: "main",
fn: flip,
requiresIfExists: ["offset"],
data: {
_skip: false
}
};
// node_modules/@popperjs/core/lib/modifiers/hide.js
function getSideOffsets(overflow, rect, preventedOffsets) {
if (preventedOffsets === void 0) {
preventedOffsets = {
x: 0,
y: 0
};
}
return {
top: overflow.top - rect.height - preventedOffsets.y,
right: overflow.right - rect.width + preventedOffsets.x,
bottom: overflow.bottom - rect.height + preventedOffsets.y,
left: overflow.left - rect.width - preventedOffsets.x
};
}
function isAnySideFullyClipped(overflow) {
return [top, right, bottom, left].some(function(side) {
return overflow[side] >= 0;
});
}
function hide(_ref) {
var state = _ref.state, name = _ref.name;
var referenceRect = state.rects.reference;
var popperRect = state.rects.popper;
var preventedOffsets = state.modifiersData.preventOverflow;
var referenceOverflow = detectOverflow(state, {
elementContext: "reference"
});
var popperAltOverflow = detectOverflow(state, {
altBoundary: true
});
var referenceClippingOffsets = getSideOffsets(referenceOverflow, referenceRect);
var popperEscapeOffsets = getSideOffsets(popperAltOverflow, popperRect, preventedOffsets);
var isReferenceHidden = isAnySideFullyClipped(referenceClippingOffsets);
var hasPopperEscaped = isAnySideFullyClipped(popperEscapeOffsets);
state.modifiersData[name] = {
referenceClippingOffsets,
popperEscapeOffsets,
isReferenceHidden,
hasPopperEscaped
};
state.attributes.popper = Object.assign({}, state.attributes.popper, {
"data-popper-reference-hidden": isReferenceHidden,
"data-popper-escaped": hasPopperEscaped
});
}
var hide_default = {
name: "hide",
enabled: true,
phase: "main",
requiresIfExists: ["preventOverflow"],
fn: hide
};
// node_modules/@popperjs/core/lib/modifiers/offset.js
function distanceAndSkiddingToXY(placement, rects, offset2) {
var basePlacement = getBasePlacement(placement);
var invertDistance = [left, top].indexOf(basePlacement) >= 0 ? -1 : 1;
var _ref = typeof offset2 === "function" ? offset2(Object.assign({}, rects, {
placement
})) : offset2, skidding = _ref[0], distance = _ref[1];
skidding = skidding || 0;
distance = (distance || 0) * invertDistance;
return [left, right].indexOf(basePlacement) >= 0 ? {
x: distance,
y: skidding
} : {
x: skidding,
y: distance
};
}
function offset(_ref2) {
var state = _ref2.state, options = _ref2.options, name = _ref2.name;
var _options$offset = options.offset, offset2 = _options$offset === void 0 ? [0, 0] : _options$offset;
var data = placements.reduce(function(acc, placement) {
acc[placement] = distanceAndSkiddingToXY(placement, state.rects, offset2);
return acc;
}, {});
var _data$state$placement = data[state.placement], x = _data$state$placement.x, y = _data$state$placement.y;
if (state.modifiersData.popperOffsets != null) {
state.modifiersData.popperOffsets.x += x;
state.modifiersData.popperOffsets.y += y;
}
state.modifiersData[name] = data;
}
var offset_default = {
name: "offset",
enabled: true,
phase: "main",
requires: ["popperOffsets"],
fn: offset
};
// node_modules/@popperjs/core/lib/modifiers/popperOffsets.js
function popperOffsets(_ref) {
var state = _ref.state, name = _ref.name;
state.modifiersData[name] = computeOffsets({
reference: state.rects.reference,
element: state.rects.popper,
strategy: "absolute",
placement: state.placement
});
}
var popperOffsets_default = {
name: "popperOffsets",
enabled: true,
phase: "read",
fn: popperOffsets,
data: {}
};
// node_modules/@popperjs/core/lib/utils/getAltAxis.js
function getAltAxis(axis) {
return axis === "x" ? "y" : "x";
}
// node_modules/@popperjs/core/lib/modifiers/preventOverflow.js
function preventOverflow(_ref) {
var state = _ref.state, options = _ref.options, name = _ref.name;
var _options$mainAxis = options.mainAxis, checkMainAxis = _options$mainAxis === void 0 ? true : _options$mainAxis, _options$altAxis = options.altAxis, checkAltAxis = _options$altAxis === void 0 ? false : _options$altAxis, boundary = options.boundary, rootBoundary = options.rootBoundary, altBoundary = options.altBoundary, padding = options.padding, _options$tether = options.tether, tether = _options$tether === void 0 ? true : _options$tether, _options$tetherOffset = options.tetherOffset, tetherOffset = _options$tetherOffset === void 0 ? 0 : _options$tetherOffset;
var overflow = detectOverflow(state, {
boundary,
rootBoundary,
padding,
altBoundary
});
var basePlacement = getBasePlacement(state.placement);
var variation = getVariation(state.placement);
var isBasePlacement = !variation;
var mainAxis = getMainAxisFromPlacement(basePlacement);
var altAxis = getAltAxis(mainAxis);
var popperOffsets2 = state.modifiersData.popperOffsets;
var referenceRect = state.rects.reference;
var popperRect = state.rects.popper;
var tetherOffsetValue = typeof tetherOffset === "function" ? tetherOffset(Object.assign({}, state.rects, {
placement: state.placement
})) : tetherOffset;
var normalizedTetherOffsetValue = typeof tetherOffsetValue === "number" ? {
mainAxis: tetherOffsetValue,
altAxis: tetherOffsetValue
} : Object.assign({
mainAxis: 0,
altAxis: 0
}, tetherOffsetValue);
var offsetModifierState = state.modifiersData.offset ? state.modifiersData.offset[state.placement] : null;
var data = {
x: 0,
y: 0
};
if (!popperOffsets2) {
return;
}
if (checkMainAxis) {
var _offsetModifierState$;
var mainSide = mainAxis === "y" ? top : left;
var altSide = mainAxis === "y" ? bottom : right;
var len = mainAxis === "y" ? "height" : "width";
var offset2 = popperOffsets2[mainAxis];
var min2 = offset2 + overflow[mainSide];
var max2 = offset2 - overflow[altSide];
var additive = tether ? -popperRect[len] / 2 : 0;
var minLen = variation === start ? referenceRect[len] : popperRect[len];
var maxLen = variation === start ? -popperRect[len] : -referenceRect[len];
var arrowElement = state.elements.arrow;
var arrowRect = tether && arrowElement ? getLayoutRect(arrowElement) : {
width: 0,
height: 0
};
var arrowPaddingObject = state.modifiersData["arrow#persistent"] ? state.modifiersData["arrow#persistent"].padding : getFreshSideObject();
var arrowPaddingMin = arrowPaddingObject[mainSide];
var arrowPaddingMax = arrowPaddingObject[altSide];
var arrowLen = within(0, referenceRect[len], arrowRect[len]);
var minOffset = isBasePlacement ? referenceRect[len] / 2 - additive - arrowLen - arrowPaddingMin - normalizedTetherOffsetValue.mainAxis : minLen - arrowLen - arrowPaddingMin - normalizedTetherOffsetValue.mainAxis;
var maxOffset = isBasePlacement ? -referenceRect[len] / 2 + additive + arrowLen + arrowPaddingMax + normalizedTetherOffsetValue.mainAxis : maxLen + arrowLen + arrowPaddingMax + normalizedTetherOffsetValue.mainAxis;
var arrowOffsetParent = state.elements.arrow && getOffsetParent(state.elements.arrow);
var clientOffset = arrowOffsetParent ? mainAxis === "y" ? arrowOffsetParent.clientTop || 0 : arrowOffsetParent.clientLeft || 0 : 0;
var offsetModifierValue = (_offsetModifierState$ = offsetModifierState == null ? void 0 : offsetModifierState[mainAxis]) != null ? _offsetModifierState$ : 0;
var tetherMin = offset2 + minOffset - offsetModifierValue - clientOffset;
var tetherMax = offset2 + maxOffset - offsetModifierValue;
var preventedOffset = within(tether ? min(min2, tetherMin) : min2, offset2, tether ? max(max2, tetherMax) : max2);
popperOffsets2[mainAxis] = preventedOffset;
data[mainAxis] = preventedOffset - offset2;
}
if (checkAltAxis) {
var _offsetModifierState$2;
var _mainSide = mainAxis === "x" ? top : left;
var _altSide = mainAxis === "x" ? bottom : right;
var _offset = popperOffsets2[altAxis];
var _len = altAxis === "y" ? "height" : "width";
var _min = _offset + overflow[_mainSide];
var _max = _offset - overflow[_altSide];
var isOriginSide = [top, left].indexOf(basePlacement) !== -1;
var _offsetModifierValue = (_offsetModifierState$2 = offsetModifierState == null ? void 0 : offsetModifierState[altAxis]) != null ? _offsetModifierState$2 : 0;
var _tetherMin = isOriginSide ? _min : _offset - referenceRect[_len] - popperRect[_len] - _offsetModifierValue + normalizedTetherOffsetValue.altAxis;
var _tetherMax = isOriginSide ? _offset + referenceRect[_len] + popperRect[_len] - _offsetModifierValue - normalizedTetherOffsetValue.altAxis : _max;
var _preventedOffset = tether && isOriginSide ? withinMaxClamp(_tetherMin, _offset, _tetherMax) : within(tether ? _tetherMin : _min, _offset, tether ? _tetherMax : _max);
popperOffsets2[altAxis] = _preventedOffset;
data[altAxis] = _preventedOffset - _offset;
}
state.modifiersData[name] = data;
}
var preventOverflow_default = {
name: "preventOverflow",
enabled: true,
phase: "main",
fn: preventOverflow,
requiresIfExists: ["offset"]
};
// node_modules/@popperjs/core/lib/dom-utils/getHTMLElementScroll.js
function getHTMLElementScroll(element) {
return {
scrollLeft: element.scrollLeft,
scrollTop: element.scrollTop
};
}
// node_modules/@popperjs/core/lib/dom-utils/getNodeScroll.js
function getNodeScroll(node) {
if (node === getWindow(node) || !isHTMLElement(node)) {
return getWindowScroll(node);
} else {
return getHTMLElementScroll(node);
}
}
// node_modules/@popperjs/core/lib/dom-utils/getCompositeRect.js
function isElementScaled(element) {
var rect = element.getBoundingClientRect();
var scaleX = round(rect.width) / element.offsetWidth || 1;
var scaleY = round(rect.height) / element.offsetHeight || 1;
return scaleX !== 1 || scaleY !== 1;
}
function getCompositeRect(elementOrVirtualElement, offsetParent, isFixed) {
if (isFixed === void 0) {
isFixed = false;
}
var isOffsetParentAnElement = isHTMLElement(offsetParent);
var offsetParentIsScaled = isHTMLElement(offsetParent) && isElementScaled(offsetParent);
var documentElement = getDocumentElement(offsetParent);
var rect = getBoundingClientRect(elementOrVirtualElement, offsetParentIsScaled, isFixed);
var scroll = {
scrollLeft: 0,
scrollTop: 0
};
var offsets = {
x: 0,
y: 0
};
if (isOffsetParentAnElement || !isOffsetParentAnElement && !isFixed) {
if (getNodeName(offsetParent) !== "body" || isScrollParent(documentElement)) {
scroll = getNodeScroll(offsetParent);
}
if (isHTMLElement(offsetParent)) {
offsets = getBoundingClientRect(offsetParent, true);
offsets.x += offsetParent.clientLeft;
offsets.y += offsetParent.clientTop;
} else if (documentElement) {
offsets.x = getWindowScrollBarX(documentElement);
}
}
return {
x: rect.left + scroll.scrollLeft - offsets.x,
y: rect.top + scroll.scrollTop - offsets.y,
width: rect.width,
height: rect.height
};
}
// node_modules/@popperjs/core/lib/utils/orderModifiers.js
function order(modifiers) {
var map = /* @__PURE__ */ new Map();
var visited = /* @__PURE__ */ new Set();
var result = [];
modifiers.forEach(function(modifier) {
map.set(modifier.name, modifier);
});
function sort(modifier) {
visited.add(modifier.name);
var requires = [].concat(modifier.requires || [], modifier.requiresIfExists || []);
requires.forEach(function(dep) {
if (!visited.has(dep)) {
var depModifier = map.get(dep);
if (depModifier) {
sort(depModifier);
}
}
});
result.push(modifier);
}
modifiers.forEach(function(modifier) {
if (!visited.has(modifier.name)) {
sort(modifier);
}
});
return result;
}
function orderModifiers(modifiers) {
var orderedModifiers = order(modifiers);
return modifierPhases.reduce(function(acc, phase) {
return acc.concat(orderedModifiers.filter(function(modifier) {
return modifier.phase === phase;
}));
}, []);
}
// node_modules/@popperjs/core/lib/utils/debounce.js
function debounce(fn2) {
var pending;
return function() {
if (!pending) {
pending = new Promise(function(resolve) {
Promise.resolve().then(function() {
pending = void 0;
resolve(fn2());
});
});
}
return pending;
};
}
// node_modules/@popperjs/core/lib/utils/mergeByName.js
function mergeByName(modifiers) {
var merged = modifiers.reduce(function(merged2, current) {
var existing = merged2[current.name];
merged2[current.name] = existing ? Object.assign({}, existing, current, {
options: Object.assign({}, existing.options, current.options),
data: Object.assign({}, existing.data, current.data)
}) : current;
return merged2;
}, {});
return Object.keys(merged).map(function(key) {
return merged[key];
});
}
// node_modules/@popperjs/core/lib/createPopper.js
var DEFAULT_OPTIONS = {
placement: "bottom",
modifiers: [],
strategy: "absolute"
};
function areValidElements() {
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
return !args.some(function(element) {
return !(element && typeof element.getBoundingClientRect === "function");
});
}
function popperGenerator(generatorOptions) {
if (generatorOptions === void 0) {
generatorOptions = {};
}
var _generatorOptions = generatorOptions, _generatorOptions$def = _generatorOptions.defaultModifiers, defaultModifiers2 = _generatorOptions$def === void 0 ? [] : _generatorOptions$def, _generatorOptions$def2 = _generatorOptions.defaultOptions, defaultOptions = _generatorOptions$def2 === void 0 ? DEFAULT_OPTIONS : _generatorOptions$def2;
return function createPopper2(reference2, popper2, options) {
if (options === void 0) {
options = defaultOptions;
}
var state = {
placement: "bottom",
orderedModifiers: [],
options: Object.assign({}, DEFAULT_OPTIONS, defaultOptions),
modifiersData: {},
elements: {
reference: reference2,
popper: popper2
},
attributes: {},
styles: {}
};
var effectCleanupFns = [];
var isDestroyed = false;
var instance = {
state,
setOptions: function setOptions(setOptionsAction) {
var options2 = typeof setOptionsAction === "function" ? setOptionsAction(state.options) : setOptionsAction;
cleanupModifierEffects();
state.options = Object.assign({}, defaultOptions, state.options, options2);
state.scrollParents = {
reference: isElement(reference2) ? listScrollParents(reference2) : reference2.contextElement ? listScrollParents(reference2.contextElement) : [],
popper: listScrollParents(popper2)
};
var orderedModifiers = orderModifiers(mergeByName([].concat(defaultModifiers2, state.options.modifiers)));
state.orderedModifiers = orderedModifiers.filter(function(m) {
return m.enabled;
});
runModifierEffects();
return instance.update();
},
forceUpdate: function forceUpdate() {
if (isDestroyed) {
return;
}
var _state$elements = state.elements, reference3 = _state$elements.reference, popper3 = _state$elements.popper;
if (!areValidElements(reference3, popper3)) {
return;
}
state.rects = {
reference: getCompositeRect(reference3, getOffsetParent(popper3), state.options.strategy === "fixed"),
popper: getLayoutRect(popper3)
};
state.reset = false;
state.placement = state.options.placement;
state.orderedModifiers.forEach(function(modifier) {
return state.modifiersData[modifier.name] = Object.assign({}, modifier.data);
});
for (var index = 0; index < state.orderedModifiers.length; index++) {
if (state.reset === true) {
state.reset = false;
index = -1;
continue;
}
var _state$orderedModifie = state.orderedModifiers[index], fn2 = _state$orderedModifie.fn, _state$orderedModifie2 = _state$orderedModifie.options, _options = _state$orderedModifie2 === void 0 ? {} : _state$orderedModifie2, name = _state$orderedModifie.name;
if (typeof fn2 === "function") {
state = fn2({
state,
options: _options,
name,
instance
}) || state;
}
}
},
update: debounce(function() {
return new Promise(function(resolve) {
instance.forceUpdate();
resolve(state);
});
}),
destroy: function destroy() {
cleanupModifierEffects();
isDestroyed = true;
}
};
if (!areValidElements(reference2, popper2)) {
return instance;
}
instance.setOptions(options).then(function(state2) {
if (!isDestroyed && options.onFirstUpdate) {
options.onFirstUpdate(state2);
}
});
function runModifierEffects() {
state.orderedModifiers.forEach(function(_ref) {
var name = _ref.name, _ref$options = _ref.options, options2 = _ref$options === void 0 ? {} : _ref$options, effect4 = _ref.effect;
if (typeof effect4 === "function") {
var cleanupFn = effect4({
state,
name,
instance,
options: options2
});
var noopFn = function noopFn2() {
};
effectCleanupFns.push(cleanupFn || noopFn);
}
});
}
function cleanupModifierEffects() {
effectCleanupFns.forEach(function(fn2) {
return fn2();
});
effectCleanupFns = [];
}
return instance;
};
}
// node_modules/@popperjs/core/lib/popper.js
var defaultModifiers = [eventListeners_default, popperOffsets_default, computeStyles_default, applyStyles_default, offset_default, flip_default, preventOverflow_default, arrow_default, hide_default];
var createPopper = /* @__PURE__ */ popperGenerator({
defaultModifiers
});
// src/suggesters/Suggest.ts
var wrapAround = (value, size) => {
return (value % size + size) % size;
};
var Suggest = class {
constructor(owner, containerEl, scope) {
this.owner = owner;
this.containerEl = containerEl;
containerEl.on("click", ".suggestion-item", this.onSuggestionClick.bind(this));
containerEl.on("mousemove", ".suggestion-item", this.onSuggestionMouseover.bind(this));
scope.register([], "ArrowUp", (event) => {
if (!event.isComposing) {
this.setSelectedItem(this.selectedItem - 1, true);
return false;
}
});
scope.register([], "ArrowDown", (event) => {
if (!event.isComposing) {
this.setSelectedItem(this.selectedItem + 1, true);
return false;
}
});
scope.register([], "Enter", (event) => {
if (!event.isComposing) {
this.useSelectedItem(event);
return false;
}
});
}
onSuggestionClick(event, el) {
event.preventDefault();
const item = this.suggestions.indexOf(el);
this.setSelectedItem(item, false);
this.useSelectedItem(event);
}
onSuggestionMouseover(_event, el) {
const item = this.suggestions.indexOf(el);
this.setSelectedItem(item, false);
}
setSuggestions(values) {
this.containerEl.empty();
const suggestionEls = [];
values.forEach((value) => {
const suggestionEl = this.containerEl.createDiv("suggestion-item");
this.owner.renderSuggestion(value, suggestionEl);
suggestionEls.push(suggestionEl);
});
this.values = values;
this.suggestions = suggestionEls;
this.setSelectedItem(0, false);
}
useSelectedItem(event) {
const currentValue = this.values[this.selectedItem];
if (currentValue) {
this.owner.selectSuggestion(currentValue, event);
}
}
setSelectedItem(selectedIndex, scrollIntoView) {
const normalizedIndex = wrapAround(selectedIndex, this.suggestions.length);
const prevSelectedSuggestion = this.suggestions[this.selectedItem];
const selectedSuggestion = this.suggestions[normalizedIndex];
prevSelectedSuggestion == null ? void 0 : prevSelectedSuggestion.removeClass("is-selected");
selectedSuggestion == null ? void 0 : selectedSuggestion.addClass("is-selected");
this.selectedItem = normalizedIndex;
if (scrollIntoView) {
selectedSuggestion.scrollIntoView(false);
}
}
};
var TextInputSuggest = class {
constructor(inputEl, plugin) {
this.inputEl = inputEl;
this.plugin = plugin;
this.scope = new import_obsidian5.Scope();
this.suggestEl = createDiv("suggestion-container");
const suggestion = this.suggestEl.createDiv("suggestion");
this.suggest = new Suggest(this, suggestion, this.scope);
this.scope.register([], "Escape", this.close.bind(this));
this.inputEl.addEventListener("input", this.onInputChanged.bind(this));
this.inputEl.addEventListener("focus", this.onInputChanged.bind(this));
this.inputEl.addEventListener("blur", this.close.bind(this));
this.suggestEl.on("mousedown", ".suggestion-container", (event) => {
event.preventDefault();
});
}
onInputChanged() {
const inputStr = this.inputEl.value;
const suggestions = this.getSuggestions(inputStr);
if (!suggestions) {
this.close();
return;
}
if (suggestions.length > 0) {
this.suggest.setSuggestions(suggestions);
this.open(app.dom.appContainerEl, this.inputEl);
} else {
this.close();
}
}
open(container, inputEl) {
this.plugin.app.keymap.pushScope(this.scope);
container.appendChild(this.suggestEl);
this.popper = createPopper(inputEl, this.suggestEl, {
placement: "bottom-start",
modifiers: [
{
name: "sameWidth",
enabled: true,
fn: ({ state, instance }) => {
const targetWidth = `${state.rects.reference.width}px`;
if (state.styles.popper.width === targetWidth) {
return;
}
state.styles.popper.width = targetWidth;
instance.update();
},
phase: "beforeWrite",
requires: ["computeStyles"]
}
]
});
}
close() {
this.plugin.app.keymap.popScope(this.scope);
this.suggest.setSuggestions([]);
if (this.popper)
this.popper.destroy();
this.suggestEl.detach();
}
};
// src/suggesters/FolderSuggester.ts
var FolderSuggest = class extends TextInputSuggest {
constructor(inputEl, plugin, whitelistSuggester, folder) {
super(inputEl, plugin);
this.inputEl = inputEl;
this.whitelistSuggester = whitelistSuggester;
this.folder = folder;
}
get_error_msg(mode) {
switch (mode) {
case 0 /* TemplateFiles */:
return "Templates folder doesn't exist";
case 1 /* ScriptFiles */:
return "User Scripts folder doesn't exist";
}
}
getSuggestions(input_str) {
const folders = [];
const lower_input_str = input_str.toLowerCase();
let files = [];
if (this.folder) {
files = this.folder.children;
} else {
const MAX_FILE_SUGGESTIONS = 100;
files = this.plugin.app.vault.getAllLoadedFiles().slice(0, MAX_FILE_SUGGESTIONS);
}
files.forEach((folder) => {
if (folder instanceof import_obsidian6.TFolder && folder.path.toLowerCase().contains(lower_input_str) && (!this.plugin.settings.excludeFolders.find((f) => f.path === folder.path) || this.whitelistSuggester)) {
folders.push(folder);
}
});
return folders;
}
renderSuggestion(folder, el) {
el.setText(folder.path);
}
selectSuggestion(folder) {
this.inputEl.value = folder.path;
this.inputEl.trigger("input");
this.close();
}
};
// src/ExcludeFolders/modals/ExcludeFolderSettings.ts
var import_obsidian8 = require("obsidian");
// src/functions/styleFunctions.ts
var import_obsidian7 = require("obsidian");
// src/ExcludeFolders/ExcludeFolder.ts
var ExcludedFolder = class {
constructor(path, position, id, plugin) {
this.type = "folder";
this.id = id || crypto.randomUUID();
this.path = path;
this.subFolders = plugin.settings.excludeFolderDefaultSettings.subFolders;
this.disableSync = plugin.settings.excludeFolderDefaultSettings.disableSync;
this.disableAutoCreate = plugin.settings.excludeFolderDefaultSettings.disableAutoCreate;
this.disableFolderNote = plugin.settings.excludeFolderDefaultSettings.disableFolderNote;
this.enableCollapsing = plugin.settings.excludeFolderDefaultSettings.enableCollapsing;
this.position = position;
this.excludeFromFolderOverview = plugin.settings.excludeFolderDefaultSettings.excludeFromFolderOverview;
this.string = "";
this.hideInSettings = false;
this.showFolderNote = plugin.settings.excludeFolderDefaultSettings.showFolderNote;
}
};
// src/functions/styleFunctions.ts
function refreshAllFolderStyles(forceReload = false, plugin) {
if (plugin.activeFileExplorer === getFileExplorer(plugin) && !forceReload) {
return;
}
plugin.activeFileExplorer = getFileExplorer(plugin);
plugin.app.vault.getAllLoadedFiles().forEach(async (file) => {
if (file instanceof import_obsidian7.TFolder) {
await updateCSSClassesForFolder(file.path, plugin);
}
});
}
async function updateCSSClassesForFolder(folderPath, plugin) {
const folder = plugin.app.vault.getAbstractFileByPath(folderPath);
if (!folder || !(folder instanceof import_obsidian7.TFolder)) {
return;
}
const folderNote = getFolderNote(plugin, folder.path);
const detachedFolderNote = getDetachedFolder(plugin, folder.path);
if (folder.children.length === 0) {
addCSSClassToFileExplorerEl(folder.path, "fn-empty-folder", false, plugin);
}
if (!folderNote || detachedFolderNote) {
removeCSSClassFromFileExplorerEL(folder == null ? void 0 : folder.path, "has-folder-note", false, plugin);
removeCSSClassFromFileExplorerEL(folder == null ? void 0 : folder.path, "only-has-folder-note", true, plugin);
return;
}
const excludedFolder = getExcludedFolder(plugin, folder.path, true);
if (excludedFolder == null ? void 0 : excludedFolder.disableFolderNote) {
removeCSSClassFromFileExplorerEL(folderNote.path, "is-folder-note", false, plugin);
removeCSSClassFromFileExplorerEL(folder.path, "has-folder-note", false, plugin);
removeCSSClassFromFileExplorerEL(folder == null ? void 0 : folder.path, "only-has-folder-note", true, plugin);
} else {
markFolderWithFolderNoteClasses(folder, plugin);
if (excludedFolder == null ? void 0 : excludedFolder.showFolderNote) {
addCSSClassToFileExplorerEl(folder.path, "show-folder-note-in-explorer", true, plugin);
unmarkFileAsFolderNote(folderNote, plugin);
return;
}
if (plugin.isEmptyFolderNoteFolder(folder) && getFolderNote(plugin, folder.path)) {
addCSSClassToFileExplorerEl(folder.path, "only-has-folder-note", true, plugin);
} else {
removeCSSClassFromFileExplorerEL(folder.path, "only-has-folder-note", true, plugin);
}
}
markFolderAndNoteWithClasses(folderNote, folder, plugin);
}
function markFolderAndNoteWithClasses(file, folder, plugin) {
markFileAsFolderNote(file, plugin);
markFolderWithFolderNoteClasses(folder, plugin);
}
function markFolderWithFolderNoteClasses(folder, plugin) {
addCSSClassToFileExplorerEl(folder.path, "has-folder-note", false, plugin);
if (plugin.isEmptyFolderNoteFolder(folder) && getFolderNote(plugin, folder.path)) {
addCSSClassToFileExplorerEl(folder.path, "only-has-folder-note", true, plugin);
} else {
removeCSSClassFromFileExplorerEL(folder.path, "only-has-folder-note", true, plugin);
}
}
function markFileAsFolderNote(file, plugin) {
addCSSClassToFileExplorerEl(file.path, "is-folder-note", false, plugin);
}
function unmarkFileAsFolderNote(file, plugin) {
removeCSSClassFromFileExplorerEL(file.path, "is-folder-note", false, plugin);
}
function unmarkFolderAsFolderNote(folder, plugin) {
removeCSSClassFromFileExplorerEL(folder.path, "has-folder-note", false, plugin);
removeCSSClassFromFileExplorerEL(folder.path, "only-has-folder-note", true, plugin);
}
async function addCSSClassToFileExplorerEl(path, cssClass, parent = false, plugin, waitForCreate = false, count = 0) {
const fileExplorerItem = getFileExplorerElement(path, plugin);
const MAX_RETRIES = 5;
const RETRY_DELAY = 500;
if (!fileExplorerItem) {
if (waitForCreate && count < MAX_RETRIES) {
await new Promise((r) => setTimeout(r, RETRY_DELAY));
addCSSClassToFileExplorerEl(path, cssClass, parent, plugin, waitForCreate, count + 1);
return;
}
return;
}
if (parent) {
const parentElement = fileExplorerItem == null ? void 0 : fileExplorerItem.parentElement;
if (parentElement) {
parentElement.addClass(cssClass);
}
} else {
fileExplorerItem.addClass(cssClass);
document.querySelectorAll(`[data-path='${CSS.escape(path)}']`).forEach((item) => {
item.addClass(cssClass);
});
}
}
function removeCSSClassFromFileExplorerEL(path, cssClass, parent, plugin) {
if (!path)
return;
const fileExplorerItem = getFileExplorerElement(path, plugin);
document.querySelectorAll(`[data-path='${CSS.escape(path)}']`).forEach((item) => {
item.removeClass(cssClass);
});
if (!fileExplorerItem) {
return;
}
if (parent) {
const parentElement = fileExplorerItem == null ? void 0 : fileExplorerItem.parentElement;
if (parentElement) {
parentElement.removeClass(cssClass);
}
return;
}
fileExplorerItem.removeClass(cssClass);
}
function getFileExplorerElement(path, plugin) {
var _a, _b, _c, _d;
const fileExplorer = getFileExplorer(plugin);
if (!((_a = fileExplorer == null ? void 0 : fileExplorer.view) == null ? void 0 : _a.fileItems)) {
return null;
}
const fileExplorerItem = (_b = fileExplorer.view.fileItems) == null ? void 0 : _b[path];
return (_d = (_c = fileExplorerItem == null ? void 0 : fileExplorerItem.selfEl) != null ? _c : fileExplorerItem == null ? void 0 : fileExplorerItem.titleEl) != null ? _d : null;
}
function showFolderNoteInFileExplorer(path, plugin) {
const excludedFolder = new ExcludedFolder(path, plugin.settings.excludeFolders.length, void 0, plugin);
excludedFolder.subFolders = false;
excludedFolder.disableSync = false;
excludedFolder.disableAutoCreate = false;
excludedFolder.disableFolderNote = false;
excludedFolder.enableCollapsing = false;
excludedFolder.excludeFromFolderOverview = false;
excludedFolder.hideInSettings = true;
excludedFolder.showFolderNote = true;
addExcludedFolder(plugin, excludedFolder, false);
addCSSClassToFileExplorerEl(path, "show-folder-note-in-explorer", true, plugin);
updateCSSClassesForFolder(path, plugin);
}
function hideFolderNoteInFileExplorer(folderPath, plugin) {
plugin.settings.excludeFolders = plugin.settings.excludeFolders.filter((folder) => folder.path !== folderPath && folder.showFolderNote);
plugin.saveSettings(false);
removeCSSClassFromFileExplorerEL(folderPath, "show-folder-note-in-explorer", true, plugin);
updateCSSClassesForFolder(folderPath, plugin);
}
function setActiveFolder(folderPath, plugin) {
const fileExplorerItem = getFileExplorerElement(folderPath, plugin);
if (fileExplorerItem) {
fileExplorerItem.addClass("fn-is-active");
plugin.activeFolderDom = fileExplorerItem;
}
}
function removeActiveFolder(plugin) {
var _a;
if (plugin.activeFolderDom) {
plugin.activeFolderDom.removeClass("fn-is-active");
(_a = plugin.activeFolderDom) == null ? void 0 : _a.removeClass("has-focus");
plugin.activeFolderDom = null;
}
}
// src/ExcludeFolders/modals/ExcludeFolderSettings.ts
var ExcludedFolderSettings = class extends import_obsidian8.Modal {
constructor(app2, plugin, excludedFolder) {
super(app2);
this.plugin = plugin;
this.app = app2;
this.excludedFolder = excludedFolder;
}
onOpen() {
this.display();
}
display() {
const { contentEl } = this;
contentEl.empty();
contentEl.createEl("h2", { text: "Excluded folder settings" });
new import_obsidian8.Setting(contentEl).setName("Include subfolders").setDesc("Choose if the subfolders of the folder should also be excluded").addToggle((toggle) => toggle.setValue(this.excludedFolder.subFolders).onChange(async (value) => {
this.excludedFolder.subFolders = value;
await this.plugin.saveSettings(true);
}));
new import_obsidian8.Setting(contentEl).setName("Disable folder name sync").setDesc("Choose if the folder note should be renamed when the folder name is changed").addToggle((toggle) => toggle.setValue(this.excludedFolder.disableSync).onChange(async (value) => {
this.excludedFolder.disableSync = value;
await this.plugin.saveSettings();
}));
new import_obsidian8.Setting(contentEl).setName("Don't show folder in folder overview").setDesc("Choose if the folder should be shown in the folder overview").addToggle((toggle) => toggle.setValue(this.excludedFolder.excludeFromFolderOverview).onChange(async (value) => {
this.excludedFolder.excludeFromFolderOverview = value;
await this.plugin.saveSettings();
}));
new import_obsidian8.Setting(contentEl).setName("Show folder note in the file explorer").setDesc("Choose if the folder note should be shown in the file explorer").addToggle((toggle) => toggle.setValue(this.excludedFolder.showFolderNote).onChange(async (value) => {
this.excludedFolder.showFolderNote = value;
updateCSSClassesForFolder(this.excludedFolder.path, this.plugin);
await this.plugin.saveSettings();
this.display();
}));
new import_obsidian8.Setting(contentEl).setName("Disable auto creation of folder notes in this folder").setDesc("Choose if a folder note should be created when a new folder is created").addToggle((toggle) => toggle.setValue(this.excludedFolder.disableAutoCreate).onChange(async (value) => {
this.excludedFolder.disableAutoCreate = value;
await this.plugin.saveSettings();
}));
new import_obsidian8.Setting(contentEl).setName("Disable open folder note").setDesc("Choose if the folder note should be opened when the folder is opened").addToggle((toggle) => toggle.setValue(this.excludedFolder.disableFolderNote).onChange(async (value) => {
this.excludedFolder.disableFolderNote = value;
await this.plugin.saveSettings(true);
this.display();
}));
if (!this.excludedFolder.disableFolderNote) {
new import_obsidian8.Setting(contentEl).setName("Collapse folder when opening folder note").setDesc("Choose if the folder should be collapsed when the folder note is opened").addToggle((toggle) => toggle.setValue(this.excludedFolder.enableCollapsing).onChange(async (value) => {
this.excludedFolder.enableCollapsing = value;
await this.plugin.saveSettings();
}));
}
}
onClose() {
const { contentEl } = this;
contentEl.empty();
}
};
// src/ExcludeFolders/functions/patternFunctions.ts
var import_obsidian10 = require("obsidian");
// src/ExcludeFolders/modals/PatternSettings.ts
var import_obsidian9 = require("obsidian");
var PatternSettings = class extends import_obsidian9.Modal {
constructor(app2, plugin, pattern) {
super(app2);
this.plugin = plugin;
this.app = app2;
this.pattern = pattern;
}
onOpen() {
this.display();
}
display() {
const { contentEl } = this;
contentEl.empty();
contentEl.createEl("h2", { text: "Pattern settings" });
new import_obsidian9.Setting(contentEl).setName("Disable folder name sync").setDesc("Choose if the folder name should be renamed when the file name has been changed").addToggle((toggle) => toggle.setValue(this.pattern.disableSync).onChange(async (value) => {
this.pattern.disableSync = value;
await this.plugin.saveSettings();
}));
new import_obsidian9.Setting(contentEl).setName("Disable auto creation of folder notes in this folder").setDesc("Choose if a folder note should be created when a new folder is created that matches this pattern").addToggle((toggle) => toggle.setValue(this.pattern.disableAutoCreate).onChange(async (value) => {
this.pattern.disableAutoCreate = value;
await this.plugin.saveSettings();
}));
new import_obsidian9.Setting(contentEl).setName("Don't show folder in folder overview").setDesc("Choose if the folder should be shown in the folder overview").addToggle((toggle) => toggle.setValue(this.pattern.excludeFromFolderOverview).onChange(async (value) => {
this.pattern.excludeFromFolderOverview = value;
await this.plugin.saveSettings();
}));
new import_obsidian9.Setting(contentEl).setName("Show folder note in the file explorer").setDesc("Choose if the folder note should be shown in the file explorer").addToggle((toggle) => toggle.setValue(this.pattern.showFolderNote).onChange(async (value) => {
this.pattern.showFolderNote = value;
await this.plugin.saveSettings();
refreshAllFolderStyles(true, this.plugin);
this.display();
}));
new import_obsidian9.Setting(contentEl).setName("Disable open folder note").setDesc("Choose if the folder note should be opened when the folder is opened").addToggle((toggle) => toggle.setValue(this.pattern.disableFolderNote).onChange(async (value) => {
this.pattern.disableFolderNote = value;
await this.plugin.saveSettings(true);
this.display();
}));
if (!this.pattern.disableFolderNote) {
new import_obsidian9.Setting(contentEl).setName("Collapse folder when opening folder note").setDesc("Choose if the folder should be collapsed when the folder note is opened").addToggle((toggle) => toggle.setValue(this.pattern.enableCollapsing).onChange(async (value) => {
this.pattern.enableCollapsing = value;
await this.plugin.saveSettings();
}));
}
}
onClose() {
const { contentEl } = this;
contentEl.empty();
}
};
// src/ExcludeFolders/functions/patternFunctions.ts
var REGEX_PREFIX = "{regex}";
var STAR = "*";
var INDEX_START = 0;
var SLICE_START_ONE = 1;
var SLICE_EXCLUDE_LAST = -1;
function matchesPatternSpec(raw, folderName) {
if (!raw)
return false;
const string = raw.trim();
const isRegex = string.startsWith(REGEX_PREFIX);
const hasStartStar = string.startsWith(STAR);
const hasEndStar = string.endsWith(STAR);
if (!isRegex && !(hasStartStar || hasEndStar))
return false;
if (isRegex) {
const body = string.replace(REGEX_PREFIX, "").trim();
if (body === "")
return false;
try {
return new RegExp(body).test(folderName);
} catch (e) {
return false;
}
}
if (hasStartStar && hasEndStar) {
const inner = string.slice(SLICE_START_ONE, SLICE_EXCLUDE_LAST);
return folderName.includes(inner);
}
if (hasStartStar) {
const suffix = string.slice(SLICE_START_ONE);
return folderName.endsWith(suffix);
}
if (hasEndStar) {
const prefix = string.slice(INDEX_START, SLICE_EXCLUDE_LAST);
return folderName.startsWith(prefix);
}
return false;
}
function updatePattern(plugin, pattern, newPattern) {
plugin.settings.excludeFolders = plugin.settings.excludeFolders.filter((folder) => folder.id !== pattern.id);
addExcludedFolder(plugin, newPattern);
}
async function deletePattern(plugin, pattern) {
plugin.settings.excludeFolders = plugin.settings.excludeFolders.filter((folder) => folder.id !== pattern.id || folder.type === "folder");
await plugin.saveSettings(true);
resyncArray(plugin);
}
function getExcludedFoldersByPattern(plugin, folderName) {
return plugin.settings.excludeFolders.filter((s) => s.type === "pattern").filter((pattern) => matchesPatternSpec(pattern.string, folderName));
}
function addExcludePatternListItem(settings, containerEl, pattern) {
const { plugin } = settings;
const setting = new import_obsidian10.Setting(containerEl);
setting.setClass("fn-exclude-folder-list");
setting.addSearch((cb) => {
cb.containerEl.addClass("fn-exclude-folder-path");
cb.setPlaceholder("Pattern");
cb.setValue(pattern.string);
cb.onChange((value) => {
pattern.string = value;
updatePattern(plugin, pattern, pattern);
});
});
setting.addButton((cb) => {
cb.setIcon("edit");
cb.setTooltip("Edit pattern");
cb.onClick(() => {
new PatternSettings(plugin.app, plugin, pattern).open();
});
});
if (import_obsidian10.Platform.isDesktop || import_obsidian10.Platform.isTablet) {
setting.addButton((cb) => {
cb.setIcon("up-chevron-glyph");
cb.setTooltip("Move up");
cb.onClick(() => {
if (pattern.position === 0) {
return;
}
pattern.position -= 1;
updatePattern(plugin, pattern, pattern);
const oldPattern = plugin.settings.excludeFolders.find((folder) => folder.position === pattern.position);
if (oldPattern) {
oldPattern.position += 1;
if (oldPattern.type === "pattern") {
const pat = oldPattern;
updatePattern(plugin, pat, pat);
} else {
updateExcludedFolder(plugin, oldPattern, oldPattern);
}
}
settings.display();
});
});
setting.addButton((cb) => {
cb.setIcon("down-chevron-glyph");
cb.setTooltip("Move down");
cb.onClick(() => {
if (pattern.position === plugin.settings.excludeFolders.length - 1) {
return;
}
pattern.position += 1;
updatePattern(plugin, pattern, pattern);
const oldPattern = plugin.settings.excludeFolders.find((folder) => folder.position === pattern.position);
if (oldPattern) {
oldPattern.position -= 1;
if (oldPattern.type === "pattern") {
const pat = oldPattern;
updatePattern(plugin, pat, pat);
} else {
updateExcludedFolder(plugin, oldPattern, oldPattern);
}
}
settings.display();
});
});
}
setting.addButton((cb) => {
cb.setIcon("trash-2");
cb.setTooltip("Delete pattern");
cb.onClick(() => {
void deletePattern(plugin, pattern);
setting.clear();
setting.settingEl.remove();
});
});
}
// src/ExcludeFolders/WhitelistPattern.ts
var WhitelistedPattern = class {
constructor(pattern, position, id, plugin) {
this.type = "pattern";
this.id = id || crypto.randomUUID();
this.subFolders = plugin.settings.excludePatternDefaultSettings.subFolders;
this.position = position;
this.string = pattern;
this.path = "";
}
};
// src/ExcludeFolders/functions/whitelistFolderFunctions.ts
var import_obsidian14 = require("obsidian");
// src/ExcludeFolders/modals/WhitelistFolderSettings.ts
var import_obsidian11 = require("obsidian");
var WhitelistFolderSettings = class extends import_obsidian11.Modal {
constructor(app2, plugin, whitelistedFolder) {
super(app2);
this.plugin = plugin;
this.app = app2;
this.whitelistedFolder = whitelistedFolder;
}
onOpen() {
this.display();
}
display() {
const { contentEl } = this;
contentEl.empty();
contentEl.createEl("h2", { text: "Whitelisted folder settings" });
new import_obsidian11.Setting(contentEl).setName("Include subfolders").setDesc("Choose if the subfolders of the folder should also be whitelisted").addToggle((toggle) => toggle.setValue(this.whitelistedFolder.subFolders).onChange(async (value) => {
this.whitelistedFolder.subFolders = value;
await this.plugin.saveSettings(true);
}));
new import_obsidian11.Setting(contentEl).setName("Enable folder name sync").setDesc("Choose if the name of a folder note should be renamed when the folder name is changed").addToggle((toggle) => toggle.setValue(this.whitelistedFolder.enableSync).onChange(async (value) => {
this.whitelistedFolder.enableSync = value;
await this.plugin.saveSettings();
}));
new import_obsidian11.Setting(contentEl).setName("Show folder in folder overview").setDesc("Choose if the folder should be shown in the folder overview").addToggle((toggle) => toggle.setValue(this.whitelistedFolder.showInFolderOverview).onChange(async (value) => {
this.whitelistedFolder.showInFolderOverview = value;
await this.plugin.saveSettings();
}));
new import_obsidian11.Setting(contentEl).setName("Hide folder note in file explorer").setDesc("Choose if the folder note should be hidden in the file explorer").addToggle((toggle) => toggle.setValue(this.whitelistedFolder.hideInFileExplorer).onChange(async (value) => {
this.whitelistedFolder.hideInFileExplorer = value;
await this.plugin.saveSettings();
}));
new import_obsidian11.Setting(contentEl).setName("Allow auto creation of folder notes in this folder").addToggle((toggle) => toggle.setValue(this.whitelistedFolder.enableAutoCreate).onChange(async (value) => {
this.whitelistedFolder.enableAutoCreate = value;
await this.plugin.saveSettings();
}));
new import_obsidian11.Setting(contentEl).setName("Open folder note when clicking on the folder").setDesc("Choose if the folder note should be opened when the folder is opened").addToggle((toggle) => toggle.setValue(this.whitelistedFolder.enableFolderNote).onChange(async (value) => {
this.whitelistedFolder.enableFolderNote = value;
await this.plugin.saveSettings(true);
this.display();
}));
if (this.whitelistedFolder.enableFolderNote) {
new import_obsidian11.Setting(contentEl).setName("Don't collapse folder when opening folder note").setDesc("Choose if the folder should be collapsed when the folder note is opened").addToggle((toggle) => toggle.setValue(this.whitelistedFolder.disableCollapsing).onChange(async (value) => {
this.whitelistedFolder.disableCollapsing = value;
await this.plugin.saveSettings();
}));
}
}
onClose() {
const { contentEl } = this;
contentEl.empty();
}
};
// src/ExcludeFolders/functions/whitelistPatternFunctions.ts
var import_obsidian13 = require("obsidian");
// src/ExcludeFolders/modals/WhitelistPatternSettings.ts
var import_obsidian12 = require("obsidian");
var WhitelistPatternSettings = class extends import_obsidian12.Modal {
constructor(app2, plugin, pattern) {
super(app2);
this.plugin = plugin;
this.app = app2;
this.pattern = pattern;
}
onOpen() {
this.display();
}
display() {
const { contentEl } = this;
contentEl.empty();
contentEl.createEl("h2", { text: "Whitelisted pattern settings" });
new import_obsidian12.Setting(contentEl).setName("Enable folder name sync").setDesc("Choose if the name of a folder note should be renamed when the folder name is changed").addToggle((toggle) => toggle.setValue(this.pattern.enableSync).onChange(async (value) => {
this.pattern.enableSync = value;
await this.plugin.saveSettings();
}));
new import_obsidian12.Setting(contentEl).setName("Allow auto creation of folder notes in this folder").addToggle((toggle) => toggle.setValue(this.pattern.enableAutoCreate).onChange(async (value) => {
this.pattern.enableAutoCreate = value;
await this.plugin.saveSettings();
}));
new import_obsidian12.Setting(contentEl).setName("Show folder in folder overview").setDesc("Choose if the folder should be shown in the folder overview").addToggle((toggle) => toggle.setValue(this.pattern.showInFolderOverview).onChange(async (value) => {
this.pattern.showInFolderOverview = value;
await this.plugin.saveSettings();
}));
new import_obsidian12.Setting(contentEl).setName("Open folder note when clicking on the folder").setDesc("Choose if the folder note should be opened when you click on the folder").addToggle((toggle) => toggle.setValue(this.pattern.enableFolderNote).onChange(async (value) => {
this.pattern.enableFolderNote = value;
await this.plugin.saveSettings(true);
this.display();
}));
if (this.pattern.enableFolderNote) {
new import_obsidian12.Setting(contentEl).setName("Don't collapse folder when opening folder note").setDesc("Choose if the folder should be collapsed when the folder note is opened").addToggle((toggle) => toggle.setValue(this.pattern.disableCollapsing).onChange(async (value) => {
this.pattern.disableCollapsing = value;
await this.plugin.saveSettings();
}));
}
}
onClose() {
const { contentEl } = this;
contentEl.empty();
}
};
// src/ExcludeFolders/functions/whitelistPatternFunctions.ts
var REGEX_PREFIX2 = "{regex}";
var STAR2 = "*";
var SLICE_START_ONE2 = 1;
var SLICE_EXCLUDE_LAST2 = -1;
function matchesPatternSpec2(raw, folderName) {
if (!raw)
return false;
const string = raw.trim();
const isRegex = string.startsWith(REGEX_PREFIX2);
const hasStartStar = string.startsWith(STAR2);
const hasEndStar = string.endsWith(STAR2);
if (!isRegex && !(hasStartStar || hasEndStar))
return false;
if (isRegex) {
const body = string.replace(REGEX_PREFIX2, "").trim();
if (body === "")
return false;
try {
return new RegExp(body).test(folderName);
} catch (e) {
return false;
}
}
if (hasStartStar && hasEndStar) {
const inner = string.slice(SLICE_START_ONE2, SLICE_EXCLUDE_LAST2);
return folderName.includes(inner);
}
if (hasStartStar) {
const suffix = string.slice(SLICE_START_ONE2);
return folderName.endsWith(suffix);
}
if (hasEndStar) {
const prefix = string.slice(0, SLICE_EXCLUDE_LAST2);
return folderName.startsWith(prefix);
}
return false;
}
function updateWhitelistedPattern(plugin, pattern, newPattern) {
plugin.settings.whitelistFolders = plugin.settings.whitelistFolders.filter((folder) => folder.id !== pattern.id);
addWhitelistedFolder(plugin, newPattern);
}
async function deletePattern2(plugin, pattern) {
plugin.settings.whitelistFolders = plugin.settings.whitelistFolders.filter((folder) => folder.id !== pattern.id || folder.type === "folder");
await plugin.saveSettings(true);
resyncArray(plugin);
}
function getWhitelistedFoldersByPattern(plugin, folderName) {
return plugin.settings.whitelistFolders.filter((s) => s.type === "pattern").filter((pattern) => matchesPatternSpec2(pattern.string, folderName));
}
function addWhitelistedPatternListItem(settings, containerEl, pattern) {
const { plugin } = settings;
const setting = new import_obsidian13.Setting(containerEl);
setting.setClass("fn-exclude-folder-list");
setting.addSearch((cb) => {
cb.containerEl.addClass("fn-exclude-folder-path");
cb.setPlaceholder("Pattern");
cb.setValue(pattern.string);
cb.onChange((value) => {
const exists = plugin.settings.whitelistFolders.some((folder) => folder.string === value);
if (exists) {
return;
}
pattern.string = value;
updateWhitelistedPattern(plugin, pattern, pattern);
});
});
setting.addButton((cb) => {
cb.setIcon("edit");
cb.setTooltip("Edit pattern");
cb.onClick(() => {
new WhitelistPatternSettings(plugin.app, plugin, pattern).open();
});
});
setting.addButton((cb) => {
cb.setIcon("up-chevron-glyph");
cb.setTooltip("Move up");
cb.onClick(() => {
if (pattern.position === 0) {
return;
}
pattern.position -= 1;
updateWhitelistedPattern(plugin, pattern, pattern);
const oldPattern = plugin.settings.whitelistFolders.find((folder) => folder.position === pattern.position);
if (oldPattern) {
oldPattern.position += 1;
if (oldPattern.type === "pattern") {
updateWhitelistedPattern(plugin, oldPattern, oldPattern);
} else {
updateWhitelistedFolder(plugin, oldPattern, oldPattern);
}
}
settings.display();
});
});
setting.addButton((cb) => {
cb.setIcon("down-chevron-glyph");
cb.setTooltip("Move down");
cb.onClick(() => {
if (pattern.position === plugin.settings.whitelistFolders.length - 1) {
return;
}
pattern.position += 1;
updateWhitelistedPattern(plugin, pattern, pattern);
const oldPattern = plugin.settings.whitelistFolders.find((folder) => folder.position === pattern.position);
if (oldPattern) {
oldPattern.position -= 1;
if (oldPattern.type === "pattern") {
updateWhitelistedPattern(plugin, oldPattern, oldPattern);
} else {
updateWhitelistedFolder(plugin, oldPattern, oldPattern);
}
}
settings.display();
});
});
setting.addButton((cb) => {
cb.setIcon("trash-2");
cb.setTooltip("Delete pattern");
cb.onClick(() => {
void deletePattern2(plugin, pattern);
setting.clear();
setting.settingEl.remove();
});
});
}
// src/ExcludeFolders/functions/whitelistFolderFunctions.ts
function getWhitelistedFolder(plugin, path) {
let whitelistedFolder = {};
const folderName = getFolderNameFromPathString(path);
const matchedPatterns = getWhitelistedFoldersByPattern(plugin, folderName);
const whitelistedFolders = getWhitelistedFoldersByPath(plugin, path);
const combinedWhitelistedFolders = [...matchedPatterns, ...whitelistedFolders];
const propertiesToCopy = [
"enableAutoCreate",
"enableFolderNote",
"enableSync",
"showInFolderOverview"
];
if (combinedWhitelistedFolders.length > 0) {
for (const matchedFolder of combinedWhitelistedFolders) {
propertiesToCopy.forEach((property) => {
const value = matchedFolder[property];
if (value === true) {
whitelistedFolder[property] = true;
} else if (!value) {
whitelistedFolder[property] = false;
}
});
}
}
if (whitelistedFolder && Object.keys(whitelistedFolder).length === 0) {
whitelistedFolder = void 0;
}
return whitelistedFolder;
}
function getWhitelistedFoldersByPath(plugin, path) {
return plugin.settings.whitelistFolders.filter((whitelistedFolder) => {
if (whitelistedFolder.path === path) {
return true;
}
if (!whitelistedFolder.subFolders) {
return false;
}
return getFolderPathFromString(path).startsWith(whitelistedFolder.path);
});
}
function addWhitelistedFolder(plugin, whitelistedFolder) {
plugin.settings.whitelistFolders.push(whitelistedFolder);
void plugin.saveSettings(true);
}
async function deleteWhitelistedFolder(plugin, whitelistedFolder) {
plugin.settings.whitelistFolders = plugin.settings.whitelistFolders.filter((folder) => folder.id !== whitelistedFolder.id || folder.type === "pattern");
await plugin.saveSettings(true);
resyncArray2(plugin);
}
function updateWhitelistedFolder(plugin, whitelistedFolder, newWhitelistFolder) {
plugin.settings.whitelistFolders = plugin.settings.whitelistFolders.filter((folder) => folder.id !== whitelistedFolder.id);
addWhitelistedFolder(plugin, newWhitelistFolder);
}
function resyncArray2(plugin) {
plugin.settings.whitelistFolders = plugin.settings.whitelistFolders.sort((a, b) => a.position - b.position);
plugin.settings.whitelistFolders.forEach((folder, index) => {
folder.position = index;
});
void plugin.saveSettings();
}
function addWhitelistFolderListItem(settings, containerEl, whitelistedFolder) {
const { plugin } = settings;
const setting = new import_obsidian14.Setting(containerEl);
setting.setClass("fn-exclude-folder-list");
const inputContainer = setting.settingEl.createDiv({
cls: "fn-whitelist-folder-input-container"
});
const SearchComponent = new import_obsidian14.Setting(inputContainer);
SearchComponent.addSearch((cb) => {
new FolderSuggest(cb.inputEl, plugin, true);
cb.containerEl.addClass("fn-exclude-folder-path");
cb.setPlaceholder("Folder path");
cb.setValue(whitelistedFolder.path);
cb.onChange((value) => {
if (value.startsWith("{regex}") || value.includes("*")) {
void deleteWhitelistedFolder(plugin, whitelistedFolder);
const pattern = new WhitelistedPattern(value, plugin.settings.whitelistFolders.length, void 0, plugin);
addWhitelistedFolder(plugin, pattern);
addWhitelistedPatternListItem(settings, containerEl, pattern);
setting.clear();
setting.settingEl.remove();
}
if (!plugin.app.vault.getAbstractFileByPath(value))
return;
whitelistedFolder.path = value;
updateWhitelistedFolder(plugin, whitelistedFolder, whitelistedFolder);
});
});
const buttonContainer = setting.settingEl.createDiv({ cls: "fn-whitelist-folder-buttons" });
new import_obsidian14.ButtonComponent(buttonContainer).setIcon("edit").setTooltip("Edit folder note").onClick(() => {
new WhitelistFolderSettings(plugin.app, plugin, whitelistedFolder).open();
});
new import_obsidian14.ButtonComponent(buttonContainer).setIcon("up-chevron-glyph").setTooltip("Move up").onClick(() => {
if (whitelistedFolder.position === 0) {
return;
}
whitelistedFolder.position -= 1;
updateWhitelistedFolder(plugin, whitelistedFolder, whitelistedFolder);
const oldWhitelistedFolder = plugin.settings.whitelistFolders.find((folder) => folder.position === whitelistedFolder.position);
if (oldWhitelistedFolder) {
oldWhitelistedFolder.position += 1;
if (oldWhitelistedFolder.type === "pattern") {
updateWhitelistedPattern(plugin, oldWhitelistedFolder, oldWhitelistedFolder);
} else {
updateWhitelistedFolder(plugin, oldWhitelistedFolder, oldWhitelistedFolder);
}
}
settings.display();
});
new import_obsidian14.ButtonComponent(buttonContainer).setIcon("down-chevron-glyph").setTooltip("Move down").onClick(() => {
if (whitelistedFolder.position === plugin.settings.whitelistFolders.length - 1) {
return;
}
whitelistedFolder.position += 1;
updateWhitelistedFolder(plugin, whitelistedFolder, whitelistedFolder);
const oldWhitelistedFolder = plugin.settings.whitelistFolders.find((folder) => folder.position === whitelistedFolder.position);
if (oldWhitelistedFolder) {
oldWhitelistedFolder.position -= 1;
if (oldWhitelistedFolder.type === "pattern") {
updateWhitelistedPattern(plugin, oldWhitelistedFolder, oldWhitelistedFolder);
} else {
updateWhitelistedFolder(plugin, oldWhitelistedFolder, oldWhitelistedFolder);
}
}
settings.display();
});
new import_obsidian14.ButtonComponent(buttonContainer).setIcon("trash-2").setTooltip("Delete excluded folder").onClick(() => {
void deleteWhitelistedFolder(plugin, whitelistedFolder);
setting.clear();
setting.settingEl.remove();
});
}
// src/ExcludeFolders/functions/folderFunctions.ts
function combineExcluded(plugin, path, includeDetached, pathOnly) {
const folderName = getFolderNameFromPathString(path);
const matchedPatterns = pathOnly ? [] : getExcludedFoldersByPattern(plugin, folderName);
const excludedByPath = getExcludedFoldersByPath(plugin, path);
let combined = [...matchedPatterns, ...excludedByPath];
if (!includeDetached)
combined = combined.filter((f) => !f.detached);
return combined;
}
function aggregateFlags(combinedExcludedFolders) {
if (combinedExcludedFolders.length === 0)
return void 0;
const result = {};
const propertiesToCopy = [
"disableAutoCreate",
"disableFolderNote",
"disableSync",
"enableCollapsing",
"excludeFromFolderOverview",
"detached",
"hideInSettings",
"id",
"showFolderNote"
];
for (const matchedFolder of combinedExcludedFolders) {
for (const property of propertiesToCopy) {
const value = matchedFolder[property];
if (value === true) {
result[property] = true;
} else if (!value) {
result[property] = false;
}
}
}
return result;
}
function applyWhitelistOverrides(excluded, whitelisted) {
const out = { ...excluded };
if (out.disableAutoCreate !== void 0) {
out.disableAutoCreate = !whitelisted.enableAutoCreate;
}
if (out.disableFolderNote !== void 0) {
out.disableFolderNote = !whitelisted.enableFolderNote;
}
if (out.disableSync !== void 0) {
out.disableSync = !whitelisted.enableSync;
}
out.enableCollapsing = !whitelisted.disableCollapsing;
if (out.excludeFromFolderOverview !== void 0) {
out.excludeFromFolderOverview = !whitelisted.showInFolderOverview;
}
out.showFolderNote = !whitelisted.hideInFileExplorer;
return out;
}
function defaultExcludedIfEmpty(value) {
if (value && Object.keys(value).length === 0) {
return {
type: "folder",
id: "",
path: "",
string: "",
subFolders: false,
disableSync: false,
disableAutoCreate: false,
disableFolderNote: false,
enableCollapsing: false,
position: 0,
excludeFromFolderOverview: false,
hideInSettings: false,
detached: false,
showFolderNote: false
};
}
return value;
}
function getExcludedFolder(plugin, path, includeDetached, pathOnly, ignoreWhitelist) {
const combined = combineExcluded(plugin, path, includeDetached, pathOnly);
let excluded = aggregateFlags(combined);
const whitelist = getWhitelistedFolder(plugin, path);
let skipWhitelist = ignoreWhitelist != null ? ignoreWhitelist : false;
if (excluded == null ? void 0 : excluded.detached)
skipWhitelist = true;
if (whitelist && excluded && !skipWhitelist) {
excluded = applyWhitelistOverrides(excluded, whitelist);
}
return defaultExcludedIfEmpty(excluded);
}
function getDetachedFolder(plugin, path) {
return plugin.settings.excludeFolders.find((f) => f.path === path && f.detached);
}
function getExcludedFoldersByPath(plugin, path) {
return plugin.settings.excludeFolders.filter((excludedFolder) => {
if (path.trim() === "" || !excludedFolder.path) {
return false;
}
if (excludedFolder.path === path) {
return true;
}
if (!excludedFolder.subFolders) {
return false;
}
const excludedFolderPath = excludedFolder.path.includes("/") ? excludedFolder.path : `${excludedFolder.path}/`;
let folderPath = getFolderPathFromString(path);
folderPath = folderPath.includes("/") ? folderPath : `${folderPath}/`;
if (folderPath.includes("/") || folderPath.includes("\\")) {
return folderPath.startsWith(excludedFolderPath) || folderPath === excludedFolderPath;
}
return folderPath === excludedFolderPath;
});
}
function addExcludedFolder(plugin, excludedFolder, reloadStyles = true) {
plugin.settings.excludeFolders.push(excludedFolder);
void plugin.saveSettings(reloadStyles);
}
async function deleteExcludedFolder(plugin, excludedFolder) {
plugin.settings.excludeFolders = plugin.settings.excludeFolders.filter((folder) => folder.id !== excludedFolder.id || folder.type === "pattern");
await plugin.saveSettings(true);
resyncArray(plugin);
}
function updateExcludedFolder(plugin, excludedFolder, newExcludeFolder) {
plugin.settings.excludeFolders = plugin.settings.excludeFolders.filter((folder) => folder.id !== excludedFolder.id);
addExcludedFolder(plugin, newExcludeFolder);
}
function resyncArray(plugin) {
plugin.settings.excludeFolders = plugin.settings.excludeFolders.sort((a, b) => a.position - b.position);
plugin.settings.excludeFolders.forEach((folder, index) => {
folder.position = index;
});
void plugin.saveSettings();
}
function addExcludeFolderListItem(settings, containerEl, excludedFolder) {
const { plugin } = settings;
const setting = new import_obsidian15.Setting(containerEl);
setting.setClass("fn-exclude-folder-list");
setting.addSearch((cb) => {
new FolderSuggest(cb.inputEl, plugin, false);
cb.containerEl.addClass("fn-exclude-folder-path");
cb.setPlaceholder("Folder path");
cb.setValue(excludedFolder.path || "");
cb.onChange((value) => {
if (value.startsWith("{regex}") || value.includes("*")) {
deleteExcludedFolder(plugin, excludedFolder);
const pattern = new ExcludePattern(value, plugin.settings.excludeFolders.length, void 0, plugin);
addExcludedFolder(plugin, pattern);
addExcludePatternListItem(settings, containerEl, pattern);
setting.clear();
setting.settingEl.remove();
}
if (!plugin.app.vault.getAbstractFileByPath(value))
return;
excludedFolder.path = value;
updateExcludedFolder(plugin, excludedFolder, excludedFolder);
});
});
setting.addButton((cb) => {
cb.setIcon("edit");
cb.setTooltip("Edit folder note");
cb.onClick(() => {
new ExcludedFolderSettings(plugin.app, plugin, excludedFolder).open();
});
});
if (import_obsidian15.Platform.isDesktop || import_obsidian15.Platform.isTablet) {
setting.addButton((cb) => {
cb.setIcon("up-chevron-glyph");
cb.setTooltip("Move up");
cb.onClick(() => {
if (excludedFolder.position === 0) {
return;
}
excludedFolder.position -= 1;
updateExcludedFolder(plugin, excludedFolder, excludedFolder);
const oldExcludedFolder = plugin.settings.excludeFolders.find((folder) => folder.position === excludedFolder.position);
if (oldExcludedFolder) {
oldExcludedFolder.position += 1;
if (oldExcludedFolder.type === "pattern") {
updatePattern(plugin, oldExcludedFolder, oldExcludedFolder);
} else {
updateExcludedFolder(plugin, oldExcludedFolder, oldExcludedFolder);
}
}
settings.display();
});
});
setting.addButton((cb) => {
cb.setIcon("down-chevron-glyph");
cb.setTooltip("Move down");
cb.onClick(() => {
if (excludedFolder.position === plugin.settings.excludeFolders.length - 1) {
return;
}
excludedFolder.position += 1;
updateExcludedFolder(plugin, excludedFolder, excludedFolder);
const oldExcludedFolder = plugin.settings.excludeFolders.find((folder) => folder.position === excludedFolder.position);
if (oldExcludedFolder) {
oldExcludedFolder.position -= 1;
if (oldExcludedFolder.type === "pattern") {
updatePattern(plugin, oldExcludedFolder, oldExcludedFolder);
} else {
updateExcludedFolder(plugin, oldExcludedFolder, oldExcludedFolder);
}
}
settings.display();
});
});
}
setting.addButton((cb) => {
cb.setIcon("trash-2");
cb.setTooltip("Delete excluded folder");
cb.onClick(() => {
deleteExcludedFolder(plugin, excludedFolder);
setting.clear();
setting.settingEl.remove();
});
});
}
// src/functions/excalidraw.ts
async function openExcalidrawView(app2, leaf) {
const { excalidraw, excalidrawEnabled } = await getExcalidrawPlugin(app2);
if (excalidrawEnabled && excalidraw) {
excalidraw.setExcalidrawView(leaf);
}
}
async function getExcalidrawPlugin(app2) {
const { plugins: pluginManager } = app2;
const excalidraw = pluginManager.plugins["obsidian-excalidraw-plugin"];
const excalidrawEnabled = pluginManager.enabledPlugins.has("obsidian-excalidraw-plugin");
return {
excalidraw: excalidraw != null ? excalidraw : null,
excalidrawEnabled
};
}
// src/modals/AskForExtension.ts
var import_obsidian16 = require("obsidian");
var AskForExtensionModal = class extends import_obsidian16.FuzzySuggestModal {
constructor(plugin, folderPath, openFile, extension, useModal, existingNote) {
super(plugin.app);
this.plugin = plugin;
this.folderPath = folderPath;
this.extension = extension;
this.openFile = openFile;
this.useModal = useModal;
this.existingNote = existingNote;
plugin.askModalCurrentlyOpen = true;
}
getItems() {
return this.plugin.settings.supportedFileTypes.filter((item) => item.toLowerCase() !== ".ask");
}
getItemText(item) {
return item;
}
onChooseItem(item, _evt) {
this.plugin.askModalCurrentlyOpen = false;
this.extension = "." + item;
createFolderNote(this.plugin, this.folderPath, this.openFile, this.extension, this.useModal, this.existingNote);
this.close();
}
};
// src/functions/folderNoteFunctions.ts
var defaultExcalidrawTemplate = `---
excalidraw-plugin: parsed
tags: [excalidraw]
---
==\u26A0 Switch to EXCALIDRAW VIEW in the MORE OPTIONS menu of this document. \u26A0==
%%
# Drawing
\`\`\`json
{'type":"excalidraw","version":2,"source":"https://github.com/zsviczian/obsidian-excalidraw-plugin/releases/tag/1.9.20","elements":[],"appState":{"gridSize":null,"viewBackgroundColor":"#ffffff'}}
\`\`\`
%%`;
async function createFolderNote(plugin, folderPath, openFile, extension, displayModal, preexistingNote) {
var _a;
let {
leaf,
fileName,
folderNote,
folderNoteType,
detachedFolder,
path
} = getArgs(plugin, folderPath, extension, preexistingNote);
if (folderNoteType === ".excalidraw") {
folderNoteType = ".md";
extension = ".excalidraw";
} else if (folderNoteType === ".ask") {
if (plugin.askModalCurrentlyOpen)
return;
return new AskForExtensionModal(plugin, folderPath, openFile, folderNoteType, displayModal, preexistingNote).open();
}
if (plugin.settings.storageLocation === "parentFolder") {
const parentFolderPath = getFolderPathFromString(folderPath);
if (parentFolderPath.trim() === "") {
path = `${fileName}${folderNoteType}`;
} else {
path = `${parentFolderPath}/${fileName}${folderNoteType}`;
}
} else if (plugin.settings.storageLocation === "vaultFolder") {
path = `${fileName}${folderNoteType}`;
} else {
path = `${folderPath}/${fileName}${folderNoteType}`;
}
if (detachedFolder && (folderNote == null ? void 0 : folderNote.extension) !== extension && folderNote) {
await handleTurnNoteIntoFolderNote(plugin, folderNote, detachedFolder, folderPath, fileName);
}
if (!extension) {
extension = folderNoteType;
}
if (!folderNote) {
folderNote = await handleCreateFolderNote(plugin, folderNoteType, openFile, leaf, folderNote, path, extension);
} else {
await plugin.app.fileManager.renameFile(folderNote, path);
}
if (openFile) {
if (((_a = plugin.app.workspace.getActiveFile()) == null ? void 0 : _a.path) === path) {
removeActiveFolder(plugin);
const folder2 = getFolder(plugin, folderNote);
if (!folder2) {
return;
}
setActiveFolder(folder2.path, plugin);
}
await leaf.openFile(folderNote);
if (plugin.settings.folderNoteType === ".excalidraw" || extension === ".excalidraw") {
openExcalidrawView(plugin.app, leaf);
}
}
const matchingExtension = (extension == null ? void 0 : extension.split(".").pop()) === plugin.settings.templatePath.split(".").pop();
if (folderNote && matchingExtension && plugin.settings.folderNoteType !== ".excalidraw") {
applyTemplate(plugin, folderNote, leaf, plugin.settings.templatePath);
}
const folder = plugin.app.vault.getAbstractFileByPath(folderPath);
if (!(folder instanceof import_obsidian17.TFolder))
return;
addCSSClassToFileExplorerEl(path, "is-folder-note", false, plugin, true);
addCSSClassToFileExplorerEl(folder.path, "has-folder-note", false, plugin);
}
function getArgs(plugin, folderPath, extension, preexistingNote) {
const leaf = plugin.app.workspace.getLeaf(false);
const folderName = getFolderNameFromPathString(folderPath);
const fileName = plugin.settings.folderNoteName.replace("{{folder_name}}", folderName);
let folderNote = getFolderNote(plugin, folderPath);
if (preexistingNote) {
folderNote = preexistingNote;
}
let folderNoteType = extension != null ? extension : plugin.settings.folderNoteType;
const detachedFolder = getDetachedFolder(plugin, folderPath);
let path = "";
return {
leaf,
fileName,
folderNote,
folderNoteType,
detachedFolder,
path
};
}
async function handleCreateFolderNote(plugin, folderNoteType, openFile, leaf, folderNote, path, extension) {
let content = "";
if (extension !== ".md" && extension) {
if (plugin.settings.templatePath && folderNoteType.split(".").pop() === plugin.settings.templatePath.split(".").pop()) {
const templateFile = plugin.app.vault.getAbstractFileByPath(plugin.settings.templatePath);
if (templateFile instanceof import_obsidian17.TFile) {
if (["md", "canvas", "txt"].includes(templateFile.extension)) {
content = await plugin.app.vault.read(templateFile);
if (extension === ".excalidraw" && !content.includes("==\u26A0 Switch to EXCALIDRAW VIEW in the MORE OPTIONS menu of this document. \u26A0==")) {
content = defaultExcalidrawTemplate;
}
} else {
plugin.app.vault.readBinary(templateFile).then(async (data) => {
folderNote = await plugin.app.vault.createBinary(path, data);
if (openFile) {
await leaf.openFile(folderNote);
}
return folderNote;
});
}
}
} else if (plugin.settings.folderNoteType === ".excalidraw" || extension === ".excalidraw") {
content = defaultExcalidrawTemplate;
} else if (plugin.settings.folderNoteType === ".canvas") {
content = "{}";
}
}
folderNote = await plugin.app.vault.create(path, content);
return folderNote;
}
async function handleTurnNoteIntoFolderNote(plugin, folderNote, detachedFolder, folderPath, fileName) {
deleteExcludedFolder(plugin, detachedFolder);
removeCSSClassFromFileExplorerEL(folderNote == null ? void 0 : folderNote.path, "is-folder-note", false, plugin);
const folder = plugin.app.vault.getAbstractFileByPath(folderPath);
if (!folderNote || folderNote.basename !== fileName)
return;
let count = 1;
const baseName = removeExtension(folderNote.path);
const ext = folderNote.path.split(".").pop();
let newName = `${baseName} (${count}).${ext}`;
const MAX_FOLDER_NOTE_RENAME_ATTEMPTS = 100;
while (count < MAX_FOLDER_NOTE_RENAME_ATTEMPTS && plugin.app.vault.getAbstractFileByPath(newName)) {
count++;
newName = `${baseName} (${count}).${ext}`;
}
const [
excludedFolder,
excludedFolderExisted,
disabledSync
] = await tempDisableSync(plugin, folder);
await plugin.app.fileManager.renameFile(folderNote, newName).then(() => {
if (!excludedFolder)
return;
if (!excludedFolderExisted) {
deleteExcludedFolder(plugin, excludedFolder);
} else if (!disabledSync) {
excludedFolder.disableSync = false;
updateExcludedFolder(plugin, excludedFolder, excludedFolder);
}
});
}
async function turnIntoFolderNote(plugin, file, folder, folderNote, skipConfirmation) {
var _a;
const { extension } = file;
const detachedExcludedFolder = getDetachedFolder(plugin, folder.path);
if (folderNote) {
if (plugin.settings.showRenameConfirmation && !skipConfirmation && !detachedExcludedFolder) {
return new ExistingFolderNoteModal(plugin.app, plugin, file, folder, folderNote).open();
}
removeCSSClassFromFileExplorerEL(folderNote.path, "is-folder-note", false, plugin);
const [
excludedFolder,
excludedFolderExisted,
disabledSync
] = await tempDisableSync(plugin, folder);
const CTIME_SLICE_START = 10;
const RANDOM_SUFFIX_MAX = 1e3;
const randomSuffix = Math.floor(Math.random() * RANDOM_SUFFIX_MAX);
const ctimeSuffix = file.stat.ctime.toString().slice(CTIME_SLICE_START);
const newPath = `${folder.path}/${folder.name} (${ctimeSuffix}${randomSuffix}).${extension}`;
plugin.app.fileManager.renameFile(folderNote, newPath).then(() => {
if (!excludedFolder)
return;
if (!excludedFolderExisted) {
deleteExcludedFolder(plugin, excludedFolder);
} else if (!disabledSync) {
excludedFolder.disableSync = false;
updateExcludedFolder(plugin, excludedFolder, excludedFolder);
}
});
}
const folderName = folder.name;
const fileName = plugin.settings.folderNoteName.replace("{{folder_name}}", folderName);
let path = `${folder.path}/${fileName}.${extension}`;
if (plugin.settings.storageLocation === "parentFolder") {
const parentFolderPath = (_a = folder.parent) == null ? void 0 : _a.path;
if (!parentFolderPath)
return;
if (parentFolderPath.trim() === "") {
path = `${fileName}.${extension}`;
} else {
path = `${parentFolderPath}/${fileName}.${extension}`;
}
}
if (detachedExcludedFolder) {
deleteExcludedFolder(plugin, detachedExcludedFolder);
}
await plugin.app.fileManager.renameFile(file, path);
addCSSClassToFileExplorerEl(path, "is-folder-note", false, plugin, true);
addCSSClassToFileExplorerEl(folder.path, "has-folder-note", false, plugin);
removeActiveFolder(plugin);
setActiveFolder(folder.path, plugin);
}
async function tempDisableSync(plugin, folder) {
let excludedFolder = getExcludedFolder(plugin, folder.path, false);
let excludedFolderExisted = true;
let disabledSync = false;
if (!excludedFolder) {
excludedFolderExisted = false;
excludedFolder = new ExcludedFolder(folder.path, plugin.settings.excludeFolders.length, void 0, plugin);
excludedFolder.disableSync = true;
addExcludedFolder(plugin, excludedFolder);
} else if (!excludedFolder.disableSync) {
disabledSync = false;
excludedFolder.disableSync = true;
updateExcludedFolder(plugin, excludedFolder, excludedFolder);
}
return [excludedFolder, excludedFolderExisted, disabledSync];
}
async function openFolderNote(plugin, file, evt) {
var _a;
const { path } = file;
const focusExistingTab = plugin.settings.focusExistingTab && plugin.settings.openInNewTab;
const activeFilePath = (_a = plugin.app.workspace.getActiveFile()) == null ? void 0 : _a.path;
if (activeFilePath === path && !(import_obsidian17.Keymap.isModEvent(evt) === "tab")) {
return;
}
let foundLeaf = null;
if (focusExistingTab && file instanceof import_obsidian17.TFile) {
plugin.app.workspace.iterateAllLeaves((leaf) => {
var _a2;
if (leaf.getViewState().type === "markdown" && ((_a2 = leaf.view.file) == null ? void 0 : _a2.path) === path) {
foundLeaf = leaf;
}
});
}
if (foundLeaf) {
plugin.app.workspace.setActiveLeaf(foundLeaf, { focus: true });
} else {
const shouldOpenInNewTab = import_obsidian17.Keymap.isModEvent(evt) || plugin.settings.openInNewTab;
const leaf = plugin.app.workspace.getLeaf(shouldOpenInNewTab);
if (file instanceof import_obsidian17.TFile) {
await leaf.openFile(file);
}
}
}
async function deleteFolderNote(plugin, file, displayModal) {
if (plugin.settings.showDeleteConfirmation && displayModal) {
return new DeleteConfirmationModal(plugin.app, plugin, file).open();
}
const folder = getFolder(plugin, file);
if (!folder)
return;
plugin.settings.excludeFolders = plugin.settings.excludeFolders.filter((excludedFolder) => excludedFolder.path !== folder.path && excludedFolder.showFolderNote);
plugin.saveSettings(false);
removeCSSClassFromFileExplorerEL(folder.path, "has-folder-note", false, plugin);
switch (plugin.settings.deleteFilesAction) {
case "trash":
await plugin.app.vault.trash(file, true);
break;
case "obsidianTrash":
await plugin.app.vault.trash(file, false);
break;
case "delete":
await plugin.app.vault.delete(file);
break;
}
}
function extractFolderName(template, changedFileName) {
const [prefix, suffix] = template.split("{{folder_name}}");
if (prefix.trim() === "" && suffix.trim() === "") {
return changedFileName;
}
if (!changedFileName.startsWith(prefix) || !changedFileName.endsWith(suffix)) {
return null;
}
if (changedFileName.startsWith(prefix) && prefix.trim() !== "") {
return changedFileName.slice(prefix.length).replace(suffix, "");
} else if (changedFileName.endsWith(suffix) && suffix.trim() !== "") {
return changedFileName.slice(0, -suffix.length);
}
return null;
}
function findFolderNoteFile(plugin, path, primaryType) {
let folderNote = plugin.app.vault.getAbstractFileByPath(path + primaryType);
if (folderNote instanceof import_obsidian17.TFile && plugin.settings.supportedFileTypes.includes(primaryType.replace(".", ""))) {
return folderNote;
}
const supportedFileTypes = plugin.settings.supportedFileTypes.filter((type) => type !== primaryType.replace(".", ""));
for (let type of supportedFileTypes) {
if (type === "excalidraw" || type === ".excalidraw") {
type = ".md";
}
if (!type.startsWith(".")) {
type = "." + type;
}
folderNote = plugin.app.vault.getAbstractFileByPath(path + type);
if (folderNote instanceof import_obsidian17.TFile) {
return folderNote;
}
}
return null;
}
function getFolderNote(plugin, folderPath, storageLocation, file, oldFolderNoteName) {
const folder = getFolderInfo(folderPath);
if (!folder)
return null;
let fileName = resolveFileName(plugin, folder, file, oldFolderNoteName);
if (!fileName)
return null;
adjustFolderPathForStorage(folder, folderPath, plugin, storageLocation);
const path = buildFullPath(folder, fileName);
const primaryType = normalizeFolderNoteType(plugin.settings.folderNoteType);
return findFolderNoteFile(plugin, path, primaryType);
}
function detachFolderNote(plugin, file) {
const folder = getFolder(plugin, file);
if (!folder)
return;
const excludedFolder = new ExcludedFolder(folder.path, plugin.settings.excludeFolders.length, void 0, plugin);
excludedFolder.hideInSettings = true;
excludedFolder.disableFolderNote = true;
excludedFolder.disableSync = true;
excludedFolder.subFolders = false;
excludedFolder.excludeFromFolderOverview = false;
excludedFolder.detached = true;
excludedFolder.detachedFilePath = file.path;
addExcludedFolder(plugin, excludedFolder);
}
function getFolder(plugin, file, storageLocation) {
var _a, _b;
if (!file)
return null;
let folderName = extractFolderName(plugin.settings.folderNoteName, file.basename);
if (plugin.settings.folderNoteName === file.basename && plugin.settings.storageLocation === "insideFolder") {
folderName = (_b = (_a = file.parent) == null ? void 0 : _a.name) != null ? _b : "";
}
if (!folderName)
return null;
let folderPath = getFolderPathFromString(file.path);
let folder = null;
if ((plugin.settings.storageLocation === "parentFolder" || storageLocation === "parentFolder") && storageLocation !== "insideFolder") {
if (folderPath.trim() === "" || folderPath === "/") {
folderPath = folderName;
} else {
folderPath = `${folderPath}/${folderName}`;
}
folder = plugin.app.vault.getAbstractFileByPath(folderPath);
} else {
folder = plugin.app.vault.getAbstractFileByPath(folderPath);
}
if (!folder) {
return null;
}
return folder;
}
function getFolderNoteFolder(plugin, folderNote, fileName) {
if (!folderNote)
return null;
let filePath = "";
if (typeof folderNote === "string") {
filePath = folderNote;
} else {
fileName = folderNote.basename;
filePath = folderNote.path;
}
const folderName = extractFolderName(plugin.settings.folderNoteName, fileName);
if (!folderName)
return null;
let folderPath = getFolderPathFromString(filePath);
if (plugin.settings.storageLocation === "parentFolder") {
if (folderPath.trim() === "") {
folderPath = folderName;
} else {
folderPath = `${folderPath}/${folderName}`;
}
} else {
folderPath = getFolderPathFromString(filePath);
}
const folder = plugin.app.vault.getAbstractFileByPath(folderPath);
if (!folder) {
return null;
}
return folder;
}
function getFolderInfo(folderPath) {
if (!folderPath)
return null;
return {
path: folderPath,
name: getFolderNameFromPathString(folderPath)
};
}
function resolveFileName(plugin, folder, file, oldFolderNoteName) {
const templateName = oldFolderNoteName != null ? oldFolderNoteName : plugin.settings.folderNoteName;
if (!templateName)
return null;
const nameSource = file ? file.basename : folder.name;
return templateName.replace("{{folder_name}}", nameSource);
}
function adjustFolderPathForStorage(folder, folderPath, plugin, storageLocation) {
if ((plugin.settings.storageLocation === "parentFolder" || storageLocation === "parentFolder") && storageLocation !== "insideFolder") {
folder.path = getFolderPathFromString(folderPath);
}
}
function buildFullPath(folder, fileName) {
return folder.path === "/" ? fileName : `${folder.path}/${fileName}`;
}
function normalizeFolderNoteType(type) {
return type === ".excalidraw" ? ".md" : type;
}
// src/settings/GeneralSettings.ts
var import_obsidian24 = require("obsidian");
// src/events/EventEmitter.ts
var CustomEventEmitter = class {
constructor() {
this.events = {};
}
on(event, listener) {
if (!this.events[event]) {
this.events[event] = [];
}
this.events[event].push(listener);
}
off(event, listener) {
if (!this.events[event])
return;
this.events[event] = this.events[event].filter((l) => l !== listener);
}
emit(event, data) {
if (!this.events[event])
return;
this.events[event].forEach((listener) => listener(data));
}
};
// src/functions/ListComponent.ts
var ListComponent = class {
constructor(containerEl, values = [], defaultValues = []) {
this.emitter = new CustomEventEmitter();
this.containerEl = containerEl;
this.controlEl = containerEl.querySelector(".setting-item-control") || containerEl;
this.listEl = this.controlEl.createDiv("setting-command-hotkeys");
this.addResetButton();
this.setValues(values);
this.defaultValues = defaultValues;
}
on(event, listener) {
this.emitter.on(event, listener);
}
off(event, listener) {
this.emitter.off(event, listener);
}
emit(event, data) {
this.emitter.emit(event, data);
}
setValues(values) {
this.removeElements();
this.values = values;
if (values.length !== 0) {
values.forEach((value) => {
this.addElement(value);
});
}
this.emit("update", this.values);
}
removeElements() {
this.listEl.empty();
}
addElement(value) {
this.listEl.createSpan("setting-hotkey", (span) => {
if (value.toLocaleLowerCase() === "md") {
span.innerText = "markdown";
} else {
span.innerText = value;
}
span.setAttribute("extension", value);
const removeSpan = span.createEl("span", { cls: "ofn-list-item-remove setting-hotkey-icon" });
const svg = '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="svg-icon lucide-x"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg>';
const svgElement = removeSpan.createEl("span", { cls: "ofn-list-item-remove-icon" });
svgElement.innerHTML = svg;
removeSpan.onClickEvent(() => {
this.removeValue(value);
span.remove();
});
});
}
async addValue(value) {
this.values.push(value);
this.addElement(value);
this.emit("add", value);
this.emit("update", this.values);
}
addResetButton() {
const resetButton = this.controlEl.createEl("span", { cls: "clickable-icon setting-restore-hotkey-button" });
const svg = '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="svg-icon lucide-rotate-ccw"><path d="M3 2v6h6"></path><path d="M3 13a9 9 0 1 0 3-7.7L3 8"></path></svg>';
resetButton.innerHTML = svg;
resetButton.onClickEvent(() => {
this.setValues(this.defaultValues);
});
return this;
}
removeValue(value) {
this.values = this.values.filter((v) => v !== value);
this.listEl.find(`[extension='${value}']`).remove();
this.emit("remove", value);
this.emit("update", this.values);
}
};
// src/modals/AddSupportedFileType.ts
var import_obsidian18 = require("obsidian");
var AddSupportedFileModal = class extends import_obsidian18.Modal {
constructor(app2, plugin, settingsTab, list) {
super(app2);
this.plugin = plugin;
this.app = app2;
this.name = "";
this.list = list;
this.settingsTab = settingsTab;
}
onOpen() {
const { contentEl } = this;
contentEl.addEventListener("keydown", (e) => {
if (e.key === "Enter") {
this.close();
}
});
contentEl.createEl("h2", { text: "Extension name" });
new import_obsidian18.Setting(contentEl).setName('Enter the name of the extension (only the short form, e.g. "md")').addText((text) => text.setValue("").onChange(async (value) => {
if (value.trim() !== "") {
this.name = value.trim();
}
}));
}
async onClose() {
if (this.name.toLocaleLowerCase() === "markdown") {
this.name = "md";
}
const { contentEl } = this;
if (this.name === "") {
contentEl.empty();
this.settingsTab.display();
} else if (this.plugin.settings.supportedFileTypes.includes(this.name.toLowerCase())) {
new import_obsidian18.Notice("This extension is already supported");
return;
} else {
await this.list.addValue(this.name.toLowerCase());
this.settingsTab.display();
this.plugin.saveSettings();
contentEl.empty();
}
}
};
// src/events/FrontMatterTitle.ts
var import_front_matter_plugin_api_provider = __toESM(require_lib());
var import_obsidian19 = require("obsidian");
var FrontMatterTitlePluginHandler = class {
constructor(plugin) {
this.api = null;
this.deffer = null;
this.modifiedFolders = /* @__PURE__ */ new Map();
this.plugin = plugin;
this.app = plugin.app;
(async () => {
var _a;
this.deffer = (0, import_front_matter_plugin_api_provider.getDefer)(this.app);
if (this.deffer.isPluginReady()) {
this.api = this.deffer.getApi();
} else {
await this.deffer.awaitPlugin();
this.api = this.deffer.getApi();
if (!this.deffer.isFeaturesReady()) {
await this.deffer.awaitFeatures();
}
}
if (plugin.settings.frontMatterTitle.enabled) {
const dispatcher = (_a = this.api) == null ? void 0 : _a.getEventDispatcher();
if (dispatcher) {
this.dispatcher = dispatcher;
}
const event = {
name: "manager:update",
cb: (data) => {
this.fmptUpdateFileName(data, true);
}
};
const ref = dispatcher == null ? void 0 : dispatcher.addListener(event);
if (ref) {
this.eventRef = ref;
}
this.plugin.updateAllBreadcrumbs();
}
})();
}
deleteEvent() {
if (this.eventRef) {
this.dispatcher.removeListener(this.eventRef);
}
}
async fmptUpdateFileName(data, isEvent) {
var _a, _b, _c;
const hasNestedData = "data" in data;
const actualData = hasNestedData ? data.data : data;
const file = this.app.vault.getAbstractFileByPath(actualData.path);
if (!(file instanceof import_obsidian19.TFile)) {
return;
}
const resolver = (_b = (_a = this.api) == null ? void 0 : _a.getResolverFactory()) == null ? void 0 : _b.createResolver("#feature-id#");
const newName = resolver == null ? void 0 : resolver.resolve((_c = file == null ? void 0 : file.path) != null ? _c : "");
const folder = getFolder(this.plugin, file);
if (!(folder instanceof import_obsidian19.TFolder)) {
return;
}
const folderNote = getFolderNote(this.plugin, folder.path);
if (!folderNote) {
return;
}
if (folderNote !== file) {
return;
}
if (!actualData.pathOnly) {
this.plugin.changeFolderNameInExplorer(folder, newName);
}
const { breadcrumb } = actualData;
if (breadcrumb) {
this.plugin.changeFolderNameInPath(folder, newName, breadcrumb);
}
if (isEvent) {
this.plugin.updateAllBreadcrumbs();
}
if (newName) {
folder.newName = newName;
this.modifiedFolders.set(folder.path, folder);
} else {
folder.newName = null;
this.modifiedFolders.delete(folder.path);
}
}
async fmptUpdateFolderName(data, _replacePath) {
var _a, _b, _c;
const hasNestedData = "data" in data;
const actualData = hasNestedData ? data.data : data;
const folder = this.app.vault.getAbstractFileByPath(actualData.path);
if (!(folder instanceof import_obsidian19.TFolder)) {
return;
}
const folderNote = getFolderNote(this.plugin, folder.path);
if (!folderNote) {
return;
}
const resolver = (_b = (_a = this.api) == null ? void 0 : _a.getResolverFactory()) == null ? void 0 : _b.createResolver("#feature-id#");
const newName = resolver == null ? void 0 : resolver.resolve((_c = folderNote == null ? void 0 : folderNote.path) != null ? _c : "");
if (!newName)
return;
if (!actualData.pathOnly) {
this.plugin.changeFolderNameInExplorer(folder, newName);
}
const { breadcrumb } = actualData;
if (breadcrumb) {
this.plugin.changeFolderNameInPath(folder, newName, breadcrumb);
}
folder.newName = newName;
this.modifiedFolders.set(folder.path, folder);
}
async getNewFolderName(folder) {
var _a, _b, _c, _d;
if (this.modifiedFolders.has(folder.path)) {
const modifiedFolder = this.modifiedFolders.get(folder.path);
if (modifiedFolder) {
return modifiedFolder.newName;
}
}
const folderNote = getFolderNote(this.plugin, folder.path);
if (!folderNote)
return null;
const resolver = (_b = (_a = this.api) == null ? void 0 : _a.getResolverFactory()) == null ? void 0 : _b.createResolver("#feature-id#");
return (_d = resolver == null ? void 0 : resolver.resolve((_c = folderNote == null ? void 0 : folderNote.path) != null ? _c : "")) != null ? _d : null;
}
async getNewFileName(file) {
var _a, _b, _c;
const resolver = (_b = (_a = this.api) == null ? void 0 : _a.getResolverFactory()) == null ? void 0 : _b.createResolver("#feature-id#");
const changedName = resolver == null ? void 0 : resolver.resolve((_c = file == null ? void 0 : file.path) != null ? _c : "");
return changedName != null ? changedName : null;
}
};
// src/settings/modals/CreateFnForEveryFolder.ts
var import_obsidian20 = require("obsidian");
var ConfirmationModal = class extends import_obsidian20.Modal {
constructor(app2, plugin) {
super(app2);
this.plugin = plugin;
this.app = app2;
this.extension = plugin.settings.folderNoteType;
}
onOpen() {
var _a, _b, _c;
this.modalEl.addClass("fn-confirmation-modal");
let templateFolderPath;
const { templateFolder, templaterPlugin } = getTemplatePlugins(this.plugin.app);
if ((!templateFolder || (templateFolder == null ? void 0 : templateFolder.trim()) === "") && !templaterPlugin) {
templateFolderPath = "";
}
if (templaterPlugin) {
templateFolderPath = (_b = (_a = templaterPlugin.plugin) == null ? void 0 : _a.settings) == null ? void 0 : _b.templates_folder;
} else if (templateFolder) {
templateFolderPath = templateFolder;
}
const { contentEl } = this;
contentEl.createEl("h2", { text: "Create folder note for every folder" });
const setting = new import_obsidian20.Setting(contentEl);
setting.infoEl.createEl("p", { text: "Make sure to backup your vault before using this feature." }).style.color = "#fb464c";
setting.infoEl.createEl("p", { text: "This feature will create a folder note for every folder in your vault." });
setting.infoEl.createEl("p", { text: "Every folder that already has a folder note will be ignored." });
setting.infoEl.createEl("p", { text: "Every excluded folder will be ignored." });
if (!this.plugin.settings.templatePath || ((_c = this.plugin.settings.templatePath) == null ? void 0 : _c.trim()) === "") {
new import_obsidian20.Setting(contentEl).setName("Folder note file extension").setDesc("Choose the file extension for the folder notes.").addDropdown((cb) => {
this.plugin.settings.supportedFileTypes.forEach((extension) => {
cb.addOption("." + extension, extension);
});
cb.setValue(this.extension);
cb.onChange(async (value) => {
this.extension = value;
});
});
}
new import_obsidian20.Setting(contentEl).addButton((cb) => {
cb.setButtonText("Create");
cb.setCta();
cb.buttonEl.focus();
cb.onClick(async () => {
if (this.plugin.settings.templatePath && this.plugin.settings.templatePath.trim() !== "") {
this.extension = "." + this.plugin.settings.templatePath.split(".").pop();
}
if (this.extension === ".ask") {
return new import_obsidian20.Notice("Please choose a file extension");
}
this.close();
const folders = this.app.vault.getAllLoadedFiles().filter((file) => file.parent instanceof import_obsidian20.TFolder);
for (const folder of folders) {
if (folder instanceof import_obsidian20.TFolder) {
const excludedFolder = getExcludedFolder(this.plugin, folder.path, true);
if (excludedFolder)
continue;
if (folder.path === templateFolderPath)
continue;
const folderNote = getFolderNote(this.plugin, folder.path);
if (folderNote)
continue;
await createFolderNote(this.plugin, folder.path, false, this.extension);
}
}
});
}).addButton((cb) => {
cb.setButtonText("Cancel");
cb.onClick(async () => {
this.close();
});
});
}
onClose() {
const { contentEl } = this;
contentEl.empty();
}
};
// src/suggesters/TemplateSuggester.ts
var import_obsidian21 = require("obsidian");
var TemplateSuggest = class extends import_obsidian21.AbstractInputSuggest {
constructor(inputEl, plugin) {
super(plugin.app, inputEl);
this.inputEl = inputEl;
this.plugin = plugin;
}
get_error_msg(mode) {
switch (mode) {
case 0 /* TemplateFiles */:
return "Templates folder doesn't exist";
case 1 /* ScriptFiles */:
return "User Scripts folder doesn't exist";
}
}
getSuggestions(input_str) {
var _a, _b;
const { templateFolder, templaterPlugin } = getTemplatePlugins(this.app);
let files = [];
const lower_input_str = input_str.toLowerCase();
if ((!templateFolder || templateFolder.trim() === "") && !templaterPlugin) {
files = this.plugin.app.vault.getFiles().filter((file) => file.path.toLowerCase().includes(lower_input_str));
} else {
let folder = null;
if (templaterPlugin) {
folder = this.plugin.app.vault.getAbstractFileByPath((_b = (_a = templaterPlugin.plugin) == null ? void 0 : _a.settings) == null ? void 0 : _b.templates_folder);
if (!(folder instanceof import_obsidian21.TFolder)) {
return [
{
path: "",
name: "You need to set the Templates folder in the Templater settings first."
}
];
}
} else if (templateFolder) {
folder = this.plugin.app.vault.getAbstractFileByPath(templateFolder);
}
if (!(folder instanceof import_obsidian21.TFolder)) {
return [];
}
import_obsidian21.Vault.recurseChildren(folder, (file) => {
if (file instanceof import_obsidian21.TFile && file.path.toLowerCase().includes(lower_input_str)) {
files.push(file);
}
});
}
return files;
}
renderSuggestion(file, el) {
var _a, _b;
const { templateFolder, templaterPlugin } = getTemplatePlugins(this.app);
if ((!templateFolder || templateFolder.trim() === "") && !templaterPlugin) {
el.setText(`${((_a = file.parent) == null ? void 0 : _a.path) !== "/" ? ((_b = file.parent) == null ? void 0 : _b.path) + "/" : ""}${file.name}`);
} else {
el.setText(file.name);
}
}
selectSuggestion(file) {
this.inputEl.value = file.name.replace(".md", "");
this.inputEl.trigger("input");
this.plugin.settings.templatePath = file.path;
this.plugin.saveSettings();
this.close();
}
};
// src/settings/modals/BackupWarning.ts
var import_obsidian22 = require("obsidian");
var BackupWarningModal = class extends import_obsidian22.Modal {
constructor(plugin, title, description, callback, args = []) {
super(plugin.app);
this.plugin = plugin;
this.title = title;
this.callback = callback;
this.args = args;
this.desc = description;
}
onOpen() {
this.modalEl.addClass("fn-backup-warning-modal");
const { contentEl } = this;
contentEl.createEl("h2", { text: this.title });
contentEl.createEl("p", { text: this.desc });
contentEl.createEl("p", { text: "Make sure to backup your vault before using this feature." }).style.color = "#fb464c";
const buttonContainer = contentEl.createDiv({ cls: "fn-modal-button-container" });
const confirmButton = new import_obsidian22.ButtonComponent(buttonContainer);
confirmButton.setButtonText("Confirm").setCta().onClick(() => {
this.callback(...this.args);
this.close();
});
const cancelButton = new import_obsidian22.ButtonComponent(buttonContainer);
cancelButton.setButtonText("Cancel").onClick(() => {
this.close();
});
}
onClose() {
const { contentEl } = this;
contentEl.empty();
}
};
// src/settings/modals/RenameFns.ts
var import_obsidian23 = require("obsidian");
var RenameFolderNotesModal = class extends BackupWarningModal {
constructor(plugin, title, description, callback, args = []) {
super(plugin, title, description, callback, args);
}
insertCustomHtml() {
const { contentEl } = this;
new import_obsidian23.Setting(contentEl).setName("Old Folder Note Name").setDesc("Every folder note that matches this name will be renamed to the new folder note name.").addText((text) => text.setPlaceholder("Enter the old folder note name").setValue(this.plugin.settings.oldFolderNoteName || "").onChange(async (value) => {
this.plugin.settings.oldFolderNoteName = value;
}));
new import_obsidian23.Setting(contentEl).setName("New Folder Note Name").setDesc("Every folder note that matches the old folder note name will be renamed to this name.").addText((text) => text.setPlaceholder("Enter the new folder note name").setValue(this.plugin.settings.folderNoteName || "").onChange(async (value) => {
this.plugin.settings.folderNoteName = value;
this.plugin.settingsTab.display();
}));
}
};
// src/settings/GeneralSettings.ts
var debounceTimer;
async function renderGeneral(settingsTab) {
const containerEl = settingsTab.settingsPage;
const nameSetting = new import_obsidian24.Setting(containerEl).setName("Folder note name template").setDesc("All folder notes will use this name. Use {{folder_name}} to insert the folder\u2019s name. Existing notes won\u2019t update automatically; click on the button to apply the new name.").addText((text) => text.setValue(settingsTab.plugin.settings.folderNoteName).onChange(async (value) => {
if (value.trim() === "") {
return;
}
settingsTab.plugin.settings.folderNoteName = value;
await settingsTab.plugin.saveSettings();
clearTimeout(debounceTimer);
const FOLDER_NOTE_NAME_DEBOUNCE_MS = 2e3;
debounceTimer = setTimeout(() => {
if (!value.includes("{{folder_name}}")) {
if (!settingsTab.showFolderNameInTabTitleSetting) {
settingsTab.display();
settingsTab.showFolderNameInTabTitleSetting = true;
}
} else {
if (settingsTab.showFolderNameInTabTitleSetting) {
settingsTab.display();
settingsTab.showFolderNameInTabTitleSetting = false;
}
}
}, FOLDER_NOTE_NAME_DEBOUNCE_MS);
})).addButton((button) => button.setButtonText("Rename existing folder notes").setCta().onClick(async () => {
new RenameFolderNotesModal(settingsTab.plugin, "Rename all existing folder notes", 'When you click on "Confirm" all existing folder notes will be renamed to the new folder note name.', settingsTab.renameFolderNotes, []).open();
}));
nameSetting.infoEl.appendText("Requires a restart to take effect");
nameSetting.infoEl.style.color = settingsTab.app.vault.getConfig("accentColor") || "#7d5bed";
if (!settingsTab.plugin.settings.folderNoteName.includes("{{folder_name}}")) {
new import_obsidian24.Setting(containerEl).setName("Display Folder Name in Tab Title").setDesc('Use the actual folder name in the tab title instead of the custom folder note name (e.g., "Folder Note").').addToggle((toggle) => toggle.setValue(settingsTab.plugin.settings.tabManagerEnabled).onChange(async (value) => {
if (!value) {
settingsTab.plugin.tabManager.resetTabs();
} else {
settingsTab.plugin.settings.tabManagerEnabled = value;
settingsTab.plugin.tabManager.updateTabs();
}
settingsTab.plugin.settings.tabManagerEnabled = value;
await settingsTab.plugin.saveSettings();
settingsTab.display();
}));
}
new import_obsidian24.Setting(containerEl).setName("Default file type for new folder notes").setDesc("Choose the default file type (canvas, markdown, ...) used when creating new folder notes.").addDropdown((dropdown) => {
dropdown.addOption(".ask", "ask for file type");
settingsTab.plugin.settings.supportedFileTypes.forEach((type) => {
if (type === ".md" || type === "md") {
dropdown.addOption(".md", "markdown");
} else {
dropdown.addOption("." + type, type);
}
});
if (!settingsTab.plugin.settings.supportedFileTypes.includes(settingsTab.plugin.settings.folderNoteType.replace(".", "")) && settingsTab.plugin.settings.folderNoteType !== ".ask") {
settingsTab.plugin.settings.folderNoteType = ".md";
settingsTab.plugin.saveSettings();
}
let defaultType = settingsTab.plugin.settings.folderNoteType.startsWith(".") ? settingsTab.plugin.settings.folderNoteType : "." + settingsTab.plugin.settings.folderNoteType;
if (!settingsTab.plugin.settings.supportedFileTypes.includes(defaultType.replace(".", ""))) {
defaultType = ".ask";
settingsTab.plugin.settings.folderNoteType = defaultType;
}
dropdown.setValue(defaultType).onChange(async (value) => {
settingsTab.plugin.settings.folderNoteType = value;
settingsTab.plugin.saveSettings();
settingsTab.display();
});
});
const setting0 = new import_obsidian24.Setting(containerEl);
setting0.setName("Supported file types");
const desc0 = document.createDocumentFragment();
desc0.append("Specify which file types are allowed as folder notes. Applies to both new and existing folders. Adding many types may affect performance.");
setting0.setDesc(desc0);
const list = new ListComponent(setting0.settingEl, settingsTab.plugin.settings.supportedFileTypes || [], ["md", "canvas"]);
list.on("update", async (values) => {
settingsTab.plugin.settings.supportedFileTypes = values;
await settingsTab.plugin.saveSettings();
settingsTab.display();
});
if (!settingsTab.plugin.settings.supportedFileTypes.includes("md") || !settingsTab.plugin.settings.supportedFileTypes.includes("canvas") || !settingsTab.plugin.settings.supportedFileTypes.includes("excalidraw")) {
setting0.addDropdown((dropdown) => {
const options = [
{ value: "md", label: "Markdown" },
{ value: "canvas", label: "Canvas" },
{ value: "base", label: "Bases" },
{ value: "excalidraw", label: "Excalidraw" },
{ value: "custom", label: "Custom extension" }
];
options.forEach((option) => {
var _a;
if (!((_a = settingsTab.plugin.settings.supportedFileTypes) == null ? void 0 : _a.includes(option.value))) {
dropdown.addOption(option.value, option.label);
}
});
dropdown.addOption("+", "+");
dropdown.setValue("+");
dropdown.onChange(async (value) => {
if (value === "custom") {
return new AddSupportedFileModal(settingsTab.app, settingsTab.plugin, settingsTab, list).open();
}
await list.addValue(value.toLowerCase());
settingsTab.display();
settingsTab.plugin.saveSettings();
});
});
} else {
setting0.addButton((button) => button.setButtonText("Add custom file type").setCta().onClick(async () => {
new AddSupportedFileModal(settingsTab.app, settingsTab.plugin, settingsTab, list).open();
}));
}
const templateSetting = new import_obsidian24.Setting(containerEl).setDesc("Can be used with templater/templates plugin. If you add the location of the templates there.").setName("Template path").addSearch((cb) => {
new TemplateSuggest(cb.inputEl, settingsTab.plugin);
cb.setPlaceholder("Template path");
const templateFile = settingsTab.plugin.app.vault.getAbstractFileByPath(settingsTab.plugin.settings.templatePath);
const templateName = (templateFile == null ? void 0 : templateFile.name.replace(".md", "")) || "";
cb.setValue(templateName);
cb.onChange(async (value) => {
if (value.trim() === "") {
settingsTab.plugin.settings.templatePath = "";
await settingsTab.plugin.saveSettings();
settingsTab.display();
return;
}
});
});
templateSetting.infoEl.appendText("Requires a restart to take effect");
templateSetting.infoEl.style.color = settingsTab.app.vault.getConfig("accentColor") || "#7d5bed";
const storageLocation = new import_obsidian24.Setting(containerEl).setName("Storage location").setDesc("Choose where to store the folder notes").addDropdown((dropdown) => dropdown.addOption("insideFolder", "Inside the folder").addOption("parentFolder", "In the parent folder").setValue(settingsTab.plugin.settings.storageLocation).onChange(async (value) => {
settingsTab.plugin.settings.storageLocation = value;
await settingsTab.plugin.saveSettings();
settingsTab.display();
refreshAllFolderStyles(void 0, settingsTab.plugin);
})).addButton((button) => button.setButtonText("Switch").setCta().onClick(async () => {
let oldStorageLocation = settingsTab.plugin.settings.storageLocation;
if (settingsTab.plugin.settings.storageLocation === "parentFolder") {
oldStorageLocation = "insideFolder";
} else if (settingsTab.plugin.settings.storageLocation === "insideFolder") {
oldStorageLocation = "parentFolder";
}
new BackupWarningModal(settingsTab.plugin, "Switch storage location", 'When you click on "Confirm" all folder notes will be moved to the new storage location.', settingsTab.switchStorageLocation, [oldStorageLocation]).open();
}));
storageLocation.infoEl.appendText("Requires a restart to take effect");
storageLocation.infoEl.style.color = settingsTab.app.vault.getConfig("accentColor") || "#7d5bed";
if (settingsTab.plugin.settings.storageLocation === "parentFolder") {
new import_obsidian24.Setting(containerEl).setName("Delete folder notes when deleting the folder").setDesc("Delete the folder note when deleting the folder").addToggle((toggle) => toggle.setValue(settingsTab.plugin.settings.syncDelete).onChange(async (value) => {
settingsTab.plugin.settings.syncDelete = value;
await settingsTab.plugin.saveSettings();
}));
new import_obsidian24.Setting(containerEl).setName("Move folder notes when moving the folder").setDesc("Move the folder note file along with the folder when it is moved").addToggle((toggle) => toggle.setValue(settingsTab.plugin.settings.syncMove).onChange(async (value) => {
settingsTab.plugin.settings.syncMove = value;
await settingsTab.plugin.saveSettings();
}));
}
if (import_obsidian24.Platform.isDesktopApp) {
settingsTab.settingsPage.createEl("h3", { text: "Keyboard Shortcuts" });
new import_obsidian24.Setting(containerEl).setName("Key for creating folder note").setDesc("The key combination to create a folder note").addDropdown((dropdown) => {
if (!import_obsidian24.Platform.isMacOS) {
dropdown.addOption("ctrl", "Ctrl + Click");
dropdown.addOption("alt", "Alt + Click");
} else {
dropdown.addOption("ctrl", "Cmd + Click");
dropdown.addOption("alt", "Option + Click");
}
dropdown.setValue(settingsTab.plugin.settings.ctrlKey ? "ctrl" : "alt");
dropdown.onChange(async (value) => {
settingsTab.plugin.settings.ctrlKey = value === "ctrl";
settingsTab.plugin.settings.altKey = value === "alt";
await settingsTab.plugin.saveSettings();
settingsTab.display();
});
});
new import_obsidian24.Setting(containerEl).setName("Key for opening folder note").setDesc("Select the combination to open a folder note").addDropdown((dropdown) => {
dropdown.addOption("click", "Mouse Click");
if (!import_obsidian24.Platform.isMacOS) {
dropdown.addOption("ctrl", "Ctrl + Click");
dropdown.addOption("alt", "Alt + Click");
} else {
dropdown.addOption("ctrl", "Cmd + Click");
dropdown.addOption("alt", "Option + Click");
}
if (settingsTab.plugin.settings.openByClick) {
dropdown.setValue("click");
} else if (settingsTab.plugin.settings.openWithCtrl) {
dropdown.setValue("ctrl");
} else {
dropdown.setValue("alt");
}
dropdown.onChange(async (value) => {
settingsTab.plugin.settings.openByClick = value === "click";
settingsTab.plugin.settings.openWithCtrl = value === "ctrl";
settingsTab.plugin.settings.openWithAlt = value === "alt";
await settingsTab.plugin.saveSettings();
settingsTab.display();
});
});
}
settingsTab.settingsPage.createEl("h3", { text: "Folder note behavior" });
new import_obsidian24.Setting(containerEl).setName("Confirm folder note deletion").setDesc("Ask for confirmation before deleting a folder note").addToggle((toggle) => toggle.setValue(settingsTab.plugin.settings.showDeleteConfirmation).onChange(async (value) => {
settingsTab.plugin.settings.showDeleteConfirmation = value;
await settingsTab.plugin.saveSettings();
settingsTab.display();
}));
new import_obsidian24.Setting(containerEl).setName("Deleted folder notes").setDesc("What happens to the folder note after you delete it").addDropdown((dropdown) => {
dropdown.addOption("trash", "Move to system trash");
dropdown.addOption("obsidianTrash", "Move to Obsidian trash (.trash folder)");
dropdown.addOption("delete", "Delete permanently");
dropdown.setValue(settingsTab.plugin.settings.deleteFilesAction);
dropdown.onChange(async (value) => {
settingsTab.plugin.settings.deleteFilesAction = value;
await settingsTab.plugin.saveSettings();
settingsTab.display();
});
});
if (import_obsidian24.Platform.isDesktop) {
const setting3 = new import_obsidian24.Setting(containerEl);
setting3.setName("Open folder note in a new tab by default");
setting3.setDesc("Always open folder notes in a new tab unless the note is already open in the current tab.");
setting3.addToggle((toggle) => toggle.setValue(settingsTab.plugin.settings.openInNewTab).onChange(async (value) => {
settingsTab.plugin.settings.openInNewTab = value;
await settingsTab.plugin.saveSettings();
settingsTab.display();
}));
setting3.infoEl.appendText("Requires a restart to take effect");
setting3.infoEl.style.color = settingsTab.app.vault.getConfig("accentColor") || "#7d5bed";
}
if (settingsTab.plugin.settings.openInNewTab) {
new import_obsidian24.Setting(containerEl).setName("Focus existing tab instead of creating a new one").setDesc("If a folder note is already open in a tab, focus that tab instead of creating a new one.").addToggle((toggle) => toggle.setValue(settingsTab.plugin.settings.focusExistingTab).onChange(async (value) => {
settingsTab.plugin.settings.focusExistingTab = value;
await settingsTab.plugin.saveSettings();
settingsTab.display();
}));
}
new import_obsidian24.Setting(containerEl).setName("Sync folder name").setDesc("Automatically rename the folder note when the folder name is changed").addToggle((toggle) => toggle.setValue(settingsTab.plugin.settings.syncFolderName).onChange(async (value) => {
settingsTab.plugin.settings.syncFolderName = value;
await settingsTab.plugin.saveSettings();
settingsTab.display();
}));
settingsTab.settingsPage.createEl("h4", { text: "Automation settings" });
new import_obsidian24.Setting(containerEl).setName("Create folder notes for all folders").setDesc("Generate folder notes for every folder in the vault.").addButton((cb) => {
cb.setIcon("plus");
cb.setTooltip("Create folder notes");
cb.onClick(async () => {
new ConfirmationModal(settingsTab.app, settingsTab.plugin).open();
});
});
new import_obsidian24.Setting(containerEl).setName("Auto-create on folder creation").setDesc("Automatically create a folder note whenever a new folder is added.").addToggle((toggle) => toggle.setValue(settingsTab.plugin.settings.autoCreate).onChange(async (value) => {
settingsTab.plugin.settings.autoCreate = value;
await settingsTab.plugin.saveSettings();
settingsTab.display();
}));
if (settingsTab.plugin.settings.autoCreate) {
new import_obsidian24.Setting(containerEl).setName("Auto-open after creation").setDesc("Open the folder note immediately after it\u2019s created automatically.").addToggle((toggle) => toggle.setValue(settingsTab.plugin.settings.autoCreateFocusFiles).onChange(async (value) => {
settingsTab.plugin.settings.autoCreateFocusFiles = value;
await settingsTab.plugin.saveSettings();
settingsTab.display();
}));
new import_obsidian24.Setting(containerEl).setName("Auto-create for attachment folders").setDesc('Also automatically create folder notes for attachment folders (e.g., "Attachments", "Media", etc.).').addToggle((toggle) => toggle.setValue(settingsTab.plugin.settings.autoCreateForAttachmentFolder).onChange(async (value) => {
settingsTab.plugin.settings.autoCreateForAttachmentFolder = value;
await settingsTab.plugin.saveSettings();
settingsTab.display();
}));
}
new import_obsidian24.Setting(containerEl).setName("Auto-create when creating notes").setDesc("Automatically create a folder note when a regular note is created inside a folder. Works for supported file types only.").addToggle((toggle) => toggle.setValue(settingsTab.plugin.settings.autoCreateForFiles).onChange(async (value) => {
settingsTab.plugin.settings.autoCreateForFiles = value;
await settingsTab.plugin.saveSettings();
settingsTab.display();
}));
settingsTab.settingsPage.createEl("h3", { text: "Integration & Compatibility" });
const desc1 = document.createDocumentFragment();
const link = document.createElement("a");
link.href = "https://github.com/snezhig/obsidian-front-matter-title";
link.textContent = "front matter title plugin";
link.target = "_blank";
desc1.append("Allows you to use the ", link, " with folder notes. It allows you to set the folder name to some name you set in the front matter.");
const fmtpSetting = new import_obsidian24.Setting(containerEl).setName("Enable front matter title plugin integration").setDesc(desc1).addToggle((toggle) => toggle.setValue(settingsTab.plugin.settings.frontMatterTitle.enabled).onChange(async (value) => {
var _a;
settingsTab.plugin.settings.frontMatterTitle.enabled = value;
await settingsTab.plugin.saveSettings();
if (value) {
settingsTab.plugin.fmtpHandler = new FrontMatterTitlePluginHandler(settingsTab.plugin);
} else {
if (settingsTab.plugin.fmtpHandler) {
settingsTab.plugin.updateAllBreadcrumbs(true);
}
settingsTab.plugin.app.vault.getFiles().forEach((file) => {
var _a2;
(_a2 = settingsTab.plugin.fmtpHandler) == null ? void 0 : _a2.fmptUpdateFileName({
id: "",
result: false,
path: file.path,
pathOnly: false
}, false);
});
(_a = settingsTab.plugin.fmtpHandler) == null ? void 0 : _a.deleteEvent();
settingsTab.plugin.fmtpHandler = new FrontMatterTitlePluginHandler(settingsTab.plugin);
}
settingsTab.display();
}));
fmtpSetting.infoEl.appendText("Requires a restart to take effect");
fmtpSetting.infoEl.style.color = settingsTab.app.vault.getConfig("accentColor") || "#7d5bed";
settingsTab.settingsPage.createEl("h3", { text: "Session & Persistence" });
new import_obsidian24.Setting(containerEl).setName("Persist tab after restart").setDesc("Restore the same settings tab after restarting Obsidian.").addToggle((toggle) => toggle.setValue(settingsTab.plugin.settings.persistentSettingsTab.afterRestart).onChange(async (value) => {
settingsTab.plugin.settings.persistentSettingsTab.afterRestart = value;
await settingsTab.plugin.saveSettings();
settingsTab.display();
}));
new import_obsidian24.Setting(containerEl).setName("Persist tab during session only").setDesc("Keep the current settings tab open during the session, but reset it after a restart or reload.").addToggle((toggle) => toggle.setValue(settingsTab.plugin.settings.persistentSettingsTab.afterChangingTab).onChange(async (value) => {
settingsTab.plugin.settings.persistentSettingsTab.afterChangingTab = value;
await settingsTab.plugin.saveSettings();
settingsTab.display();
}));
}
// src/settings/FileExplorerSettings.ts
var import_obsidian25 = require("obsidian");
async function renderFileExplorer(settingsTab) {
const containerEl = settingsTab.settingsPage;
new import_obsidian25.Setting(containerEl).setName("Hide folder note").setDesc("Hide the folder note file from appearing in the file explorer").addToggle((toggle) => toggle.setValue(settingsTab.plugin.settings.hideFolderNote).onChange(async (value) => {
settingsTab.plugin.settings.hideFolderNote = value;
await settingsTab.plugin.saveSettings();
if (value) {
document.body.classList.add("hide-folder-note");
} else {
document.body.classList.remove("hide-folder-note");
}
settingsTab.display();
}));
const setting2 = new import_obsidian25.Setting(containerEl).setName("Disable click-to-open folder note on mobile").setDesc("Prevents folder notes from opening when tapping the folder name or surrounding area on mobile devices. They can now only be opened via the context menu or a command.").addToggle((toggle) => toggle.setValue(settingsTab.plugin.settings.disableOpenFolderNoteOnClick).onChange(async (value) => {
settingsTab.plugin.settings.disableOpenFolderNoteOnClick = value;
await settingsTab.plugin.saveSettings();
}));
setting2.infoEl.appendText("Requires a restart to take effect");
const setting2AccentColor = settingsTab.app.vault.getConfig("accentColor") || "#7d5bed";
setting2.infoEl.style.color = setting2AccentColor;
new import_obsidian25.Setting(containerEl).setName("Open folder notes by only clicking directly on the folder name").setDesc("Only allow folder notes to open when clicking directly on the folder name in the file explorer").addToggle((toggle) => toggle.setValue(!settingsTab.plugin.settings.stopWhitespaceCollapsing).onChange(async (value) => {
if (!value) {
document.body.classList.add("fn-whitespace-stop-collapsing");
} else {
document.body.classList.remove("fn-whitespace-stop-collapsing");
}
settingsTab.plugin.settings.stopWhitespaceCollapsing = !value;
await settingsTab.plugin.saveSettings();
}));
const disableSetting = new import_obsidian25.Setting(containerEl);
disableSetting.setName("Disable folder collapsing");
disableSetting.setDesc("When enabled, folders in the file explorer will only collapse when clicking the collapse icon next to the folder name, not when clicking near a folder name when it has a folder note.");
disableSetting.addToggle((toggle) => toggle.setValue(!settingsTab.plugin.settings.enableCollapsing).onChange(async (value) => {
settingsTab.plugin.settings.enableCollapsing = !value;
await settingsTab.plugin.saveSettings();
}));
disableSetting.infoEl.appendText("Requires a restart to take effect");
const accentColor = settingsTab.app.vault.getConfig("accentColor") || "#7d5bed";
disableSetting.infoEl.style.color = accentColor;
new import_obsidian25.Setting(containerEl).setName("Use submenus").setDesc("Use submenus for file/folder commands").addToggle((toggle) => toggle.setValue(settingsTab.plugin.settings.useSubmenus).onChange(async (value) => {
settingsTab.plugin.settings.useSubmenus = value;
await settingsTab.plugin.saveSettings();
settingsTab.display();
}));
if (settingsTab.plugin.settings.frontMatterTitle.enabled) {
new import_obsidian25.Setting(containerEl).setName("Auto update folder name in the file explorer (front matter title plugin only)").setDesc("Automatically update the folder name in the file explorer when the front matter title plugin is enabled and the title for a folder note is changed in the front matter. This will not change the file name, only the displayed name in the file explorer.").addToggle((toggle) => toggle.setValue(settingsTab.plugin.settings.frontMatterTitle.explorer).onChange(async (value) => {
settingsTab.plugin.settings.frontMatterTitle.explorer = value;
await settingsTab.plugin.saveSettings();
settingsTab.plugin.app.vault.getFiles().forEach((file) => {
var _a;
(_a = settingsTab.plugin.fmtpHandler) == null ? void 0 : _a.fmptUpdateFileName({
id: "",
result: false,
path: file.path,
pathOnly: false
}, false);
});
}));
}
settingsTab.settingsPage.createEl("h3", { text: "Style settings" });
new import_obsidian25.Setting(containerEl).setName("Highlight folder in the file explorer").setDesc("Highlight the folder in the file explorer when it has a folder note and the folder note is open in the editor").addToggle((toggle) => toggle.setValue(settingsTab.plugin.settings.highlightFolder).onChange(async (value) => {
settingsTab.plugin.settings.highlightFolder = value;
if (!value) {
document.body.classList.add("disable-folder-highlight");
} else {
document.body.classList.remove("disable-folder-highlight");
}
await settingsTab.plugin.saveSettings();
}));
new import_obsidian25.Setting(containerEl).setName("Hide collapse icon").setDesc("Hide the collapse icon in the file explorer next to the name of a folder when a folder only contains a folder note").addToggle((toggle) => toggle.setValue(settingsTab.plugin.settings.hideCollapsingIcon).onChange(async (value) => {
settingsTab.plugin.settings.hideCollapsingIcon = value;
if (value) {
document.body.classList.add("fn-hide-collapse-icon");
} else {
document.body.classList.remove("fn-hide-collapse-icon");
}
await settingsTab.plugin.saveSettings();
settingsTab.display();
}));
new import_obsidian25.Setting(containerEl).setName("Hide collapse icon for every empty folder").setDesc("Hide the collapse icon in the file explorer next to the name of a folder when a folder is empty").addToggle((toggle) => toggle.setValue(settingsTab.plugin.settings.hideCollapsingIconForEmptyFolders).onChange(async (value) => {
settingsTab.plugin.settings.hideCollapsingIconForEmptyFolders = value;
await settingsTab.plugin.saveSettings();
if (value) {
document.body.classList.add("fn-hide-empty-collapse-icon");
} else {
document.body.classList.remove("fn-hide-empty-collapse-icon");
}
settingsTab.display();
}));
if (settingsTab.plugin.settings.hideCollapsingIcon) {
new import_obsidian25.Setting(containerEl).setName("Hide collapse icon also when only the attachment folder is in the same folder").addToggle((toggle) => toggle.setValue(settingsTab.plugin.settings.ignoreAttachmentFolder).onChange(async (value) => {
if (value) {
document.body.classList.add("fn-ignore-attachment-folder");
} else {
document.body.classList.remove("fn-ignore-attachment-folder");
}
settingsTab.plugin.settings.ignoreAttachmentFolder = value;
await settingsTab.plugin.saveSettings();
}));
}
new import_obsidian25.Setting(containerEl).setName("Underline the name of folder notes").setDesc("Add an underline to folders that have a folder note in the file explorer").addToggle((toggle) => toggle.setValue(settingsTab.plugin.settings.underlineFolder).onChange(async (value) => {
settingsTab.plugin.settings.underlineFolder = value;
if (value) {
document.body.classList.add("folder-note-underline");
} else {
document.body.classList.remove("folder-note-underline");
}
await settingsTab.plugin.saveSettings();
}));
new import_obsidian25.Setting(containerEl).setName("Bold the name of folder notes").setDesc("Make the folder name bold in the file explorer when it has a folder note").addToggle((toggle) => toggle.setValue(settingsTab.plugin.settings.boldName).onChange(async (value) => {
settingsTab.plugin.settings.boldName = value;
if (value) {
document.body.classList.add("folder-note-bold");
} else {
document.body.classList.remove("folder-note-bold");
}
await settingsTab.plugin.saveSettings();
}));
new import_obsidian25.Setting(containerEl).setName("Cursive the name of folder notes").setDesc("Make the folder name cursive in the file explorer when it has a folder note").addToggle((toggle) => toggle.setValue(settingsTab.plugin.settings.cursiveName).onChange(async (value) => {
settingsTab.plugin.settings.cursiveName = value;
if (value) {
document.body.classList.add("folder-note-cursive");
} else {
document.body.classList.remove("folder-note-cursive");
}
await settingsTab.plugin.saveSettings();
}));
}
// src/settings/PathSettings.ts
var import_obsidian26 = require("obsidian");
async function renderPath(settingsTab) {
const containerEl = settingsTab.settingsPage;
new import_obsidian26.Setting(containerEl).setName("Open folder note through path").setDesc("Open a folder note when clicking on a folder name in the path if it is a folder note").addToggle((toggle) => toggle.setValue(settingsTab.plugin.settings.openFolderNoteOnClickInPath).onChange(async (value) => {
settingsTab.plugin.settings.openFolderNoteOnClickInPath = value;
await settingsTab.plugin.saveSettings();
settingsTab.display();
}));
if (settingsTab.plugin.settings.openFolderNoteOnClickInPath) {
new import_obsidian26.Setting(containerEl).setName("Open sidebar when opening a folder note through path (Mobile only)").setDesc("Open the sidebar when opening a folder note through the path on mobile").addToggle((toggle) => toggle.setValue(settingsTab.plugin.settings.openSidebar.mobile).onChange(async (value) => {
settingsTab.plugin.settings.openSidebar.mobile = value;
await settingsTab.plugin.saveSettings();
}));
new import_obsidian26.Setting(containerEl).setName("Open sidebar when opening a folder note through path (Desktop only)").setDesc("Open the sidebar when opening a folder note through the path on desktop").addToggle((toggle) => toggle.setValue(settingsTab.plugin.settings.openSidebar.desktop).onChange(async (value) => {
settingsTab.plugin.settings.openSidebar.desktop = value;
await settingsTab.plugin.saveSettings();
}));
}
if (settingsTab.plugin.settings.frontMatterTitle.enabled) {
new import_obsidian26.Setting(containerEl).setName("Auto update folder name in the path (front matter title plugin only)").setDesc("Automatically update the folder name in the path when the front matter title plugin is enabled and the title for a folder note is changed in the front matter. This will not change the file name, only the displayed name in the path.").addToggle((toggle) => toggle.setValue(settingsTab.plugin.settings.frontMatterTitle.path).onChange(async (value) => {
settingsTab.plugin.settings.frontMatterTitle.path = value;
await settingsTab.plugin.saveSettings();
if (value) {
settingsTab.plugin.updateAllBreadcrumbs();
} else {
settingsTab.plugin.updateAllBreadcrumbs(true);
}
}));
}
settingsTab.settingsPage.createEl("h3", { text: "Style settings" });
new import_obsidian26.Setting(containerEl).setName("Underline folders in the path").setDesc("Add an underline to folders that have a folder note in the path above a note").addToggle((toggle) => toggle.setValue(settingsTab.plugin.settings.underlineFolderInPath).onChange(async (value) => {
settingsTab.plugin.settings.underlineFolderInPath = value;
if (value) {
document.body.classList.add("folder-note-underline-path");
} else {
document.body.classList.remove("folder-note-underline-path");
}
await settingsTab.plugin.saveSettings();
}));
new import_obsidian26.Setting(containerEl).setName("Bold folders in the path").setDesc("Make the folder name bold in the path above a note when it has a folder note").addToggle((toggle) => toggle.setValue(settingsTab.plugin.settings.boldNameInPath).onChange(async (value) => {
settingsTab.plugin.settings.boldNameInPath = value;
if (value) {
document.body.classList.add("folder-note-bold-path");
} else {
document.body.classList.remove("folder-note-bold-path");
}
await settingsTab.plugin.saveSettings();
}));
new import_obsidian26.Setting(containerEl).setName("Cursive the name of folder notes in the path").setDesc("Make the folder name cursive in the path above a note when it has a folder note").addToggle((toggle) => toggle.setValue(settingsTab.plugin.settings.cursiveNameInPath).onChange(async (value) => {
settingsTab.plugin.settings.cursiveNameInPath = value;
if (value) {
document.body.classList.add("folder-note-cursive-path");
} else {
document.body.classList.remove("folder-note-cursive-path");
}
await settingsTab.plugin.saveSettings();
}));
}
// src/settings/FolderOverviewSettings.ts
var import_obsidian37 = require("obsidian");
// src/obsidian-folder-overview/src/settings.ts
var import_obsidian36 = require("obsidian");
// src/obsidian-folder-overview/src/FolderOverview.ts
var import_obsidian33 = require("obsidian");
// src/obsidian-folder-overview/src/modals/Settings.ts
var import_obsidian29 = require("obsidian");
// src/obsidian-folder-overview/src/utils/LinkList.ts
var import_obsidian27 = require("obsidian");
function buildLinkListBlock(id, calloutFlag) {
if (calloutFlag) {
return '\n> <span class="fv-link-list-start" id="' + id + '"></span>\n> <span class="fv-link-list-end" id="' + id + '"></span>';
}
return '\n<span class="fv-link-list-start" id="' + id + '"></span>\n<span class="fv-link-list-end" id="' + id + '"></span>';
}
function updateLinkList(files = [], plugin, yaml, pathBlacklist, sourceFile) {
buildLinkList(files, plugin, yaml, pathBlacklist, sourceFile).then((fileLinks) => {
plugin.app.vault.process(sourceFile, (text) => {
const lines = text.split("\n");
const linkListStart = `${yaml.isInCallout ? "> " : ""}<span class="fv-link-list-start" id="${yaml.id}"></span>`;
const linkListEnd = `${yaml.isInCallout ? "> " : ""}<span class="fv-link-list-end" id="${yaml.id}"></span>`;
const startIdx = lines.findIndex((l) => l.trim() === linkListStart);
const endIdx = lines.findIndex((l) => l.trim() === linkListEnd);
const NOT_FOUND = -1;
const linkListExists = startIdx !== NOT_FOUND && endIdx !== NOT_FOUND;
const isInvalidLinkList = endIdx < startIdx;
if (!linkListExists || isInvalidLinkList) {
return text;
}
lines.splice(startIdx, endIdx - startIdx + 1);
const newBlock = [
linkListStart,
...fileLinks,
linkListEnd
];
lines.splice(startIdx, 0, ...newBlock);
return lines.join("\n");
});
});
}
async function buildLinkList(items, plugin, yaml, pathBlacklist, sourceFile, indent = 0) {
const result = [];
const filtered = (await filterFiles(items, plugin, yaml.folderPath, yaml.depth, pathBlacklist, yaml, sourceFile)).filter((file) => file !== null);
const sorted = sortFiles(filtered, yaml, plugin);
for (const item of sorted) {
const indentStr = " ".repeat(indent);
if (item instanceof import_obsidian27.TFile) {
result.push(buildFileLinkListLine(item, yaml, indentStr));
} else if (item instanceof import_obsidian27.TFolder) {
const folderLines = await buildFolderLinkListLines(item, plugin, yaml, pathBlacklist, sourceFile, indentStr, indent);
result.push(...folderLines);
}
}
return result;
}
function buildFileLinkListLine(item, yaml, indentStr) {
const prefix = yaml.isInCallout ? "> " : "";
const base = `${prefix}${indentStr}- [[${item.path}|${item.basename}]]`;
if (yaml.hideLinkList) {
return base + ' <span class="fv-link-list-item"></span>';
}
return base;
}
async function buildFolderLinkListLines(item, plugin, yaml, pathBlacklist, sourceFile, indentStr, indent) {
const lines = [];
const prefix = yaml.isInCallout ? "> " : "";
let line = `${prefix}${indentStr}- ${item.name}`;
let folderNote = null;
if (plugin instanceof FolderNotesPlugin) {
folderNote = getFolderNote(plugin, item.path);
}
if (folderNote) {
line = `${prefix}${indentStr}- [[${folderNote.path}|${item.name}]]`;
}
if (yaml.hideLinkList) {
line += ' <span class="fv-link-list-item"></span>';
}
lines.push(line);
const children = item.children.filter((child) => !(child instanceof import_obsidian27.TFile && folderNote && child.path === folderNote.path));
if (children.length > 0) {
const childLinks = await buildLinkList(children, plugin, yaml, pathBlacklist, sourceFile, indent + 1);
lines.push(...childLinks);
}
return lines;
}
function removeLinkList(plugin, sourceFile, yaml) {
if (sourceFile) {
plugin.app.vault.process(sourceFile, (text) => {
const lines = text.split("\n");
const linkListStart = `${yaml.isInCallout ? "> " : ""}<span class="fv-link-list-start" id="${yaml.id}"></span>`;
const linkListEnd = `${yaml.isInCallout ? "> " : ""}<span class="fv-link-list-end" id="${yaml.id}"></span>`;
const startIdx = lines.findIndex((l) => l.trim() === linkListStart);
const endIdx = lines.findIndex((l) => l.trim() === linkListEnd);
const NOT_FOUND = -1;
const linkListExists = startIdx !== NOT_FOUND && endIdx !== NOT_FOUND;
const isInvalidLinkList = endIdx < startIdx;
if (!linkListExists || isInvalidLinkList) {
return text;
}
lines.splice(startIdx, endIdx - startIdx + 1);
return lines.join("\n");
});
}
}
// src/obsidian-folder-overview/src/utils/functions.ts
var import_obsidian28 = require("obsidian");
function getFolderPathFromString2(path) {
const subString = path.lastIndexOf("/") >= 0 ? path.lastIndexOf("/") : 0;
const folderPath = path.substring(0, subString);
if (folderPath === "") {
return "/";
} else {
return folderPath;
}
}
var CODE_BLOCK_END_NOT_FOUND = -1;
var MAX_CODE_BLOCK_SEARCH_COUNT = 50;
function getCodeBlockEndLine(text, startLine, count = 1) {
let line = startLine + 1;
const lines = text.split("\n");
while (line < lines.length) {
if (count > MAX_CODE_BLOCK_SEARCH_COUNT) {
return CODE_BLOCK_END_NOT_FOUND;
}
if (lines[line].startsWith("```")) {
return line;
}
line++;
count++;
}
return line;
}
async function updateAllOverviews(plugin) {
const filePaths = await plugin.fvIndexDB.getAllNotes();
if (filePaths.length === 0)
return;
filePaths.forEach(async (filePath) => {
const file = plugin.app.vault.getAbstractFileByPath(filePath);
if (!(file instanceof import_obsidian28.TFile)) {
plugin.fvIndexDB.removeNote(filePath);
return;
}
if (!hasOverviewYaml(this, file)) {
plugin.fvIndexDB.removeNote(file.path);
return;
}
const overviews = await getOverviews(this, file);
overviews.forEach(async (overview) => {
if (!overview.useActualLinks)
return;
let files = [];
let sourceFolderPath = overview.folderPath.trim();
if (!sourceFolderPath.includes("/")) {
sourceFolderPath = "/";
}
const sourceFolder = this.app.vault.getAbstractFileByPath(sourceFolderPath);
if (!(sourceFolder instanceof import_obsidian28.TFolder) && sourceFolderPath !== "/") {
return;
}
if ((sourceFolder == null ? void 0 : sourceFolder.path) === "/") {
const rootFiles = [];
plugin.app.vault.getAllLoadedFiles().filter((f) => {
var _a;
return ((_a = f.parent) == null ? void 0 : _a.path) === "/";
}).forEach((f) => {
if (!f.path.includes("/")) {
rootFiles.push(f);
}
});
files = rootFiles;
} else if (sourceFolder instanceof import_obsidian28.TFolder) {
files = sourceFolder.children;
}
files = getAllFiles(files, sourceFolderPath, overview.depth);
const filteredFiles = await filterFiles(files, this, sourceFolderPath, overview.depth, [], overview, file);
files = filteredFiles.filter((f) => f !== null);
if (!overview.includeTypes.includes("folder")) {
files = getAllFiles(files, sourceFolderPath, overview.depth);
}
files = sortFiles(files, overview, this);
updateLinkList(files, this, overview, [], file);
});
});
}
function buildYamlConfig(yaml, defaultSettings, ctx, includeTypesParam) {
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x;
return {
id: (_a = yaml == null ? void 0 : yaml.id) != null ? _a : crypto.randomUUID(),
folderPath: (_c = (_b = yaml == null ? void 0 : yaml.folderPath) == null ? void 0 : _b.trim()) != null ? _c : getFolderPathFromString2(ctx.sourcePath),
title: (_d = yaml == null ? void 0 : yaml.title) != null ? _d : defaultSettings.title,
showTitle: (_e = yaml == null ? void 0 : yaml.showTitle) != null ? _e : defaultSettings.showTitle,
depth: (_f = yaml == null ? void 0 : yaml.depth) != null ? _f : defaultSettings.depth,
style: (_g = yaml == null ? void 0 : yaml.style) != null ? _g : "list",
includeTypes: includeTypesParam.map((type) => type.toLowerCase()),
disableFileTag: (_h = yaml == null ? void 0 : yaml.disableFileTag) != null ? _h : defaultSettings.disableFileTag,
sortBy: (_i = yaml == null ? void 0 : yaml.sortBy) != null ? _i : defaultSettings.sortBy,
sortByAsc: (_j = yaml == null ? void 0 : yaml.sortByAsc) != null ? _j : defaultSettings.sortByAsc,
showEmptyFolders: (_k = yaml == null ? void 0 : yaml.showEmptyFolders) != null ? _k : defaultSettings.showEmptyFolders,
onlyIncludeSubfolders: (_l = yaml == null ? void 0 : yaml.onlyIncludeSubfolders) != null ? _l : defaultSettings.onlyIncludeSubfolders,
storeFolderCondition: (_m = yaml == null ? void 0 : yaml.storeFolderCondition) != null ? _m : defaultSettings.storeFolderCondition,
showFolderNotes: (_n = yaml == null ? void 0 : yaml.showFolderNotes) != null ? _n : defaultSettings.showFolderNotes,
disableCollapseIcon: (_o = yaml == null ? void 0 : yaml.disableCollapseIcon) != null ? _o : defaultSettings.disableCollapseIcon,
alwaysCollapse: (_p = yaml == null ? void 0 : yaml.alwaysCollapse) != null ? _p : defaultSettings.alwaysCollapse,
autoSync: (_q = yaml == null ? void 0 : yaml.autoSync) != null ? _q : defaultSettings.autoSync,
allowDragAndDrop: (_r = yaml == null ? void 0 : yaml.allowDragAndDrop) != null ? _r : defaultSettings.allowDragAndDrop,
hideLinkList: (_s = yaml == null ? void 0 : yaml.hideLinkList) != null ? _s : defaultSettings.hideLinkList,
hideFolderOverview: (_t = yaml == null ? void 0 : yaml.hideFolderOverview) != null ? _t : defaultSettings.hideFolderOverview,
useActualLinks: (_u = yaml == null ? void 0 : yaml.useActualLinks) != null ? _u : defaultSettings.useActualLinks,
fmtpIntegration: (_v = yaml == null ? void 0 : yaml.fmtpIntegration) != null ? _v : defaultSettings.fmtpIntegration,
titleSize: (_w = yaml == null ? void 0 : yaml.titleSize) != null ? _w : defaultSettings.titleSize,
isInCallout: (_x = yaml == null ? void 0 : yaml.isInCallout) != null ? _x : false
};
}
async function updateYamlById(plugin, overviewId, file, newYaml, addLinkList, isCallout = false) {
await plugin.app.vault.process(file, (text) => {
const yamlBlocks = getYamlBlocks(text, isCallout);
if (!yamlBlocks)
return text;
for (const block of yamlBlocks) {
const cleanedBlock = cleanYamlBlock(block, isCallout);
const yaml = (0, import_obsidian28.parseYaml)(cleanedBlock);
if (!yaml)
continue;
if (yaml.id === overviewId) {
let stringYaml = (0, import_obsidian28.stringifyYaml)(newYaml);
if (stringYaml[stringYaml.length - 1] !== "\n") {
stringYaml += "\n";
}
let newBlock = buildNewBlock(stringYaml, isCallout);
if (addLinkList && !isCallout) {
newBlock += buildLinkListBlock(newYaml.id, false);
} else if (addLinkList && isCallout) {
newBlock += buildLinkListBlock(newYaml.id, true);
}
text = text.replace(block, newBlock);
}
}
return text;
});
function getYamlBlocks(text, callout) {
return callout ? text.match(/^> ```folder-overview\n([\s\S]*?)```/gm) : text.match(/^(?!>).*```folder-overview\n(?:^(?!>).*[\r\n]*)*?^```$/gm);
}
function cleanYamlBlock(block, calloutFlag) {
if (calloutFlag) {
let cleaned = block.replace("> ```folder-overview\n", "").replace("```", "");
return cleaned.replace(/^> ?/gm, "");
}
return block.replace("```folder-overview\n", "").replace("```", "");
}
function buildNewBlock(stringYaml, calloutFlag) {
if (calloutFlag) {
const yamlLines = stringYaml.split("\n").map((line) => `> ${line}`).join("\n");
return "> ```folder-overview\n" + yamlLines + "\n> ```";
}
return "```folder-overview\n" + stringYaml + "\n```";
}
}
function parseOverviewTitle(overview, plugin, sourceFolder, sourceFolderPath, sourceFile) {
var _a, _b, _c, _d;
let { title } = overview;
const variables = {
folderName: (sourceFolder == null ? void 0 : sourceFolder.path) === "/" || sourceFolderPath === "/" ? "Vault" : (_a = sourceFolder == null ? void 0 : sourceFolder.name) != null ? _a : "",
folderPath: (_c = (_b = sourceFolder == null ? void 0 : sourceFolder.path) != null ? _b : sourceFolderPath) != null ? _c : "",
filePath: sourceFile.path,
fileName: sourceFile instanceof import_obsidian28.TFile ? sourceFile.basename : ""
};
const fileCache = plugin.app.metadataCache.getFileCache(sourceFile);
const frontmatter = (_d = fileCache == null ? void 0 : fileCache.frontmatter) != null ? _d : {};
title = replacePropertiesInTitle(title, frontmatter);
title = replaceVariablesInTitle(title, variables);
return title;
}
function replacePropertiesInTitle(title, frontmatter) {
const propertyRegex = /\{\{properties\.([\w-]+)\}\}/g;
return title.replace(propertyRegex, (_, prop) => {
const value = frontmatter[prop];
return value !== void 0 ? String(value) : "";
});
}
function replaceVariablesInTitle(title, variables) {
return title.replace(/\{\{(\w+)\}\}/g, (_, key) => {
var _a;
return (_a = variables[key]) != null ? _a : "";
});
}
// src/obsidian-folder-overview/src/modals/Settings.ts
var FolderOverviewSettings = class extends import_obsidian29.Modal {
constructor(app2, plugin, yaml, ctx, el, defaultSettings) {
super(app2);
this.plugin = plugin;
this.app = app2;
this.defaultSettings = defaultSettings;
this.yaml = this.initializeYaml(yaml, ctx, defaultSettings);
this.ctx = ctx != null ? ctx : void 0;
this.el = el != null ? el : void 0;
updateYaml(this.plugin, this.ctx, this.el, this.yaml, false);
}
initializeYaml(yaml, ctx, defaultSettings) {
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w;
if (!yaml) {
return this.defaultSettings;
}
if (ctx) {
const includeTypes = (yaml == null ? void 0 : yaml.includeTypes) || defaultSettings.includeTypes || ["folder", "markdown"];
return {
id: (_a = yaml == null ? void 0 : yaml.id) != null ? _a : crypto.randomUUID(),
folderPath: (_b = yaml == null ? void 0 : yaml.folderPath) != null ? _b : getFolderPathFromString2(ctx.sourcePath),
title: (_c = yaml == null ? void 0 : yaml.title) != null ? _c : defaultSettings.title,
showTitle: (_d = yaml == null ? void 0 : yaml.showTitle) != null ? _d : defaultSettings.showTitle,
depth: (_e = yaml == null ? void 0 : yaml.depth) != null ? _e : defaultSettings.depth,
style: (_f = yaml == null ? void 0 : yaml.style) != null ? _f : "list",
includeTypes: includeTypes.map((type) => type.toLowerCase()),
disableFileTag: (_g = yaml == null ? void 0 : yaml.disableFileTag) != null ? _g : defaultSettings.disableFileTag,
sortBy: (_h = yaml == null ? void 0 : yaml.sortBy) != null ? _h : defaultSettings.sortBy,
sortByAsc: (_i = yaml == null ? void 0 : yaml.sortByAsc) != null ? _i : defaultSettings.sortByAsc,
showEmptyFolders: (_j = yaml == null ? void 0 : yaml.showEmptyFolders) != null ? _j : defaultSettings.showEmptyFolders,
onlyIncludeSubfolders: (_k = yaml == null ? void 0 : yaml.onlyIncludeSubfolders) != null ? _k : defaultSettings.onlyIncludeSubfolders,
storeFolderCondition: (_l = yaml == null ? void 0 : yaml.storeFolderCondition) != null ? _l : defaultSettings.storeFolderCondition,
showFolderNotes: (_m = yaml == null ? void 0 : yaml.showFolderNotes) != null ? _m : defaultSettings.showFolderNotes,
disableCollapseIcon: (_n = yaml == null ? void 0 : yaml.disableCollapseIcon) != null ? _n : defaultSettings.disableCollapseIcon,
alwaysCollapse: (_o = yaml == null ? void 0 : yaml.alwaysCollapse) != null ? _o : defaultSettings.alwaysCollapse,
autoSync: (_p = yaml == null ? void 0 : yaml.autoSync) != null ? _p : defaultSettings.autoSync,
allowDragAndDrop: (_q = yaml == null ? void 0 : yaml.allowDragAndDrop) != null ? _q : defaultSettings.allowDragAndDrop,
hideLinkList: (_r = yaml == null ? void 0 : yaml.hideLinkList) != null ? _r : defaultSettings.hideLinkList,
hideFolderOverview: (_s = yaml == null ? void 0 : yaml.hideFolderOverview) != null ? _s : defaultSettings.hideFolderOverview,
useActualLinks: (_t = yaml == null ? void 0 : yaml.useActualLinks) != null ? _t : defaultSettings.useActualLinks,
fmtpIntegration: (_u = yaml == null ? void 0 : yaml.fmtpIntegration) != null ? _u : defaultSettings.fmtpIntegration,
titleSize: (_v = yaml == null ? void 0 : yaml.titleSize) != null ? _v : defaultSettings.titleSize,
isInCallout: (_w = yaml == null ? void 0 : yaml.isInCallout) != null ? _w : false
};
}
return yaml;
}
onOpen() {
const { contentEl } = this;
this.display(contentEl, this.yaml, this.plugin, this.defaultSettings, this.display, this.el, this.ctx);
}
display(contentEl, yaml, plugin, defaultSettings, display, el, ctx, file, settingsTab, modal, changedSection) {
modal = this != null ? this : modal;
contentEl.empty();
contentEl.addEventListener("keydown", (e) => {
if (e.key === "Enter") {
if (!modal) {
return;
}
modal.close();
}
});
if (!modal.defaultSettings) {
contentEl.createEl("h2", { text: "Folder overview settings" });
} else {
contentEl.createEl("h2", { text: "Default folder overview settings" });
}
createOverviewSettings(contentEl, yaml, plugin, defaultSettings, display, el, ctx, void 0, void 0, modal, changedSection);
}
onClose() {
this.plugin.updateOverviewView(this.plugin, this.yaml);
const { contentEl } = this;
contentEl.empty();
}
};
// src/obsidian-folder-overview/src/styles/FileExplorer.ts
var import_obsidian30 = require("obsidian");
var FileExplorerOverview = class {
constructor(plugin, ctx, root, yaml, pathBlacklist, folderOverview) {
this.eventListeners = [];
this.plugin = plugin;
this.folderOverview = folderOverview;
this.pathBlacklist = pathBlacklist;
this.source = ctx.sourcePath;
this.yaml = yaml;
this.root = root;
}
disconnectListeners() {
this.eventListeners.forEach((unregister) => {
unregister();
});
this.eventListeners = [];
}
async renderFileExplorer() {
this.disconnectListeners();
const plugin = this.plugin;
const ctx = this.folderOverview.ctx;
const root = this.folderOverview.root;
const yaml = this.folderOverview.yaml;
const folderOverview = this.folderOverview;
let folder = null;
if (plugin instanceof FolderNotesPlugin) {
folder = getFileExplorerElement(yaml.folderPath, plugin);
}
let folderElement = folder == null ? void 0 : folder.parentElement;
const overviewList = folderOverview.listEl;
overviewList == null ? void 0 : overviewList.empty();
if (!overviewList)
return;
let tFolder = plugin.app.vault.getAbstractFileByPath(yaml.folderPath);
if (!tFolder && yaml.folderPath.trim() === "") {
if (ctx.sourcePath.includes("/")) {
const folderPath = getFolderPathFromString(ctx.sourcePath);
tFolder = plugin.app.vault.getAbstractFileByPath(folderPath);
} else {
yaml.folderPath = "/";
tFolder = plugin.app.vault.getAbstractFileByPath("/");
}
}
if (!folderElement && !tFolder)
return;
const sourceFolderPath = (tFolder == null ? void 0 : tFolder.path) || "";
folderElement = document.querySelectorAll(".nav-files-container")[0];
if (!folderElement) {
folderElement = root.createDiv({
cls: "nav-files-container"
});
}
const newFolderElement = folderElement.cloneNode(true);
newFolderElement.querySelectorAll("div.nav-folder-title").forEach((el) => {
var _a;
const folderItem = plugin.app.vault.getAbstractFileByPath(el.getAttribute("data-path") || "");
if (!(folderItem instanceof import_obsidian30.TFolder))
return;
if (yaml.alwaysCollapse) {
folderItem.collapsed = true;
el.classList.add("is-collapsed");
} else {
if (yaml.storeFolderCondition) {
if (folderItem.collapsed) {
el.classList.add("is-collapsed");
} else {
el.classList.remove("is-collapsed");
}
} else {
if ((_a = el.parentElement) == null ? void 0 : _a.classList.contains("is-collapsed")) {
folderItem.collapsed = true;
} else {
folderItem.collapsed = false;
}
}
}
if (el.classList.contains("has-folder-note")) {
if (plugin instanceof FolderNotesPlugin) {
const folderNote = getFolderNote(plugin, folderItem.path);
if (folderNote) {
folderOverview.pathBlacklist.push(folderNote.path);
}
}
}
});
const DEBOUNCE_DELAY_MS = 300;
const debouncedRenderFileExplorer = (0, import_obsidian30.debounce)(() => this.renderFileExplorer(), DEBOUNCE_DELAY_MS);
const handleVaultChange = () => {
debouncedRenderFileExplorer();
};
this.eventListeners.push(() => {
folderOverview.off("vault-change", handleVaultChange);
});
folderOverview.on("vault-change", handleVaultChange);
if (tFolder instanceof import_obsidian30.TFolder) {
await this.addFiles(tFolder.children, overviewList, folderOverview, sourceFolderPath);
}
newFolderElement.querySelectorAll("div.tree-item-icon").forEach((el) => {
if (el instanceof HTMLElement) {
el.onclick = () => {
var _a;
const path = (_a = el.parentElement) == null ? void 0 : _a.getAttribute("data-path");
if (!path)
return;
const targetFolder = plugin.app.vault.getAbstractFileByPath(path);
this.handleCollapseClick(el, plugin, yaml, this.pathBlacklist, sourceFolderPath, folderOverview, targetFolder);
};
}
});
}
async addFiles(files, childrenElement, folderOverview, sourceFolderPath) {
const { plugin } = folderOverview;
const allFiles = await filterFiles(files, plugin, sourceFolderPath, folderOverview.yaml.depth, folderOverview.pathBlacklist, folderOverview.yaml, folderOverview.sourceFile);
const sortedFiles = sortFiles((allFiles != null ? allFiles : []).filter((file) => file !== null), folderOverview.yaml, folderOverview.plugin);
const folders = sortedFiles.filter((child) => child instanceof import_obsidian30.TFolder);
const otherFiles = sortedFiles.filter((child) => child instanceof import_obsidian30.TFile);
for (const child of folders) {
if (!(child instanceof import_obsidian30.TFolder))
continue;
await this.createFolderEL(plugin, child, folderOverview, childrenElement, sourceFolderPath);
}
for (const child of otherFiles) {
if (!(child instanceof import_obsidian30.TFile))
continue;
await this.createFileEL(plugin, child, folderOverview, childrenElement);
}
}
async handleCollapseClick(el, plugin, yaml, pathBlacklist, sourceFolderPath, folderOverview, folder) {
var _a, _b, _c, _d;
el.classList.toggle("is-collapsed");
if (el.classList.contains("is-collapsed")) {
if (!(folder instanceof import_obsidian30.TFolder))
return;
folder.collapsed = true;
(_c = (_b = (_a = el.parentElement) == null ? void 0 : _a.parentElement) == null ? void 0 : _b.childNodes[1]) == null ? void 0 : _c.remove();
} else {
if (!(folder instanceof import_obsidian30.TFolder))
return;
folder.collapsed = false;
const folderElement = (_d = el.parentElement) == null ? void 0 : _d.parentElement;
if (!folderElement)
return;
const childrenElement = folderElement.createDiv({
cls: "tree-item-children nav-folder-children"
});
const files = sortFiles(folder.children, yaml, plugin);
const filteredFilesResult = await filterFiles(files, plugin, folder.path, yaml.depth || 1, pathBlacklist, yaml, folderOverview.sourceFile);
const filteredFiles = (filteredFilesResult != null ? filteredFilesResult : []).filter((file) => file !== null);
await this.addFiles(filteredFiles, childrenElement, folderOverview, sourceFolderPath);
}
}
async createFolderEL(plugin, child, folderOverview, childrenElement, sourceFolderPath) {
const folderNote = this.getFolderNoteIfExists(plugin, child);
if (folderNote) {
folderOverview.pathBlacklist.push(folderNote.path);
}
if (this.shouldExcludeFolder(plugin, child)) {
return;
}
const { folderElement, folderTitle } = this.createFolderElements(plugin, child, folderOverview, childrenElement, folderNote);
await this.handleFolderChildren(child, folderOverview, folderElement, folderTitle, childrenElement, sourceFolderPath);
this.setupFolderStyles(folderNote, child, folderTitle, folderOverview.yaml);
this.createCollapseIcon(folderTitle, child, plugin, folderOverview, sourceFolderPath);
}
getFolderNoteIfExists(plugin, child) {
if (plugin instanceof FolderNotesPlugin) {
return getFolderNote(plugin, child.path);
}
return void 0;
}
shouldExcludeFolder(plugin, child) {
var _a;
if (plugin instanceof FolderNotesPlugin) {
const excludedFolder = getExcludedFolder(plugin, child.path, true);
return (_a = excludedFolder == null ? void 0 : excludedFolder.excludeFromFolderOverview) != null ? _a : false;
}
return false;
}
createFolderElements(plugin, child, folderOverview, childrenElement, folderNote) {
var _a;
const { yaml } = folderOverview;
if (!yaml.includeTypes.includes("folder")) {
return { folderElement: null, folderTitle: null };
}
(_a = folderOverview.el.parentElement) == null ? void 0 : _a.classList.add("fv-remove-edit-button");
const folderElement = childrenElement.createDiv({
cls: "tree-item nav-folder"
});
const folderTitle = folderElement.createDiv({
cls: "tree-item-self is-clickable nav-folder-title",
attr: {
"data-path": child.path
}
});
this.setupFolderTitle(plugin, child, folderOverview, folderTitle, folderNote);
return { folderElement, folderTitle };
}
async setupFolderTitle(plugin, child, folderOverview, folderTitle, folderNote) {
var _a, _b;
const { yaml, pathBlacklist } = folderOverview;
let folderName = child.name;
if (yaml.fmtpIntegration && plugin instanceof FolderNotesPlugin && folderNote) {
folderName = (_b = await ((_a = plugin.fmtpHandler) == null ? void 0 : _a.getNewFileName(folderNote))) != null ? _b : child.name;
}
const folderTitleText = folderTitle.createDiv({
cls: "tree-item-inner nav-folder-title-content",
text: folderName
});
if (!folderNote) {
folderTitleText.onclick = () => {
const collapseIcon = folderTitle.querySelectorAll(".tree-item-icon")[0];
if (collapseIcon) {
this.handleCollapseClick(collapseIcon, plugin, yaml, pathBlacklist, "", folderOverview, child);
}
};
}
if (yaml.allowDragAndDrop) {
this.handleDragAndDrop(folderTitle, folderTitle.parentElement, child);
}
folderTitle.oncontextmenu = (e) => {
folderOverview.folderMenu(child, e);
};
}
async handleFolderChildren(child, folderOverview, folderElement, folderTitle, childrenElement, sourceFolderPath) {
const { yaml } = folderOverview;
if (!child.collapsed || !yaml.includeTypes.includes("folder")) {
if (yaml.alwaysCollapse) {
child.collapsed = true;
}
if (yaml.includeTypes.includes("folder")) {
folderTitle == null ? void 0 : folderTitle.classList.remove("is-collapsed");
const folderChildren = folderElement == null ? void 0 : folderElement.createDiv({
cls: "tree-item-children nav-folder-children"
});
if (folderChildren) {
await this.addFiles(child.children, folderChildren, folderOverview, sourceFolderPath);
}
} else {
await this.addFiles(child.children, childrenElement, folderOverview, sourceFolderPath);
}
} else {
folderTitle == null ? void 0 : folderTitle.classList.add("is-collapsed");
}
}
setupFolderStyles(folderNote, child, folderTitle, yaml) {
if (folderNote) {
folderTitle == null ? void 0 : folderTitle.classList.add("has-folder-note");
}
if (folderNote && child.children.length === 1 && yaml.disableCollapseIcon) {
folderTitle == null ? void 0 : folderTitle.classList.add("fn-has-no-files");
}
}
createCollapseIcon(folderTitle, child, plugin, folderOverview, sourceFolderPath) {
var _a;
const collapseIcon = folderTitle == null ? void 0 : folderTitle.createDiv({
cls: "tree-item-icon collapse-icon nav-folder-collapse-indicator fn-folder-overview-collapse-icon"
});
if (child.collapsed) {
collapseIcon == null ? void 0 : collapseIcon.classList.add("is-collapsed");
}
if (collapseIcon) {
(0, import_obsidian30.setIcon)(collapseIcon, "chevron-down");
(_a = collapseIcon.querySelector("path")) == null ? void 0 : _a.setAttribute("d", "M3 8L12 17L21 8");
collapseIcon.onclick = () => {
this.handleCollapseClick(collapseIcon, plugin, folderOverview.yaml, folderOverview.pathBlacklist, sourceFolderPath, folderOverview, child);
};
}
}
handleDragAndDrop(folderTitle, folderElement, child) {
folderTitle.draggable = true;
folderTitle.addEventListener("dragstart", (e) => {
const { dragManager } = this.plugin.app;
const dragData = dragManager.dragFolder(e, child);
dragManager.onDragStart(e, dragData);
folderTitle == null ? void 0 : folderTitle.classList.add("is-being-dragged");
});
folderTitle.addEventListener("dragend", () => {
folderTitle == null ? void 0 : folderTitle.classList.remove("is-being-dragged");
});
folderTitle.addEventListener("dragover", (e) => {
e.preventDefault();
const { draggable } = this.plugin.app.dragManager;
if (draggable) {
folderElement == null ? void 0 : folderElement.classList.add("is-being-dragged-over");
this.plugin.app.dragManager.setAction(window.i18next.t("interface.drag-and-drop.move-into-folder", { folder: child.name }));
}
});
folderTitle.addEventListener("dragleave", () => {
folderElement == null ? void 0 : folderElement.classList.remove("is-being-dragged-over");
});
folderTitle.addEventListener("drop", () => {
const { draggable } = this.plugin.app.dragManager;
if (draggable && draggable.file) {
const newPath = child.path + "/" + draggable.file.name;
this.plugin.app.fileManager.renameFile(draggable.file, newPath);
}
});
}
async createFileEL(plugin, child, folderOverview, childrenElement) {
var _a, _b, _c;
const { yaml } = folderOverview;
const { pathBlacklist } = folderOverview;
if (pathBlacklist.includes(child.path) && !yaml.showFolderNotes) {
return;
}
(_a = folderOverview.el.parentElement) == null ? void 0 : _a.classList.add("fv-remove-edit-button");
const fileElement = childrenElement.createDiv({
cls: "tree-item nav-file"
});
const fileTitle = fileElement.createDiv({
cls: "tree-item-self is-clickable nav-file-title pointer-cursor",
attr: {
"data-path": child.path
}
});
if (yaml.allowDragAndDrop) {
fileTitle.draggable = true;
fileTitle.addEventListener("dragstart", (e) => {
const dragManager = plugin.app.dragManager;
const dragData = dragManager.dragFile(e, child);
dragManager.onDragStart(e, dragData);
fileTitle.classList.add("is-being-dragged");
});
fileTitle.addEventListener("dragend", () => {
fileTitle.classList.remove("is-being-dragged");
});
fileTitle.addEventListener("dragover", (e) => {
var _a2, _b2, _c2;
e.preventDefault();
const { draggable } = plugin.app.dragManager;
if (draggable) {
const folderName = ((_a2 = child.parent) == null ? void 0 : _a2.name) || plugin.app.vault.getName();
plugin.app.dragManager.setAction(window.i18next.t("interface.drag-and-drop.move-into-folder", { folder: folderName }));
(_c2 = (_b2 = fileElement.parentElement) == null ? void 0 : _b2.parentElement) == null ? void 0 : _c2.classList.add("is-being-dragged-over");
}
});
fileTitle.addEventListener("dragleave", () => {
var _a2, _b2;
(_b2 = (_a2 = fileElement.parentElement) == null ? void 0 : _a2.parentElement) == null ? void 0 : _b2.classList.remove("is-being-dragged-over");
});
fileTitle.addEventListener("drop", (e) => {
var _a2, _b2, _c2;
e.preventDefault();
const { draggable } = plugin.app.dragManager;
if (draggable == null ? void 0 : draggable.file) {
const targetFolder = ((_a2 = child.parent) == null ? void 0 : _a2.path) || "";
if (targetFolder) {
const newPath = `${targetFolder}/${draggable.file.name}`;
plugin.app.fileManager.renameFile(draggable.file, newPath);
}
(_c2 = (_b2 = fileElement.parentElement) == null ? void 0 : _b2.parentElement) == null ? void 0 : _c2.classList.remove("is-being-dragged-over");
}
});
}
fileTitle.onclick = () => {
plugin.app.workspace.openLinkText(child.path, child.path, true);
};
fileTitle.oncontextmenu = (e) => {
folderOverview.fileMenu(child, e);
};
let fileName = child.basename;
if (yaml.fmtpIntegration) {
fileName = (_c = await ((_b = plugin.fmtpHandler) == null ? void 0 : _b.getNewFileName(child))) != null ? _c : child.basename;
}
fileTitle.createDiv({
cls: "tree-item-inner nav-file-title-content",
text: fileName
});
if (child.extension !== "md" && !yaml.disableFileTag) {
fileTitle.createDiv({
cls: "nav-file-tag",
text: child.extension
});
}
}
};
// src/obsidian-folder-overview/src/styles/List.ts
var import_obsidian31 = require("obsidian");
async function renderListOverview(plugin, ctx, root, yaml, pathBlacklist, folderOverview) {
const overviewList = folderOverview.listEl;
const { app: app2 } = plugin;
overviewList == null ? void 0 : overviewList.empty();
let tFolder = app2.vault.getAbstractFileByPath(yaml.folderPath);
if (!tFolder && yaml.folderPath.trim() === "") {
if (ctx.sourcePath.includes("/")) {
tFolder = app2.vault.getAbstractFileByPath(getFolderPathFromString(ctx.sourcePath));
} else {
yaml.folderPath = "/";
tFolder = app2.vault.getAbstractFileByPath("/");
}
}
if (!(tFolder instanceof import_obsidian31.TFolder)) {
return;
}
let files = tFolder.children;
if (!files) {
return;
}
const ul = folderOverview.listEl;
const sourceFolderPath = tFolder.path;
files = await filterFiles(files, plugin, sourceFolderPath, yaml.depth, folderOverview.pathBlacklist, yaml, folderOverview.sourceFile);
const folders = sortFiles(files.filter((f) => f instanceof import_obsidian31.TFolder), folderOverview.yaml, plugin);
files = sortFiles(files.filter((f) => f instanceof import_obsidian31.TFile), folderOverview.yaml, plugin);
folders.forEach(async (file) => {
if (file instanceof import_obsidian31.TFolder) {
if (yaml.includeTypes.includes("folder")) {
const folderItem = await addFolderList(plugin, ul, folderOverview.pathBlacklist, file, folderOverview);
if (!folderItem) {
return;
}
goThroughFolders(plugin, folderItem, file, folderOverview.yaml.depth, sourceFolderPath, ctx, folderOverview.yaml, folderOverview.pathBlacklist, folderOverview.yaml.includeTypes, folderOverview.yaml.disableFileTag, folderOverview);
} else {
goThroughFolders(plugin, ul, file, folderOverview.yaml.depth, sourceFolderPath, ctx, folderOverview.yaml, folderOverview.pathBlacklist, folderOverview.yaml.includeTypes, folderOverview.yaml.disableFileTag, folderOverview);
}
}
});
files.forEach((file) => {
if (file instanceof import_obsidian31.TFile) {
addFileList(plugin, ul, folderOverview.pathBlacklist, file, folderOverview.yaml.includeTypes, folderOverview.yaml.disableFileTag, folderOverview);
}
});
const DEBOUNCE_DELAY = 300;
const debouncedRenderListOverview = debounce3(() => renderListOverview(plugin, ctx, root, yaml, pathBlacklist, folderOverview), DEBOUNCE_DELAY);
const handleVaultChange = () => {
debouncedRenderListOverview();
};
folderOverview.on("vault-change", handleVaultChange);
}
function debounce3(func, wait) {
let timeout;
return (...args) => {
clearTimeout(timeout);
timeout = window.setTimeout(() => func.apply(this, args), wait);
};
}
async function addFolderList(plugin, list, pathBlacklist, folder, folderOverview) {
var _a, _b, _c;
(_a = folderOverview.el.parentElement) == null ? void 0 : _a.classList.add("fv-remove-edit-button");
const folderDepth = folder.path.split("/").length;
const sourceFolderDepth = folderOverview.yaml.folderPath.split("/").length;
const isFirstLevelSub = folderDepth === sourceFolderDepth + 1;
if (!folderOverview.yaml.showEmptyFolders && folder.children.length === 0 && !folderOverview.yaml.onlyIncludeSubfolders) {
return;
} else if (folderOverview.yaml.onlyIncludeSubfolders && !isFirstLevelSub && folder.children.length === 0) {
return;
}
const folderItem = list.createEl("li", { cls: "folder-overview-list folder-list" });
if (plugin instanceof FolderNotesPlugin) {
const folderNote = getFolderNote(plugin, folder.path);
if (folderNote instanceof import_obsidian31.TFile) {
const folderNoteLink = folderItem.createEl("a", {
cls: "folder-overview-list-item folder-name-item internal-link",
href: folderNote.path
});
if (folderOverview.yaml.fmtpIntegration) {
folderNoteLink.innerText = (_c = await ((_b = plugin.fmtpHandler) == null ? void 0 : _b.getNewFileName(folderNote))) != null ? _c : folder.name;
} else {
folderNoteLink.innerText = folder.name;
}
pathBlacklist.push(folderNote.path);
folderNoteLink.oncontextmenu = (e) => {
e.stopImmediatePropagation();
folderOverview.fileMenu(folderNote, e);
};
} else {
const folderName = folderItem.createEl("span", {
cls: "folder-overview-list-item folder-name-item"
});
folderName.innerText = folder.name;
folderName.oncontextmenu = (e) => {
folderOverview.folderMenu(folder, e);
};
}
} else {
const folderName = folderItem.createEl("span", {
cls: "folder-overview-list-item folder-name-item"
});
folderName.innerText = folder.name;
folderName.oncontextmenu = (e) => {
folderOverview.folderMenu(folder, e);
};
}
return folderItem;
}
async function goThroughFolders(plugin, list, folder, depth, sourceFolderPath, ctx, yaml, pathBlacklist, includeTypes, disableFileTag, folderOverview) {
if (sourceFolderPath === "") {
depth--;
}
const allFiles = await filterFiles(folder.children, plugin, sourceFolderPath, depth, pathBlacklist, yaml, folderOverview.sourceFile);
const files = sortFiles(allFiles.filter((file) => !(file instanceof import_obsidian31.TFolder) && file !== null), yaml, plugin);
const folders = sortFiles(allFiles.filter((file) => file instanceof import_obsidian31.TFolder && file !== null), yaml, plugin);
const ul = list.createEl("ul", { cls: "folder-overview-list" });
folders.forEach(async (file) => {
if (file instanceof import_obsidian31.TFolder) {
if (yaml.includeTypes.includes("folder")) {
const folderItem = await addFolderList(plugin, ul, pathBlacklist, file, folderOverview);
if (!folderItem) {
return;
}
goThroughFolders(plugin, folderItem, file, depth, sourceFolderPath, ctx, yaml, pathBlacklist, includeTypes, disableFileTag, folderOverview);
} else {
goThroughFolders(plugin, list, file, depth, sourceFolderPath, ctx, yaml, pathBlacklist, includeTypes, disableFileTag, folderOverview);
}
}
});
files.forEach((file) => {
if (file instanceof import_obsidian31.TFile) {
if (yaml.includeTypes.includes("folder")) {
addFileList(plugin, ul, pathBlacklist, file, includeTypes, disableFileTag, folderOverview);
} else {
addFileList(plugin, list, pathBlacklist, file, includeTypes, disableFileTag, folderOverview);
}
}
});
}
async function addFileList(plugin, list, pathBlacklist, file, includeTypes, disableFileTag, folderOverview) {
var _a, _b, _c, _d;
if (!folderOverview.yaml.showFolderNotes) {
if (pathBlacklist.includes(file.path))
return;
if (plugin instanceof FolderNotesPlugin && extractFolderName(plugin.settings.folderNoteName, file.basename) === ((_a = file.parent) == null ? void 0 : _a.name)) {
return;
}
}
(_b = folderOverview.el.parentElement) == null ? void 0 : _b.classList.add("fv-remove-edit-button");
const listItem = list.createEl("li", { cls: "folder-overview-list file-link" });
listItem.oncontextmenu = (e) => {
e.stopImmediatePropagation();
folderOverview.fileMenu(file, e);
};
const nameItem = listItem.createEl("div", { cls: "folder-overview-list-item" });
const link = nameItem.createEl("a", { cls: "internal-link", href: file.path });
if (folderOverview.yaml.fmtpIntegration) {
link.innerText = (_d = await ((_c = plugin.fmtpHandler) == null ? void 0 : _c.getNewFileName(file))) != null ? _d : file.basename;
} else {
link.innerText = file.basename;
}
if (file.extension !== "md" && !disableFileTag) {
nameItem.createDiv({ cls: "nav-file-tag" }).innerText = file.extension;
}
}
// src/modals/NewFolderName.ts
var import_obsidian32 = require("obsidian");
var NewFolderNameModal = class extends import_obsidian32.Modal {
constructor(app2, plugin, folder) {
super(app2);
this.plugin = plugin;
this.app = app2;
this.folder = folder;
}
onOpen() {
const { contentEl } = this;
contentEl.addEventListener("keydown", (e) => {
if (e.key === "Enter") {
this.saveFolderName();
this.close();
}
});
this.modalEl.classList.add("mod-file-rename");
const modalTitle = this.modalEl.querySelector("div.modal-title");
if (modalTitle) {
modalTitle.textContent = "Folder title";
}
const textarea = contentEl.createEl("textarea", {
text: this.folder.name.replace(this.plugin.settings.folderNoteType, ""),
attr: {
placeholder: "Enter the name of the folder",
rows: "1",
spellcheck: "false",
class: "rename-textarea"
}
});
textarea.addEventListener("focus", function() {
this.select();
});
textarea.focus();
const buttonContainer = this.modalEl.createDiv({ cls: "modal-button-container" });
const saveButton = buttonContainer.createEl("button", { text: "Save", cls: "mod-cta" });
saveButton.addEventListener("click", async () => {
this.saveFolderName();
this.close();
});
const cancelButton = buttonContainer.createEl("button", {
text: "Cancel",
cls: "mod-cancel"
});
cancelButton.addEventListener("click", () => {
this.close();
});
}
onClose() {
const { contentEl } = this;
contentEl.empty();
}
saveFolderName() {
const textarea = this.contentEl.querySelector("textarea");
if (textarea) {
const newName = textarea.value.trim();
if (newName.trim() !== "") {
const folderBasePath = this.folder.path.slice(0, this.folder.path.lastIndexOf("/") + 1);
const newFolderPath = folderBasePath + newName.trim();
if (!this.app.vault.getAbstractFileByPath(newFolderPath)) {
this.plugin.app.fileManager.renameFile(this.folder, newFolderPath);
}
}
}
}
};
// src/obsidian-folder-overview/src/utils/EventEmitter.ts
var CustomEventEmitter2 = class {
constructor() {
this.events = {};
}
on(event, listener) {
if (!this.events[event]) {
this.events[event] = [];
}
this.events[event].push(listener);
}
off(event, listener) {
if (!this.events[event])
return;
this.events[event] = this.events[event].filter((l) => l !== listener);
}
emit(event, data) {
if (!this.events[event])
return;
this.events[event].forEach((listener) => listener(data));
}
};
// src/obsidian-folder-overview/src/FolderOverview.ts
var FolderOverview = class {
constructor(plugin, ctx, source, el, defaultSettings) {
this.pathBlacklist = [];
this.folders = [];
this.counter = 0;
this.LINK_LIST_UPDATE_DELAY_MS = 1e3;
this.eventListeners = [];
this.plugin = plugin;
this.emitter = new CustomEventEmitter2();
const yaml = this.parseYamlOrUseDefault(source);
const includeTypes = (yaml == null ? void 0 : yaml.includeTypes) || defaultSettings.includeTypes || ["folder", "markdown"];
this.ctx = ctx;
this.source = source;
this.el = el;
this.sourceFile = this.getSourceFile(ctx);
this.yaml = buildYamlConfig(yaml, defaultSettings, ctx, includeTypes);
this.setSourceFolder();
this.defaultSettings = defaultSettings;
const customChild = new CustomMarkdownRenderChild(el, this);
ctx.addChild(customChild);
}
async create(plugin, el, ctx) {
var _a, _b, _c;
el.empty();
if (!(this.sourceFile instanceof import_obsidian33.TFile))
return;
(_a = el.parentElement) == null ? void 0 : _a.classList.add("folder-overview-container");
if (this.yaml.hideFolderOverview) {
if (this.yaml.isInCallout) {
el == null ? void 0 : el.classList.add("fv-hide-overview");
} else {
(_b = el.parentElement) == null ? void 0 : _b.classList.add("fv-hide-overview");
}
}
(_c = el.parentElement) == null ? void 0 : _c.addEventListener("contextmenu", (e) => this.editOverviewContextMenu(e), { capture: true });
this.root = el.createEl("div", { cls: "folder-overview" });
const headingTag = `h${this.yaml.titleSize}`;
const titleEl = this.root.createEl(headingTag, { cls: "folder-overview-title" });
this.listEl = this.root.createEl("ul", { cls: "folder-overview-list" });
if (this.hasNoIncludedTypes(this.root))
return;
let sourceFolderPath = this.yaml.folderPath.trim() || getFolderPathFromString(ctx.sourcePath) || "/";
this.registerListeners();
await this.renderTitle(this.sourceFolder, sourceFolderPath, this.sourceFile, titleEl);
if (!this.validateSourceFolder(this.sourceFolder, sourceFolderPath)) {
this.addEditButton(this.root);
return;
}
let files = this.getInitialFiles(plugin, this.sourceFolder);
files = await this.filterAndProcessFiles(files, plugin, sourceFolderPath, this.yaml, this.sourceFile);
if (files.length === 0) {
updateLinkList(files, this.plugin, this.yaml, this.pathBlacklist, this.sourceFile);
this.addEditButton(this.root);
return;
}
files = sortFiles(files, this.yaml, this.plugin);
this.renderOverviewStyle(plugin, ctx, this.root);
this.handleLinkList(files);
this.addEditButton(this.root);
}
parseYamlOrUseDefault(source) {
let yaml = (0, import_obsidian33.parseYaml)(source);
if (!yaml) {
yaml = {};
}
return yaml;
}
getSourceFile(ctx) {
const sourceFile = this.plugin.app.vault.getAbstractFileByPath(ctx.sourcePath);
if (sourceFile instanceof import_obsidian33.TFile) {
return sourceFile;
}
return void 0;
}
on(event, listener) {
this.emitter.on(event, listener);
}
off(event, listener) {
this.emitter.off(event, listener);
}
emit(event, data) {
this.emitter.emit(event, data);
}
handleVaultChange(eventType) {
if (this.yaml.autoSync) {
this.emit("vault-change", eventType);
}
}
disconnectListeners() {
this.eventListeners.forEach((unregister) => unregister());
this.eventListeners = [];
}
registerListeners() {
const { plugin } = this;
const handleRename2 = () => this.handleVaultChange("renamed");
const handleCreate2 = () => this.handleVaultChange("created");
const handleDelete2 = () => this.handleVaultChange("deleted");
plugin.app.vault.on("rename", handleRename2);
plugin.app.vault.on("create", handleCreate2);
plugin.app.vault.on("delete", handleDelete2);
this.eventListeners.push(() => plugin.app.vault.off("rename", handleRename2));
this.eventListeners.push(() => plugin.app.vault.off("create", handleCreate2));
this.eventListeners.push(() => plugin.app.vault.off("delete", handleDelete2));
}
setSourceFolder() {
var _a;
switch ((_a = this.yaml) == null ? void 0 : _a.folderPath.trim()) {
case "":
case "File\u2019s parent folder path": {
const folderPath = getFolderPathFromString(this.ctx.sourcePath);
const sourceFolder = this.plugin.app.vault.getAbstractFileByPath(folderPath);
if (sourceFolder instanceof import_obsidian33.TFolder) {
this.yaml.folderPath = sourceFolder.path;
this.sourceFolder = sourceFolder;
}
break;
}
case "Path of folder linked to the file": {
if (this.plugin instanceof FolderNotesPlugin && this.sourceFile instanceof import_obsidian33.TFile) {
const folderNoteFolder = getFolder(this.plugin, this.sourceFile);
if (folderNoteFolder instanceof import_obsidian33.TFolder) {
this.sourceFolder = folderNoteFolder;
this.yaml.folderPath = folderNoteFolder.path;
} else {
this.yaml.folderPath = "";
}
}
break;
}
default: {
const sourceFolder = this.plugin.app.vault.getAbstractFileByPath(this.yaml.folderPath);
if (sourceFolder instanceof import_obsidian33.TFolder) {
this.sourceFolder = sourceFolder;
}
}
}
}
async filterAndProcessFiles(files, plugin, sourceFolderPath, yaml, sourceFile) {
let filteredFiles = await filterFiles(files, plugin, sourceFolderPath, yaml.depth, this.pathBlacklist, yaml, sourceFile);
if (!yaml.includeTypes.includes("folder")) {
filteredFiles = getAllFiles(filteredFiles, sourceFolderPath, yaml.depth);
}
return filteredFiles;
}
hasNoIncludedTypes(root) {
if (this.yaml.includeTypes.length === 0) {
this.addEditButton(root);
return true;
}
return false;
}
handleLinkList(files) {
if (this.yaml.useActualLinks) {
if (this.sourceFile) {
setTimeout(() => {
updateLinkList(files, this.plugin, this.yaml, this.pathBlacklist, this.sourceFile);
}, this.LINK_LIST_UPDATE_DELAY_MS);
}
} else {
removeLinkList(this.plugin, this.sourceFile, this.yaml);
}
}
async renderTitle(sourceFolder, sourceFolderPath, sourceFile, titleEl) {
var _a, _b, _c, _d, _e, _f;
if (!this.yaml.showTitle)
return;
const variables = {
folderName: (sourceFolder == null ? void 0 : sourceFolder.path) === "/" || sourceFolderPath === "/" ? "Vault" : (_a = sourceFolder == null ? void 0 : sourceFolder.name) != null ? _a : "",
folderPath: (_c = (_b = sourceFolder == null ? void 0 : sourceFolder.path) != null ? _b : sourceFolderPath) != null ? _c : "",
filePath: sourceFile.path,
fileName: sourceFile instanceof import_obsidian33.TFile ? sourceFile.basename : "",
fmtpFileName: (_e = await ((_d = this.plugin.fmtpHandler) == null ? void 0 : _d.getNewFileName(sourceFile))) != null ? _e : ""
};
const fileCache = this.plugin.app.metadataCache.getFileCache(sourceFile);
const frontmatter = (_f = fileCache == null ? void 0 : fileCache.frontmatter) != null ? _f : {};
let { title } = this.yaml;
title = replacePropertiesInTitle(title, frontmatter);
title = replaceVariablesInTitle(title, variables);
titleEl.innerText = title;
}
validateSourceFolder(sourceFolder, sourceFolderPath) {
if (!sourceFolder && sourceFolderPath !== "/" && sourceFolderPath !== "") {
new import_obsidian33.Notice("Folder overview: Couldn't find the folder");
return false;
}
if (!sourceFolder && sourceFolderPath === "") {
sourceFolderPath = "/";
}
if (!(sourceFolder instanceof import_obsidian33.TFolder) && sourceFolderPath !== "/") {
return false;
}
return true;
}
getInitialFiles(plugin, sourceFolder) {
if ((sourceFolder == null ? void 0 : sourceFolder.path) === "/") {
const rootFiles = [];
plugin.app.vault.getAllLoadedFiles().filter((f) => {
var _a;
return ((_a = f.parent) == null ? void 0 : _a.path) === "/";
}).forEach((file) => {
if (!file.path.includes("/")) {
rootFiles.push(file);
}
});
return rootFiles;
} else if (sourceFolder instanceof import_obsidian33.TFolder) {
return sourceFolder.children;
}
return [];
}
renderOverviewStyle(plugin, ctx, root) {
if (this.yaml.style === "grid") {
} else if (this.yaml.style === "list") {
renderListOverview(plugin, ctx, root, this.yaml, this.pathBlacklist, this);
} else if (this.yaml.style === "explorer") {
const fileExplorerOverview = new FileExplorerOverview(plugin, ctx, root, this.yaml, this.pathBlacklist, this);
this.plugin.app.workspace.onLayoutReady(async () => {
await fileExplorerOverview.renderFileExplorer();
});
}
}
addEditButton(root) {
const editButton = root.createEl("button", { cls: "folder-overview-edit-button" });
editButton.innerText = "Edit overview";
editButton.addEventListener("click", (e) => {
e.stopImmediatePropagation();
e.preventDefault();
e.stopPropagation();
new FolderOverviewSettings(this.plugin.app, this.plugin, this.yaml, this.ctx, this.el, this.plugin instanceof FolderNotesPlugin ? this.plugin.settings.defaultOverview : this.plugin.settings.defaultOverviewSettings).open();
}, { capture: true });
}
fileMenu(file, e) {
const { plugin } = this;
const fileMenu = new import_obsidian33.Menu();
fileMenu.addItem((item) => {
item.setTitle("Edit folder overview");
item.setIcon("pencil");
item.onClick(async () => {
new FolderOverviewSettings(plugin.app, plugin, this.yaml, this.ctx, this.el, plugin instanceof FolderNotesPlugin ? plugin.settings.defaultOverview : plugin.settings.defaultOverviewSettings).open();
});
});
fileMenu.addSeparator();
fileMenu.addItem((item) => {
item.setTitle(window.i18next.t("plugins.file-explorer.menu-opt-rename"));
item.setIcon("pencil");
item.onClick(async () => {
plugin.app.fileManager.promptForFileRename(file);
});
});
fileMenu.addItem((item) => {
item.setTitle(window.i18next.t("plugins.file-explorer.menu-opt-delete"));
item.setIcon("trash");
item.dom.addClass("is-warning");
item.dom.setAttribute("data-section", "danger");
item.onClick(() => {
plugin.app.fileManager.promptForDeletion(file);
});
});
fileMenu.addSeparator();
plugin.app.workspace.trigger("file-menu", fileMenu, file, "folder-overview-file-context-menu", null);
fileMenu.showAtPosition({ x: e.pageX, y: e.pageY });
}
folderMenu(folder, e) {
const { plugin } = this;
const folderMenu = new import_obsidian33.Menu();
folderMenu.addItem((item) => {
item.setTitle("Edit folder overview");
item.setIcon("pencil");
item.onClick(async () => {
new FolderOverviewSettings(plugin.app, plugin, this.yaml, this.ctx, this.el, plugin instanceof FolderNotesPlugin ? plugin.settings.defaultOverview : plugin.settings.defaultOverviewSettings).open();
});
});
folderMenu.addSeparator();
folderMenu.addItem((item) => {
item.setTitle("Rename");
item.setIcon("pencil");
item.onClick(async () => {
if (plugin instanceof FolderNotesPlugin) {
new NewFolderNameModal(plugin.app, plugin, folder).open();
}
});
});
folderMenu.addItem((item) => {
item.setTitle("Delete");
item.setIcon("trash");
item.dom.addClass("is-warning");
item.dom.setAttribute("data-section", "danger");
item.onClick(() => {
plugin.app.fileManager.promptForFolderDeletion(folder);
});
});
folderMenu.addSeparator();
plugin.app.workspace.trigger("file-menu", folderMenu, folder, "folder-overview-folder-context-menu", null);
folderMenu.showAtPosition({ x: e.pageX, y: e.pageY });
}
editOverviewContextMenu(e) {
const { plugin } = this;
const menu = new import_obsidian33.Menu();
menu.addItem((item) => {
item.setTitle("Edit folder overview");
item.setIcon("pencil");
item.onClick(async () => {
new FolderOverviewSettings(plugin.app, plugin, this.yaml, this.ctx, this.el, plugin instanceof FolderNotesPlugin ? plugin.settings.defaultOverview : plugin.settings.defaultOverviewSettings).open();
});
});
menu.showAtPosition({ x: e.pageX, y: e.pageY });
}
getElFromOverview(path) {
const selector = `[data-path='${CSS.escape(path)}']`;
const el = this.listEl.querySelector(selector);
return el;
}
};
async function updateYaml(plugin, ctx, el, yaml, addLinkList) {
const NO_CODEBLOCK_END = -1;
const file = plugin.app.vault.getAbstractFileByPath(ctx.sourcePath);
if (!(file instanceof import_obsidian33.TFile))
return;
let stringYaml = (0, import_obsidian33.stringifyYaml)(yaml);
plugin.app.vault.process(file, (text) => {
const info = ctx.getSectionInfo(el);
if (stringYaml[stringYaml.length - 1] !== "\n") {
stringYaml += "\n";
}
if (info) {
const { lineStart } = info;
const lineEnd = getCodeBlockEndLine(text, lineStart);
if (lineEnd === NO_CODEBLOCK_END || !lineEnd)
return text;
const lineLength = lineEnd - lineStart;
const lines = text.split("\n");
let overviewBlock = `\`\`\`folder-overview
${stringYaml}\`\`\``;
overviewBlock += addLinkList ? `
<span class="fv-link-list-start" id="${yaml.id}"></span>
<span class="fv-link-list-end" id="${yaml.id}"></span>` : "";
lines.splice(lineStart, lineLength + 1, overviewBlock);
return lines.join("\n");
}
getOverviews(plugin, file).then((overviews) => {
overviews.forEach((overview) => {
if (overview.id !== yaml.id)
return;
const isInCallout = typeof overview.isInCallout === "boolean" ? overview.isInCallout : false;
updateYamlById(plugin, yaml.id, file, yaml, addLinkList, isInCallout);
});
});
return text;
});
}
async function getOverviews(plugin, file) {
if (!file)
return [];
const overviews = [];
const content = await plugin.app.vault.read(file);
if (!content)
return overviews;
const yamlBlocks = content.match(/^(?!>).*```folder-overview\n(?:^(?!>).*[\r\n]*)*?^```$/gm);
const calloutYamlBlocks = content.match(/^> ```folder-overview\n([\s\S]*?)```/gm);
if (calloutYamlBlocks) {
for (const block of calloutYamlBlocks) {
const cleanedBlock = block.replace(/^> ```folder-overview\n/, "").replace(/```$/, "").replace(/^> ?/gm, "");
const yaml = (0, import_obsidian33.parseYaml)(cleanedBlock);
if (yaml) {
yaml.isInCallout = true;
overviews.push(yaml);
}
}
}
if (!yamlBlocks)
return overviews;
for (const block of yamlBlocks) {
const yaml = (0, import_obsidian33.parseYaml)(block.replace("```folder-overview\n", "").replace("```", ""));
if (!yaml)
continue;
overviews.push(yaml);
}
return overviews;
}
async function hasOverviewYaml(plugin, file) {
const content = await plugin.app.vault.read(file);
if (!content)
return false;
const yamlBlocks = content.match(/```folder-overview\n([\s\S]*?)```/g);
return !!yamlBlocks;
}
var CustomMarkdownRenderChild = class extends import_obsidian33.MarkdownRenderChild {
constructor(el, folderOverview) {
super(el);
this.folderOverview = folderOverview;
}
onunload() {
this.folderOverview.disconnectListeners();
}
};
function sortFiles(files, yaml, plugin) {
var _a, _b;
if (!(yaml == null ? void 0 : yaml.sortBy)) {
const defaultSettings = plugin instanceof FolderNotesPlugin ? plugin.settings.defaultOverview : plugin.settings.defaultOverviewSettings;
yaml.sortBy = (_a = defaultSettings.sortBy) != null ? _a : "name";
yaml.sortByAsc = (_b = defaultSettings.sortByAsc) != null ? _b : false;
}
const collator = new Intl.Collator(void 0, { numeric: true, sensitivity: "base" });
const FOLDER_FIRST = -1;
const FILE_FIRST = 1;
const EQUAL = 0;
function compareFilesAndFolders(a, b) {
const a_IsFolder = a instanceof import_obsidian33.TFolder;
const b_IsFolder = b instanceof import_obsidian33.TFolder;
const a_IsFile = a instanceof import_obsidian33.TFile;
const b_IsFile = b instanceof import_obsidian33.TFile;
if (a_IsFolder && !b_IsFolder) {
return FOLDER_FIRST;
}
if (!a_IsFolder && b_IsFolder) {
return FILE_FIRST;
}
if (a_IsFolder && b_IsFolder) {
return yaml.sortByAsc ? collator.compare(a.name, b.name) : collator.compare(b.name, a.name);
}
if (a_IsFile && b_IsFile) {
return compareFiles(a, b);
}
return EQUAL;
}
function compareFiles(a, b) {
if (yaml.sortBy === "created") {
return yaml.sortByAsc ? a.stat.ctime - b.stat.ctime : b.stat.ctime - a.stat.ctime;
} else if (yaml.sortBy === "modified") {
return yaml.sortByAsc ? a.stat.mtime - b.stat.mtime : b.stat.mtime - a.stat.mtime;
} else if (yaml.sortBy === "name") {
return yaml.sortByAsc ? collator.compare(a.basename, b.basename) : collator.compare(b.basename, a.basename);
}
return 0;
}
files.sort(compareFilesAndFolders);
return files;
}
async function filterFiles(files, plugin, sourceFolderPath, depth, pathBlacklist, yaml, sourceFile) {
const filteredFiles = await Promise.all(files.map(async (file) => filterSingleFile(file, plugin, sourceFolderPath, depth, pathBlacklist, yaml, sourceFile)));
return filteredFiles.filter((file) => file !== null);
}
async function filterSingleFile(file, plugin, sourceFolderPath, depth, pathBlacklist, yaml, sourceFile) {
const folderPath = getFolderPathFromString(file.path);
const dontShowFolderNote = pathBlacklist.includes(file.path);
const isSubfolder = isFileInSubfolder(sourceFolderPath, folderPath);
const isSourceFile = sourceFile ? file.path === sourceFile.path : false;
const isFile = file instanceof import_obsidian33.TFile;
const includeTypes = yaml.includeTypes || [];
const extension = isFile ? file.extension.toLowerCase() : "";
const imageTypes = ["jpg", "jpeg", "png", "gif", "svg", "webp"];
const videoTypes = ["mp4", "webm", "ogv", "mov", "mkv"];
const audioTypes = [
"mp3",
"wav",
"m4a",
"3gp",
"flac",
"ogg",
"oga",
"opus"
];
if (isFile && !isFileTypeIncluded(extension, includeTypes, imageTypes, videoTypes, audioTypes)) {
return null;
}
const isExcludedFromOverview = await getIsExcludedFromOverview(plugin, file);
if (shouldExcludeFile(dontShowFolderNote, yaml.showFolderNotes, isSubfolder, isSourceFile, isExcludedFromOverview)) {
return null;
}
const fileDepth = getFileDepth(file.path, sourceFolderPath);
return fileDepth <= depth ? file : null;
}
function isFileTypeIncluded(extension, includeTypes, imageTypes, videoTypes, audioTypes) {
if (includeTypes.length === 0 || includeTypes.includes("all"))
return true;
if ((extension === "md" || extension === "markdown") && includeTypes.includes("markdown"))
return true;
if (extension === "canvas" && includeTypes.includes("canvas"))
return true;
if (extension === "pdf" && includeTypes.includes("pdf"))
return true;
if (imageTypes.includes(extension) && includeTypes.includes("image"))
return true;
if (videoTypes.includes(extension) && includeTypes.includes("video"))
return true;
if (audioTypes.includes(extension) && includeTypes.includes("audio"))
return true;
return false;
}
function isFileInSubfolder(sourceFolderPath, folderPath) {
return sourceFolderPath === "/" || folderPath.startsWith(sourceFolderPath);
}
async function getIsExcludedFromOverview(plugin, file) {
var _a;
if (plugin instanceof FolderNotesPlugin) {
const excluded = getExcludedFolder(plugin, file.path, true);
return (_a = excluded == null ? void 0 : excluded.excludeFromFolderOverview) != null ? _a : false;
}
return false;
}
function shouldExcludeFile(dontShowFolderNote, showFolderNotes, isSubfolder, isSourceFile, isExcludedFromOverview) {
return dontShowFolderNote && !showFolderNotes || !isSubfolder || isSourceFile || isExcludedFromOverview;
}
function getFileDepth(filePath, sourceFolderPath) {
return filePath.split("/").length - (sourceFolderPath === "/" ? 0 : sourceFolderPath.split("/").length);
}
function getAllFiles(files, sourceFolderPath, depth) {
const allFiles = [];
const getDepth = (filePath) => {
return filePath.split("/").length - sourceFolderPath.split("/").length;
};
files.forEach((file) => {
const fileDepth = getDepth(file.path);
if (file instanceof import_obsidian33.TFolder) {
if (fileDepth < depth) {
allFiles.push(...getAllFiles(file.children, sourceFolderPath, depth));
}
} else {
allFiles.push(file);
}
});
return allFiles;
}
// src/obsidian-folder-overview/src/suggesters/FolderSuggester.ts
var import_obsidian34 = require("obsidian");
var MAX_LOADED_FILES = 100;
var FolderSuggest2 = class extends import_obsidian34.AbstractInputSuggest {
constructor(inputEl, plugin, whitelistSuggester, folder) {
super(plugin.app, inputEl);
this.inputEl = inputEl;
this.whitelistSuggester = whitelistSuggester;
this.folder = folder;
this.plugin = plugin;
}
getSuggestions(input_str) {
const folders = [];
const lower_input_str = input_str.toLowerCase();
let files = [];
if (this.folder) {
files = this.folder.children.slice(0, MAX_LOADED_FILES);
} else {
files = this.plugin.app.vault.getAllLoadedFiles().slice(0, MAX_LOADED_FILES);
}
folders.push({ path: "File\u2019s parent folder path" });
if (this.plugin instanceof FolderNotesPlugin) {
folders.push({ path: "Path of folder linked to the file" });
}
files.forEach((folder) => {
if (folder instanceof import_obsidian34.TFolder && folder.path.toLowerCase().contains(lower_input_str) && (this.plugin instanceof FolderNotesPlugin ? !this.plugin.settings.excludeFolders.find((f) => f.path === folder.path) || this.whitelistSuggester : true)) {
folders.push(folder);
}
});
return folders;
}
renderSuggestion(folder, el) {
el.setText(folder.path);
}
selectSuggestion(folder) {
this.inputEl.value = folder.path;
this.inputEl.trigger("input");
this.close();
}
};
// src/obsidian-folder-overview/src/utils/ListComponent.ts
var import_obsidian35 = require("obsidian");
var ListComponent2 = class {
constructor(containerEl, values = [], defaultValues = []) {
this.emitter = new CustomEventEmitter2();
this.containerEl = containerEl;
this.controlEl = containerEl.querySelector(".setting-item-control") || containerEl;
this.listEl = this.controlEl.createDiv("setting-command-hotkeys");
this.addResetButton();
this.setValues(values);
this.defaultValues = defaultValues;
}
on(event, listener) {
this.emitter.on(event, listener);
}
off(event, listener) {
this.emitter.off(event, listener);
}
emit(event, data) {
this.emitter.emit(event, data);
}
setValues(values) {
this.removeElements();
this.values = values;
if (values.length !== 0) {
values.forEach((value) => {
this.addElement(value);
});
}
this.emit("update", this.values);
}
removeElements() {
this.listEl.empty();
}
addElement(value) {
this.listEl.createSpan("setting-hotkey", (span) => {
if (value.toLocaleLowerCase() === "md") {
span.innerText = "markdown";
} else {
span.innerText = value;
}
span.setAttribute("extension", value);
const removeSpan = span.createEl("span", {
cls: "ofn-list-item-remove setting-hotkey-icon"
});
const svgElement = removeSpan.createEl("span", { cls: "ofn-list-item-remove-icon" });
(0, import_obsidian35.setIcon)(svgElement, "x");
removeSpan.onClickEvent(() => {
this.removeValue(value);
span.remove();
});
});
}
async addValue(value) {
this.values.push(value);
this.addElement(value);
this.emit("add", value);
this.emit("update", this.values);
}
addResetButton() {
const resetButton = this.controlEl.createEl("span", {
cls: "clickable-icon setting-restore-hotkey-button"
});
(0, import_obsidian35.setIcon)(resetButton, "rotate-ccw");
resetButton.onClickEvent(() => {
this.setValues(this.defaultValues);
});
return this;
}
removeValue(value) {
this.values = this.values.filter((v) => v !== value);
this.listEl.find(`[extension='${value}']`).remove();
this.emit("remove", value);
this.emit("update", this.values);
}
};
// src/obsidian-folder-overview/src/settings.ts
var OVERVIEW_SETTINGS = {
id: "",
folderPath: "",
title: "{{folderName}} overview",
showTitle: false,
depth: 3,
includeTypes: ["folder", "markdown"],
style: "list",
disableFileTag: false,
sortBy: "name",
sortByAsc: true,
showEmptyFolders: false,
onlyIncludeSubfolders: false,
storeFolderCondition: true,
showFolderNotes: false,
disableCollapseIcon: true,
alwaysCollapse: false,
autoSync: true,
allowDragAndDrop: true,
hideLinkList: true,
hideFolderOverview: false,
useActualLinks: false,
fmtpIntegration: false,
titleSize: 1,
isInCallout: false
};
var GLOBAL_SETTINGS = {
autoUpdateLinks: false
};
var DEFAULT_SETTINGS = {
defaultOverviewSettings: OVERVIEW_SETTINGS,
globalSettings: GLOBAL_SETTINGS,
firstTimeInsertOverview: false
};
var MAX_INCLUDE_TYPES_FOR_DROPDOWN = 8;
var SettingsTab = class extends import_obsidian36.PluginSettingTab {
constructor(plugin) {
super(plugin.app, plugin);
}
display() {
const { containerEl } = this;
containerEl.createEl("h3", { text: "Global settings" });
new import_obsidian36.Setting(containerEl).setName("Auto-update links without opening the overview").setDesc("If enabled, the links that appear in the graph view will be updated even when you don't have the overview open somewhere.").addToggle((toggle) => toggle.setValue(this.plugin.settings.globalSettings.autoUpdateLinks).onChange(async (value) => {
this.plugin.settings.globalSettings.autoUpdateLinks = value;
await this.plugin.saveSettings();
if (value) {
this.plugin.fvIndexDB.init(true);
} else {
this.plugin.fvIndexDB.active = false;
}
}));
containerEl.createEl("h3", { text: "Overviews default settings" });
const pEl = containerEl.createEl("p", {
text: "Edit the default settings for new folder overviews, ",
cls: "setting-item-description"
});
const span = createSpan({
text: "this won't apply to already existing overviews.",
cls: ""
});
const accentColor = this.plugin.app.vault.getConfig("accentColor") || "#7d5bed";
span.setAttr("style", `color: ${accentColor};`);
pEl.appendChild(span);
this.display = this.display.bind(this);
createOverviewSettings(containerEl, this.plugin.settings.defaultOverviewSettings, this.plugin, this.plugin.settings.defaultOverviewSettings, this.display, void 0, void 0, void 0, this);
}
};
var createOrReplaceSetting = (container, section, changedSection, renderSetting) => {
let sectionContainer = container.querySelector(`.setting-${section}`);
if (sectionContainer) {
if (changedSection === section || changedSection === "all") {
sectionContainer.empty();
renderSetting(sectionContainer);
return;
} else {
return;
}
}
sectionContainer = container.createDiv({
cls: `setting-${section} overview-setting-item-fv`
});
renderSetting(sectionContainer);
};
async function createOverviewSettings(contentEl, yaml, plugin, defaultSettings, display, el, ctx, file, settingsTab, modal, changedSection) {
changedSection = changedSection != null ? changedSection : null;
createOrReplaceSetting(contentEl, "auto-sync", changedSection, (settingEl) => {
new import_obsidian36.Setting(settingEl).setName("Auto sync").setDesc("Choose if the overview should automatically update when you delete, create or rename a file/folder").addToggle((toggle) => toggle.setValue(yaml.autoSync).onChange(async (value) => {
yaml.autoSync = value;
updateSettings(contentEl, yaml, plugin, false, defaultSettings, el, ctx, file);
refresh(contentEl, yaml, plugin, defaultSettings, display, el, ctx, file, settingsTab, modal);
}));
});
createOrReplaceSetting(contentEl, "allow-drag-and-drop", changedSection, (settingEl) => {
new import_obsidian36.Setting(settingEl).setName("Allow drag and drop").setDesc("Choose if you want to allow drag and drop in the overview").addToggle((toggle) => toggle.setValue(yaml.allowDragAndDrop).onChange(async (value) => {
yaml.allowDragAndDrop = value;
updateSettings(contentEl, yaml, plugin, false, defaultSettings, el, ctx, file);
refresh(contentEl, yaml, plugin, defaultSettings, display, el, ctx, file, settingsTab, modal);
}));
});
createOrReplaceSetting(contentEl, "showTitle", changedSection, (settingEl) => {
new import_obsidian36.Setting(settingEl).setName("Show the title").setDesc("Choose if the title above the folder overview should be shown").addToggle((toggle) => toggle.setValue(yaml.showTitle).onChange(async (value) => {
yaml.showTitle = value;
updateSettings(contentEl, yaml, plugin, false, defaultSettings, el, ctx, file);
refresh(contentEl, yaml, plugin, defaultSettings, display, el, ctx, file, settingsTab, modal);
}));
});
createOrReplaceSetting(contentEl, "title-container-fn", changedSection, (settingEl) => {
new import_obsidian36.Setting(settingEl).setName("Title").setDesc(createFragment((frag) => {
const link = frag.createEl("a", {
text: "Find more information about the title in the documentation. There is also a list of variables you can use",
href: "https://lostpaul.github.io/obsidian-folder-notes/Folder%20overview/#title"
});
link.target = "_blank";
})).addText((text) => text.setValue((yaml == null ? void 0 : yaml.title) || "{{folderName}} overview").onChange(async (value) => {
yaml.title = value;
updateSettings(contentEl, yaml, plugin, false, defaultSettings, el, ctx, file);
}));
});
createOrReplaceSetting(contentEl, "title-size", changedSection, (settingEl) => {
const MIN_TITLE_SIZE = 1;
const MAX_TITLE_SIZE = 6;
new import_obsidian36.Setting(settingEl).setName("Title size").setDesc("The larger the number, the smaller the title will be displayed.").addSlider((slider) => slider.setValue(yaml.titleSize).setLimits(MIN_TITLE_SIZE, MAX_TITLE_SIZE, 1).setDynamicTooltip().onChange(async (value) => {
yaml.titleSize = value;
updateSettings(contentEl, yaml, plugin, false, defaultSettings, el, ctx, file);
refresh(contentEl, yaml, plugin, defaultSettings, display, el, ctx, file, settingsTab, modal);
}));
});
createOrReplaceSetting(contentEl, "folder-path", changedSection, (settingEl) => {
const folderPathSetting = new import_obsidian36.Setting(settingEl).setName("Folder path for the overview").setDesc(createFragment((frag) => {
frag.appendText("The overview will show the subfolders and files of the folder you choose here. ");
const link = frag.createEl("a", {
text: "Find more information about this setting in the documentation.",
href: "https://lostpaul.github.io/obsidian-folder-notes/Folder%20overview/#folder-path"
});
link.target = "_blank";
})).addSearch((search) => {
new FolderSuggest2(search.inputEl, plugin, false);
search.setPlaceholder("Folder path").setValue((yaml == null ? void 0 : yaml.folderPath) || "").onChange(async (value) => {
const whiteList = [
"File's parent folder path",
"Path of folder linked to the file"
];
if (value.trim() !== "" && !whiteList.includes(value.trim())) {
value = (0, import_obsidian36.normalizePath)(value);
}
if (!whiteList.includes(value.trim())) {
const abstractFile = plugin.app.vault.getAbstractFileByPath(value);
const isFolder = abstractFile instanceof import_obsidian36.TFolder;
if (!isFolder && value !== "") {
return;
}
}
yaml.folderPath = value;
updateSettings(contentEl, yaml, plugin, false, defaultSettings, el, ctx, file);
});
});
folderPathSetting.settingEl.classList.add("fn-overview-folder-path");
});
createOrReplaceSetting(contentEl, "use-actual-links", changedSection, (settingEl) => {
new import_obsidian36.Setting(settingEl).setName("Use actual links").setDesc("Choose if the links in the overview should be showed in the graph view. This requires a second list under the actual overview and which is hidden by default.").addToggle((toggle) => toggle.setValue(yaml.useActualLinks).onChange(async (value) => {
yaml.useActualLinks = value;
updateSettings(contentEl, yaml, plugin, yaml.useActualLinks, defaultSettings, el, ctx, file);
refresh(contentEl, yaml, plugin, defaultSettings, display, el, ctx, file, settingsTab, modal);
}));
});
createOrReplaceSetting(contentEl, "hide-folder-overview", changedSection, (settingEl) => {
const hideOverviewSeting = new import_obsidian36.Setting(settingEl).setName("Hide folder overview").setDesc("Choose if the folder overview should be hidden and instead only the link list should be shown").addToggle((toggle) => toggle.setValue(yaml.hideFolderOverview).onChange(async (value) => {
yaml.hideFolderOverview = value;
updateSettings(contentEl, yaml, plugin, false, defaultSettings, el, ctx, file);
refresh(contentEl, yaml, plugin, defaultSettings, display, el, ctx, file, settingsTab, modal);
}));
hideOverviewSeting.settingEl.classList.add("fn-hide-overview-setting");
});
createOrReplaceSetting(contentEl, "hide-link-list", changedSection, (settingEl) => {
const hideLinkListSetting = new import_obsidian36.Setting(settingEl).setName("Hide link list").setDesc("Choose if only link list under the folder overview should be shown").addToggle((toggle) => toggle.setValue(yaml.hideLinkList).onChange(async (value) => {
yaml.hideLinkList = value;
updateSettings(contentEl, yaml, plugin, false, defaultSettings, el, ctx, file);
refresh(contentEl, yaml, plugin, defaultSettings, display, el, ctx, file, settingsTab, modal);
}));
hideLinkListSetting.settingEl.classList.add("fn-hide-link-list-setting");
});
createOrReplaceSetting(contentEl, "overview-style", changedSection, (settingEl) => {
new import_obsidian36.Setting(settingEl).setName("Overview style").setDesc("Choose the style of the overview (grid style soon)").addDropdown((dropdown) => dropdown.addOption("list", "List").addOption("explorer", "Explorer").setValue((yaml == null ? void 0 : yaml.style) || "list").onChange(async (value) => {
yaml.style = value;
updateSettings(contentEl, yaml, plugin, false, defaultSettings, el, ctx, file);
refresh(contentEl, yaml, plugin, defaultSettings, display, el, ctx, file, settingsTab, modal);
}));
});
createOrReplaceSetting(contentEl, "include-types", changedSection, (settingEl) => {
var _a, _b;
const setting = new import_obsidian36.Setting(settingEl);
setting.setName("Include types");
const list = new ListComponent2(setting.settingEl, yaml.includeTypes || [], ["markdown", "folder"]);
list.on("update", (values) => {
yaml.includeTypes = values;
updateSettings(contentEl, yaml, plugin, false, defaultSettings, el, ctx, file);
refresh(contentEl, yaml, plugin, defaultSettings, display, el, ctx, file, settingsTab, modal, "include-types");
});
if ((((_a = yaml == null ? void 0 : yaml.includeTypes) == null ? void 0 : _a.length) || 0) < MAX_INCLUDE_TYPES_FOR_DROPDOWN && !((_b = yaml.includeTypes) == null ? void 0 : _b.includes("all"))) {
setting.addDropdown((dropdown) => {
if (!yaml.includeTypes) {
yaml.includeTypes = plugin instanceof FolderNotesPlugin ? plugin.settings.defaultOverview.includeTypes : plugin.settings.defaultOverviewSettings.includeTypes || [];
}
yaml.includeTypes = yaml.includeTypes.map((type) => type.toLowerCase());
const options = [
{ value: "markdown", label: "Markdown" },
{ value: "folder", label: "Folder" },
{ value: "canvas", label: "Canvas" },
{ value: "pdf", label: "PDF" },
{ value: "image", label: "Image" },
{ value: "audio", label: "Audio" },
{ value: "video", label: "Video" },
{ value: "other", label: "All other file types" },
{ value: "all", label: "All file types" }
];
options.forEach((option) => {
var _a2;
if (!((_a2 = yaml.includeTypes) == null ? void 0 : _a2.includes(option.value))) {
dropdown.addOption(option.value, option.label);
}
});
dropdown.addOption("+", "+");
dropdown.setValue("+");
dropdown.onChange(async (value) => {
var _a2;
if (value === "all") {
yaml.includeTypes = (_a2 = yaml.includeTypes) == null ? void 0 : _a2.filter((type) => type === "folder");
list.setValues(yaml.includeTypes);
}
await list.addValue(value.toLowerCase());
updateSettings(contentEl, yaml, plugin, false, defaultSettings, el, ctx, file);
refresh(contentEl, yaml, plugin, defaultSettings, display, el, ctx, file, settingsTab, modal, "include-types");
});
});
}
});
createOrReplaceSetting(contentEl, "file-tag", changedSection, (settingEl) => {
new import_obsidian36.Setting(settingEl).setName("Disable file tag").setDesc("Choose if the file tag should be shown after the file name").addToggle((toggle) => {
toggle.setValue(yaml.disableFileTag).onChange(async (value) => {
yaml.disableFileTag = value;
updateSettings(contentEl, yaml, plugin, false, defaultSettings, el, ctx, file);
});
});
});
createOrReplaceSetting(contentEl, "show-folder-notes", changedSection, (settingEl) => {
new import_obsidian36.Setting(settingEl).setName("Show folder notes").setDesc("Choose if folder notes (the note itself and not the folder name) should be shown in the overview").addToggle((toggle) => toggle.setValue(yaml.showFolderNotes).onChange(async (value) => {
yaml.showFolderNotes = value;
updateSettings(contentEl, yaml, plugin, false, defaultSettings, el, ctx, file);
}));
});
createOrReplaceSetting(contentEl, "file-depth", changedSection, (settingEl) => {
const DEFAULT_DEPTH = 2;
const MAX_DEPTH = 10;
new import_obsidian36.Setting(settingEl).setName("File depth").setDesc("File & folder = +1 depth").addSlider((slider) => slider.setValue((yaml == null ? void 0 : yaml.depth) || DEFAULT_DEPTH).setLimits(1, MAX_DEPTH, 1).setDynamicTooltip().onChange(async (value) => {
yaml.depth = value;
updateSettings(contentEl, yaml, plugin, false, defaultSettings, el, ctx, file);
}));
});
createOrReplaceSetting(contentEl, "sort-files", changedSection, (settingEl) => {
new import_obsidian36.Setting(settingEl).setName("Sort files by").setDesc("Choose how the files should be sorted").addDropdown((dropdown) => dropdown.addOption("name", "Name").addOption("created", "Created").addOption("modified", "Modified").setValue((yaml == null ? void 0 : yaml.sortBy) || "name").onChange(async (value) => {
yaml.sortBy = value;
updateSettings(contentEl, yaml, plugin, false, defaultSettings, el, ctx, file);
})).addDropdown((dropdown) => {
dropdown.addOption("desc", "Descending").addOption("asc", "Ascending");
if (yaml.sortByAsc) {
dropdown.setValue("asc");
} else {
dropdown.setValue("desc");
}
dropdown.onChange(async (value) => {
yaml.sortByAsc = value === "asc";
updateSettings(contentEl, yaml, plugin, false, defaultSettings, el, ctx, file);
});
});
});
createOrReplaceSetting(contentEl, "show-empty-folders", changedSection, (settingEl) => {
new import_obsidian36.Setting(settingEl).setName("Show folder names of folders that appear empty in the folder overview").setDesc("Show the names of folders that appear to have no files/folders in the folder overview. That's mostly the case when you set the file depth to 1.").addToggle((toggle) => {
toggle.setValue(yaml.showEmptyFolders).onChange(async (value) => {
yaml.showEmptyFolders = value;
yaml.onlyIncludeSubfolders = false;
updateSettings(contentEl, yaml, plugin, false, defaultSettings, el, ctx, file);
refresh(contentEl, yaml, plugin, defaultSettings, display, el, ctx, file, settingsTab, modal);
});
});
});
createOrReplaceSetting(contentEl, "show-empty-folders-only-first-level", changedSection, (settingEl) => {
new import_obsidian36.Setting(settingEl).setName("Only show empty folders which are on the first level of the folder overview").addToggle((toggle) => {
toggle.setValue(yaml.onlyIncludeSubfolders).onChange(async (value) => {
yaml.onlyIncludeSubfolders = value;
updateSettings(contentEl, yaml, plugin, false, defaultSettings, el, ctx, file);
});
});
});
createOrReplaceSetting(contentEl, "disable-collapse-icon", changedSection, (settingEl) => {
new import_obsidian36.Setting(settingEl).setName("Disable collapse icon for folder notes").setDesc("Remove the collapse icon next to the folder name for folder notes when they only contain the folder note itself").addToggle((toggle) => {
toggle.setValue(yaml.disableCollapseIcon).onChange(async (value) => {
yaml.disableCollapseIcon = value;
updateSettings(contentEl, yaml, plugin, false, defaultSettings, el, ctx, file);
});
});
});
createOrReplaceSetting(contentEl, "store-collapse-condition", changedSection, (settingEl) => {
new import_obsidian36.Setting(settingEl).setName("Store collapsed condition").setDesc("Choose if the collapsed condition should be stored until you restart Obsidian").addToggle((toggle) => toggle.setValue(yaml.storeFolderCondition).onChange(async (value) => {
yaml.storeFolderCondition = value;
updateSettings(contentEl, yaml, plugin, false, defaultSettings, el, ctx, file);
}));
});
createOrReplaceSetting(contentEl, "collapse-all-by-default", changedSection, (settingEl) => {
new import_obsidian36.Setting(settingEl).setName("Collapse all in the tree by default").setDesc("Collapse every folder in the file explorer in the overview by default").addToggle((toggle) => {
toggle.setValue(yaml.alwaysCollapse).onChange(async (value) => {
yaml.alwaysCollapse = value;
updateSettings(contentEl, yaml, plugin, false, defaultSettings, el, ctx, file);
});
});
});
createOrReplaceSetting(contentEl, "fmtp-integration", changedSection, (settingEl) => {
new import_obsidian36.Setting(settingEl).setName("Front Matter Title Plugin integration").setDesc("Replace the folder/file name with the title from the Front Matter Title Plugin. This requires the plugin to be installed and enabled.").addToggle((toggle) => toggle.setValue(yaml.fmtpIntegration).onChange(async (value) => {
yaml.fmtpIntegration = value;
updateSettings(contentEl, yaml, plugin, false, defaultSettings, el, ctx, file);
}));
});
updateSettings(contentEl, yaml, plugin, false, defaultSettings, el, ctx, file);
}
function determineVisibleSections(yaml, plugin) {
var _a;
let showDisableFileTag = false;
(_a = yaml.includeTypes) == null ? void 0 : _a.forEach((type) => {
if (type !== "markdown" && type !== "folder") {
showDisableFileTag = true;
}
});
if (yaml.includeTypes.length === 0) {
showDisableFileTag = false;
}
return {
"setting-title-container-fn": yaml.showTitle,
"setting-title-size": yaml.showTitle,
"setting-store-collapse-condition": yaml.style === "explorer",
"setting-file-tag": showDisableFileTag,
"setting-show-empty-folders": yaml.style === "list",
"setting-show-empty-folders-only-first-level": yaml.showEmptyFolders && yaml.style === "list",
"setting-disable-collapse-icon": yaml.style === "explorer",
"setting-collapse-all-by-default": yaml.style === "explorer",
"setting-allow-drag-and-drop": yaml.style === "explorer",
"setting-hide-folder-overview": !yaml.hideLinkList && yaml.useActualLinks,
"setting-hide-link-list": !yaml.hideFolderOverview && yaml.useActualLinks,
"setting-fmtp-integration": !!plugin.app.plugins.getPlugin("obsidian-front-matter-title-plugin")
};
}
async function updateSettings(contentEl, yaml, plugin, addLinkList, defaultSettings, el, ctx, file) {
const visibleSections = determineVisibleSections(yaml, plugin);
toggleSections(contentEl, visibleSections);
if (!yaml.id) {
plugin.saveSettings();
if (file === void 0) {
plugin.updateOverviewView(plugin);
}
return;
}
if (el && ctx) {
await updateYaml(plugin, ctx, el, yaml, addLinkList);
}
if (file) {
await updateYamlById(plugin, yaml.id, file, yaml, addLinkList, yaml.isInCallout);
}
}
function refresh(contentEl, yaml, plugin, defaultSettings, display, el, ctx, file, settingsTab, modal, changedSection) {
if (file) {
contentEl = contentEl.parentElement;
}
display(contentEl, yaml, plugin, defaultSettings, display, el, ctx, file, settingsTab, modal, changedSection);
}
function toggleSections(contentEl, sections) {
Object.entries(sections).forEach(([sectionClass, shouldShow]) => {
const sectionElements = contentEl.querySelectorAll(`.${sectionClass}`);
sectionElements.forEach((section) => {
if (shouldShow && section) {
section.classList.remove("hide");
} else {
section == null ? void 0 : section.classList.add("hide");
}
});
});
}
// src/settings/FolderOverviewSettings.ts
async function renderFolderOverview(settingsTab) {
const { plugin } = settingsTab;
const defaultOverviewSettings = plugin.settings.defaultOverview;
const containerEl = settingsTab.settingsPage;
containerEl.createEl("h3", { text: "Global settings" });
new import_obsidian37.Setting(containerEl).setName("Auto-update links without opening the overview").setDesc("If enabled, the links that appear in the graph view will be updated even when you don't have the overview open somewhere.").addToggle((toggle) => toggle.setValue(plugin.settings.fvGlobalSettings.autoUpdateLinks).onChange(async (value) => {
plugin.settings.fvGlobalSettings.autoUpdateLinks = value;
await plugin.saveSettings();
if (value) {
plugin.fvIndexDB.init(true);
} else {
plugin.fvIndexDB.active = false;
}
}));
containerEl.createEl("h3", { text: "Overviews default settings" });
const pEl = containerEl.createEl("p", {
text: "Edit the default settings for new folder overviews, ",
cls: "setting-item-description"
});
const span = createSpan({ text: "this won't apply to already existing overviews.", cls: "" });
const accentColor = settingsTab.app.vault.getConfig("accentColor") || "#7d5bed";
span.setAttr("style", `color: ${accentColor};`);
pEl.appendChild(span);
createOverviewSettings(containerEl, defaultOverviewSettings, plugin, plugin.settings.defaultOverview, settingsTab.display, void 0, void 0, void 0, settingsTab);
}
// src/settings/ExcludedFoldersSettings.ts
var import_obsidian39 = require("obsidian");
// src/ExcludeFolders/modals/WhitelistedFoldersSettings.ts
var import_obsidian38 = require("obsidian");
// src/ExcludeFolders/WhitelistFolder.ts
var WhitelistedFolder = class {
constructor(path, position, id, plugin) {
this.type = "folder";
this.id = id || crypto.randomUUID();
this.path = path;
this.subFolders = plugin.settings.excludeFolderDefaultSettings.subFolders;
this.position = position;
this.string = "";
}
};
// src/ExcludeFolders/modals/WhitelistedFoldersSettings.ts
var WhitelistedFoldersSettings = class extends import_obsidian38.Modal {
constructor(settingsTab) {
super(settingsTab.app);
this.plugin = settingsTab.plugin;
this.settingsTab = settingsTab;
this.app = settingsTab.app;
}
onOpen() {
const { contentEl } = this;
contentEl.createEl("h2", { text: "Manage whitelisted folders" });
new import_obsidian38.Setting(contentEl).setName("Add whitelisted folder").setClass("add-exclude-folder-item").addButton((cb) => {
cb.setIcon("plus");
cb.setClass("add-exclude-folder");
cb.setTooltip("Add whitelisted folder");
cb.onClick(() => {
const whitelistedFolder = new WhitelistedFolder("", this.plugin.settings.whitelistFolders.length, void 0, this.plugin);
addWhitelistFolderListItem(this.plugin.settingsTab, contentEl, whitelistedFolder);
addWhitelistedFolder(this.plugin, whitelistedFolder);
this.settingsTab.display();
});
});
this.plugin.settings.whitelistFolders.sort((a, b) => a.position - b.position).forEach((whitelistedFolder) => {
var _a, _b;
if (((_a = whitelistedFolder.string) == null ? void 0 : _a.trim()) !== "" && ((_b = whitelistedFolder.path) == null ? void 0 : _b.trim()) === "") {
addWhitelistedPatternListItem(this.settingsTab, contentEl, whitelistedFolder);
} else {
addWhitelistFolderListItem(this.settingsTab, contentEl, whitelistedFolder);
}
});
}
onClose() {
const { contentEl } = this;
contentEl.empty();
}
};
// src/settings/ExcludedFoldersSettings.ts
async function renderExcludeFolders(settingsTab) {
const containerEl = settingsTab.settingsPage;
const manageExcluded = new import_obsidian39.Setting(containerEl).setHeading().setClass("fn-excluded-folder-heading").setName("Manage excluded folders");
const desc3 = document.createDocumentFragment();
desc3.append("Add {regex} at the beginning of the folder name to use a regex pattern.", desc3.createEl("br"), "Use * before and after to exclude folders that include the name between the *s.", desc3.createEl("br"), "Use * before the folder name to exclude folders that end with the folder name.", desc3.createEl("br"), "Use * after the folder name to exclude folders that start with the folder name.");
manageExcluded.setDesc(desc3);
manageExcluded.infoEl.appendText("The regexes and wildcards are only for the folder name, not the path.");
manageExcluded.infoEl.createEl("br");
manageExcluded.infoEl.appendText("If you want to switch to a folder path delete the pattern first.");
manageExcluded.infoEl.style.color = settingsTab.app.vault.getConfig("accentColor") || "#7d5bed";
new import_obsidian39.Setting(containerEl).setName("Whitelisted folders").setDesc("Folders that override the excluded folders/patterns").addButton((cb) => {
cb.setButtonText("Manage");
cb.setCta();
cb.onClick(async () => {
new WhitelistedFoldersSettings(settingsTab).open();
});
});
new import_obsidian39.Setting(containerEl).setName("Exclude folder default settings").addButton((cb) => {
cb.setButtonText("Manage");
cb.setCta();
cb.onClick(async () => {
new ExcludedFolderSettings(settingsTab.app, settingsTab.plugin, settingsTab.plugin.settings.excludeFolderDefaultSettings).open();
});
});
new import_obsidian39.Setting(containerEl).setName("Exclude pattern default settings").addButton((cb) => {
cb.setButtonText("Manage");
cb.setCta();
cb.onClick(async () => {
new PatternSettings(settingsTab.app, settingsTab.plugin, settingsTab.plugin.settings.excludePatternDefaultSettings).open();
});
});
new import_obsidian39.Setting(containerEl).setName("Add excluded folder").setClass("add-exclude-folder-item").addButton((cb) => {
cb.setIcon("plus");
cb.setClass("add-exclude-folder");
cb.setTooltip("Add excluded folder");
cb.onClick(() => {
const excludedFolder = new ExcludedFolder("", settingsTab.plugin.settings.excludeFolders.length, void 0, settingsTab.plugin);
addExcludeFolderListItem(settingsTab, containerEl, excludedFolder);
addExcludedFolder(settingsTab.plugin, excludedFolder);
settingsTab.display();
});
});
settingsTab.plugin.settings.excludeFolders.filter((folder) => !folder.hideInSettings).sort((a, b) => a.position - b.position).forEach((excludedFolder) => {
var _a, _b;
if (((_a = excludedFolder.string) == null ? void 0 : _a.trim()) !== "" && ((_b = excludedFolder.path) == null ? void 0 : _b.trim()) === "") {
addExcludePatternListItem(settingsTab, containerEl, excludedFolder);
} else {
addExcludeFolderListItem(settingsTab, containerEl, excludedFolder);
}
});
}
// src/settings/SettingsTab.ts
var DEFAULT_SETTINGS2 = {
syncFolderName: true,
ctrlKey: true,
altKey: false,
hideFolderNote: true,
templatePath: "",
autoCreate: false,
autoCreateFocusFiles: true,
autoCreateForAttachmentFolder: false,
autoCreateForFiles: false,
enableCollapsing: false,
excludeFolders: [],
whitelistFolders: [],
showDeleteConfirmation: true,
underlineFolder: true,
stopWhitespaceCollapsing: true,
underlineFolderInPath: true,
openFolderNoteOnClickInPath: true,
openInNewTab: false,
focusExistingTab: false,
oldFolderNoteName: void 0,
folderNoteName: "{{folder_name}}",
folderNoteType: ".md",
disableFolderHighlighting: false,
newFolderNoteName: "{{folder_name}}",
storageLocation: "insideFolder",
syncDelete: false,
showRenameConfirmation: true,
defaultOverview: {
id: "",
folderPath: "",
title: "{{folderName}} overview",
showTitle: false,
depth: 3,
includeTypes: ["folder", "markdown"],
style: "list",
disableFileTag: false,
sortBy: "name",
sortByAsc: true,
showEmptyFolders: false,
onlyIncludeSubfolders: false,
storeFolderCondition: true,
showFolderNotes: false,
disableCollapseIcon: true,
alwaysCollapse: false,
autoSync: true,
allowDragAndDrop: true,
hideLinkList: true,
hideFolderOverview: false,
useActualLinks: false,
fmtpIntegration: false,
titleSize: 1,
isInCallout: false
},
useSubmenus: true,
syncMove: true,
frontMatterTitle: {
enabled: false,
explorer: true,
path: true
},
settingsTab: "general",
supportedFileTypes: ["md", "canvas", "base"],
boldName: false,
boldNameInPath: false,
cursiveName: false,
cursiveNameInPath: false,
disableOpenFolderNoteOnClick: false,
openByClick: true,
openWithCtrl: false,
openWithAlt: false,
excludeFolderDefaultSettings: {
type: "folder",
path: "",
id: crypto.randomUUID(),
subFolders: true,
disableSync: true,
disableAutoCreate: true,
disableFolderNote: false,
enableCollapsing: false,
position: 0,
excludeFromFolderOverview: false,
string: "",
hideInSettings: false,
detached: false,
showFolderNote: false
},
excludePatternDefaultSettings: {
type: "pattern",
path: "",
id: crypto.randomUUID(),
subFolders: true,
disableSync: true,
disableAutoCreate: true,
disableFolderNote: false,
enableCollapsing: false,
position: 0,
excludeFromFolderOverview: false,
string: "",
hideInSettings: false,
detached: false,
showFolderNote: false
},
hideCollapsingIcon: false,
hideCollapsingIconForEmptyFolders: false,
tabManagerEnabled: true,
ignoreAttachmentFolder: true,
deleteFilesAction: "trash",
openSidebar: {
mobile: false,
desktop: true
},
highlightFolder: true,
persistentSettingsTab: {
afterRestart: true,
afterChangingTab: true
},
firstTimeInsertOverview: true,
fvGlobalSettings: {
autoUpdateLinks: false
}
};
var SettingsTab2 = class extends import_obsidian40.PluginSettingTab {
constructor(app2, plugin) {
super(app2, plugin);
this.TABS = {
GENERAL: {
name: "General",
id: "general"
},
FOLDER_OVERVIEW: {
name: "Folder overview",
id: "folder_overview"
},
EXCLUDE_FOLDERS: {
name: "Exclude folders",
id: "exclude_folders"
},
FILE_EXPLORER: {
name: "File explorer",
id: "file_explorer"
},
PATH: {
name: "Path",
id: "path"
}
};
}
renderSettingsPage(tabId) {
this.settingsPage.empty();
switch (tabId.toLocaleLowerCase()) {
case this.TABS.GENERAL.id:
renderGeneral(this);
break;
case this.TABS.FOLDER_OVERVIEW.id:
renderFolderOverview(this);
break;
case this.TABS.EXCLUDE_FOLDERS.id:
renderExcludeFolders(this);
break;
case this.TABS.FILE_EXPLORER.id:
renderFileExplorer(this);
break;
case this.TABS.PATH.id:
renderPath(this);
break;
}
}
display(contentEl, yaml, plugin, defaultSettings, display, el, ctx, file, settingsTab) {
var _a;
plugin = (_a = this == null ? void 0 : this.plugin) != null ? _a : plugin;
if (plugin) {
plugin.settingsOpened = true;
}
settingsTab = this != null ? this : settingsTab;
const { containerEl } = settingsTab;
if (plugin && !plugin.settings.persistentSettingsTab.afterChangingTab) {
plugin.settings.settingsTab = this.TABS.GENERAL.id;
}
containerEl.empty();
const tabBar = containerEl.createEl("nav", { cls: "fn-settings-tab-bar" });
for (const [tabId, tabInfo] of Object.entries(settingsTab.TABS)) {
const tabEl = tabBar.createEl("div", { cls: "fn-settings-tab" });
tabEl.createEl("div", { cls: "fn-settings-tab-name", text: tabInfo.name });
if (plugin && plugin.settings.settingsTab.toLocaleLowerCase() === tabId.toLocaleLowerCase()) {
tabEl.addClass("fn-settings-tab-active");
}
tabEl.addEventListener("click", () => {
for (const child of tabBar.children) {
child.removeClass("fn-settings-tab-active");
if (!plugin) {
return;
}
plugin.settings.settingsTab = tabId.toLocaleLowerCase();
plugin.saveSettings();
}
tabEl.addClass("fn-settings-tab-active");
if (!settingsTab) {
return;
}
settingsTab.renderSettingsPage(tabId);
});
}
settingsTab.settingsPage = containerEl.createDiv({ cls: "fn-settings-page" });
if (plugin) {
if (plugin.settings.persistentSettingsTab) {
settingsTab.renderSettingsPage(plugin.settings.settingsTab);
} else {
settingsTab.renderSettingsPage(this.TABS.GENERAL.id);
}
}
}
renameFolderNotes() {
var _a, _b, _c;
new import_obsidian40.Notice("Starting to update folder notes...");
const oldTemplate = (_a = this.plugin.settings.oldFolderNoteName) != null ? _a : "{{folder_name}}";
for (const folder of this.app.vault.getAllLoadedFiles()) {
if (folder instanceof import_obsidian40.TFolder) {
const folderNote = getFolderNote(this.plugin, folder.path, void 0, void 0, oldTemplate);
if (!(folderNote instanceof import_obsidian40.TFile)) {
continue;
}
const folderName = (_b = extractFolderName(oldTemplate, folderNote.basename)) != null ? _b : "";
const newFolderNoteName = this.plugin.settings.folderNoteName.replace("{{folder_name}}", folderName);
let newPath = "";
if (this.plugin.settings.storageLocation === "parentFolder") {
if (getFolderPathFromString(folder.path).trim() === "/") {
newPath = `${newFolderNoteName}.${folderNote.extension}`;
} else {
newPath = `${(_c = folderNote.parent) == null ? void 0 : _c.path}/${newFolderNoteName}.${folderNote.extension}`;
}
} else if (this.plugin.settings.storageLocation === "insideFolder") {
newPath = `${folder.path}/${newFolderNoteName}.${folderNote.extension}`;
}
this.app.fileManager.renameFile(folderNote, newPath);
}
}
this.plugin.settings.oldFolderNoteName = this.plugin.settings.folderNoteName;
this.plugin.saveSettings();
new import_obsidian40.Notice("Finished updating folder notes");
}
switchStorageLocation(oldMethod) {
new import_obsidian40.Notice("Starting to switch storage location...");
this.app.vault.getAllLoadedFiles().forEach((file) => {
if (file instanceof import_obsidian40.TFolder) {
const folderNote = getFolderNote(this.plugin, file.path, oldMethod);
if (folderNote instanceof import_obsidian40.TFile) {
if (this.plugin.settings.storageLocation === "parentFolder") {
let newPath = "";
if (getFolderPathFromString(file.path).trim() === "") {
newPath = `${folderNote.name}`;
} else {
newPath = `${getFolderPathFromString(file.path)}/${folderNote.name}`;
}
this.plugin.app.fileManager.renameFile(folderNote, newPath);
} else if (this.plugin.settings.storageLocation === "insideFolder") {
if (getFolderPathFromString(folderNote.path) === file.path) {
return;
}
const newPath = `${file.path}/${folderNote.name}`;
this.plugin.app.fileManager.renameFile(folderNote, newPath);
}
}
}
});
new import_obsidian40.Notice("Finished switching storage location");
}
onClose() {
this.plugin.settingsOpened = false;
}
};
// src/Commands.ts
var import_obsidian41 = require("obsidian");
var Commands = class {
constructor(app2, plugin) {
this.plugin = plugin;
this.app = app2;
}
registerCommands() {
this.editorCommands();
this.fileCommands();
this.regularCommands();
}
regularCommands() {
this.plugin.addCommand({
id: "turn-into-folder-note",
name: "Use this file as the folder note for its parent folder",
checkCallback: (checking) => {
const file = this.app.workspace.getActiveFile();
if (!(file instanceof import_obsidian41.TFile))
return false;
const folder = file.parent;
if (!folder || !(folder instanceof import_obsidian41.TFolder))
return false;
if (folder.path === "" || folder.path === "/")
return false;
const folderNote = getFolderNote(this.plugin, folder.path);
if (folderNote instanceof import_obsidian41.TFile && folderNote === file)
return false;
if (checking)
return true;
turnIntoFolderNote(this.plugin, file, folder, folderNote);
}
});
this.plugin.addCommand({
id: "create-folder-note",
name: "Make a folder with this file as its folder note",
callback: async () => {
var _a, _b, _c;
const file = this.app.workspace.getActiveFile();
if (!(file instanceof import_obsidian41.TFile))
return;
let newPath = ((_a = file.parent) == null ? void 0 : _a.path) + "/" + file.basename;
if (((_b = file.parent) == null ? void 0 : _b.path) === "" || ((_c = file.parent) == null ? void 0 : _c.path) === "/") {
newPath = file.basename;
}
if (this.plugin.app.vault.getAbstractFileByPath(newPath)) {
return new import_obsidian41.Notice("Folder already exists");
}
const automaticallyCreateFolderNote = this.plugin.settings.autoCreate;
this.plugin.settings.autoCreate = false;
this.plugin.saveSettings();
await this.plugin.app.vault.createFolder(newPath);
const folder = this.plugin.app.vault.getAbstractFileByPath(newPath);
if (!(folder instanceof import_obsidian41.TFolder))
return;
createFolderNote(this.plugin, folder.path, true, "." + file.extension, false, file);
this.plugin.settings.autoCreate = automaticallyCreateFolderNote;
this.plugin.saveSettings();
}
});
this.plugin.addCommand({
id: "create-folder-note-for-current-folder",
name: "Create markdown folder note for this folder",
checkCallback: (checking) => {
const file = this.app.workspace.getActiveFile();
if (!(file instanceof import_obsidian41.TFile))
return false;
const folder = file.parent;
if (!(folder instanceof import_obsidian41.TFolder))
return false;
if (folder.path === "" || folder.path === "/")
return false;
if (checking)
return true;
createFolderNote(this.plugin, folder.path, true, ".md", false);
}
});
this.plugin.settings.supportedFileTypes.forEach((fileType) => {
if (fileType === "md")
return;
this.plugin.addCommand({
id: `create-${fileType}-folder-note-for-current-folder`,
name: `Create ${fileType} folder note for this folder`,
checkCallback: (checking) => {
const file = this.app.workspace.getActiveFile();
if (!(file instanceof import_obsidian41.TFile))
return false;
const folder = file.parent;
if (!(folder instanceof import_obsidian41.TFolder))
return false;
if (folder.path === "" || folder.path === "/")
return false;
if (checking)
return true;
createFolderNote(this.plugin, folder.path, true, "." + fileType, false);
}
});
});
this.plugin.settings.supportedFileTypes.forEach((fileType) => {
const type = fileType === "md" ? "markdown" : fileType;
this.plugin.addCommand({
id: `create-${type}-folder-note-for-active-file-explorer-folder`,
name: `Create ${type} folder note for current active folder in file explorer`,
checkCallback: (checking) => {
const folder = getFileExplorerActiveFolder();
if (!folder)
return false;
const folderNote = getFolderNote(this.plugin, folder.path);
if (folderNote instanceof import_obsidian41.TFile)
return false;
if (checking)
return true;
const ext = "." + fileType;
const { path } = folder;
createFolderNote(this.plugin, path, true, ext, false);
}
});
});
this.plugin.addCommand({
id: "delete-folder-note-for-current-folder",
name: "Delete this folder's linked note",
checkCallback: (checking) => {
const file = this.app.workspace.getActiveFile();
if (!(file instanceof import_obsidian41.TFile))
return false;
const folder = file.parent;
if (!(folder instanceof import_obsidian41.TFolder))
return false;
const folderNote = getFolderNote(this.plugin, folder.path);
if (!(folderNote instanceof import_obsidian41.TFile))
return false;
if (checking)
return true;
deleteFolderNote(this.plugin, folderNote, true);
}
});
this.plugin.addCommand({
id: "delete-folder-note-of-active-file-explorer-folder",
name: "Delete folder note of current active folder in file explorer",
checkCallback: (checking) => {
const folder = getFileExplorerActiveFolder();
if (!folder)
return false;
const folderNote = getFolderNote(this.plugin, folder.path);
if (!(folderNote instanceof import_obsidian41.TFile))
return false;
if (checking)
return true;
deleteFolderNote(this.plugin, folderNote, true);
}
});
this.plugin.addCommand({
id: "open-folder-note-for-current-folder",
name: "Open this folder's linked note",
checkCallback: (checking) => {
const file = this.app.workspace.getActiveFile();
if (!(file instanceof import_obsidian41.TFile))
return false;
const folder = file.parent;
if (!(folder instanceof import_obsidian41.TFolder))
return false;
const folderNote = getFolderNote(this.plugin, folder.path);
if (!(folderNote instanceof import_obsidian41.TFile))
return false;
if (checking)
return true;
openFolderNote(this.plugin, folderNote);
}
});
this.plugin.addCommand({
id: "open-folder-note-of-active-file-explorer-folder",
name: "Open folder note of current active folder in file explorer",
checkCallback: (checking) => {
const folder = getFileExplorerActiveFolder();
if (!folder)
return false;
const folderNote = getFolderNote(this.plugin, folder.path);
if (!(folderNote instanceof import_obsidian41.TFile))
return false;
if (checking)
return true;
openFolderNote(this.plugin, folderNote);
}
});
this.plugin.addCommand({
id: "create-folder-note-from-selected-text",
name: "Create folder note from selection",
editorCheckCallback: (checking, editor, view) => {
const text = editor.getSelection().trim();
const { file } = view;
if (!(file instanceof import_obsidian41.TFile))
return false;
if (text && text.trim() !== "") {
if (checking) {
return true;
}
const blacklist = ["*", "\\", '"', "/", "<", ">", "?", "|", ":"];
for (const char of blacklist) {
if (text.includes(char)) {
new import_obsidian41.Notice('File name cannot contain any of the following characters: * " \\ / < > : | ?');
return false;
}
}
if (text.endsWith(".")) {
new import_obsidian41.Notice("File name cannot end with a dot");
return;
}
let folder;
const folderPath = getFolderPathFromString(file.path);
if (folderPath === "") {
folder = this.plugin.app.vault.getAbstractFileByPath(text);
if (folder instanceof import_obsidian41.TFolder) {
new import_obsidian41.Notice("Folder note already exists");
return false;
}
this.plugin.app.vault.createFolder(text);
createFolderNote(this.plugin, text, false);
} else {
const folderFullPath = folderPath + "/" + text;
folder = this.plugin.app.vault.getAbstractFileByPath(folderFullPath);
if (folder instanceof import_obsidian41.TFolder) {
new import_obsidian41.Notice("Folder note already exists");
return false;
}
if (this.plugin.settings.storageLocation === "parentFolder") {
if (this.app.vault.getAbstractFileByPath(folderPath + "/" + text + this.plugin.settings.folderNoteType)) {
new import_obsidian41.Notice("File already exists");
return false;
}
}
this.plugin.app.vault.createFolder(folderPath + "/" + text);
createFolderNote(this.plugin, folderPath + "/" + text, false);
}
const { folderNoteName } = this.plugin.settings;
const fileName = folderNoteName.replace("{{folder_name}}", text);
if (fileName !== text) {
editor.replaceSelection(`[[${fileName}]]`);
} else {
editor.replaceSelection(`[[${fileName}|${text}]]`);
}
return true;
}
return false;
}
});
}
fileCommands() {
this.plugin.registerEvent(this.app.workspace.on("file-menu", (menu, file) => {
var _a, _b, _c;
let folder = file.parent;
if (file instanceof import_obsidian41.TFile) {
if (this.plugin.settings.storageLocation === "insideFolder") {
folder = file.parent;
} else {
const { folderNoteName } = this.plugin.settings;
const fileName = extractFolderName(folderNoteName, file.basename);
if (fileName) {
if (((_a = file.parent) == null ? void 0 : _a.path) === "" || ((_b = file.parent) == null ? void 0 : _b.path) === "/") {
folder = this.plugin.app.vault.getAbstractFileByPath(fileName);
} else {
folder = this.plugin.app.vault.getAbstractFileByPath(((_c = file.parent) == null ? void 0 : _c.path) + "/" + fileName);
}
}
}
if (folder instanceof import_obsidian41.TFolder) {
const folderNote = getFolderNote(this.plugin, folder.path);
const excludedFolder = getExcludedFolder(this.plugin, folder.path, true);
if ((folderNote == null ? void 0 : folderNote.path) === file.path && !(excludedFolder == null ? void 0 : excludedFolder.detached)) {
return;
}
} else if (file.parent instanceof import_obsidian41.TFolder) {
folder = file.parent;
}
}
const addFolderNoteActions = (folderMenu) => {
if (file instanceof import_obsidian41.TFile) {
folderMenu.addItem((item) => {
item.setTitle("Create folder note");
item.setIcon("edit");
item.onClick(async () => {
if (!folder)
return;
let newPath = folder.path + "/" + file.basename;
if (folder.path === "" || folder.path === "/") {
newPath = file.basename;
}
if (this.plugin.app.vault.getAbstractFileByPath(newPath)) {
return new import_obsidian41.Notice("Folder already exists");
}
const automaticallyCreateFolderNote = this.plugin.settings.autoCreate;
this.plugin.settings.autoCreate = false;
this.plugin.saveSettings();
await this.plugin.app.vault.createFolder(newPath);
const newFolder = this.plugin.app.vault.getAbstractFileByPath(newPath);
if (!(newFolder instanceof import_obsidian41.TFolder))
return;
await createFolderNote(this.plugin, newFolder.path, true, "." + file.extension, false, file);
this.plugin.settings.autoCreate = automaticallyCreateFolderNote;
this.plugin.saveSettings();
});
});
if (getFolderPathFromString(file.path) === "")
return;
if (!(folder instanceof import_obsidian41.TFolder))
return;
if (folder.path === "" || folder.path === "/")
return;
folderMenu.addItem((item) => {
item.setTitle(`Turn into folder note for ${folder == null ? void 0 : folder.name}`);
item.setIcon("edit");
item.onClick(() => {
if (!folder || !(folder instanceof import_obsidian41.TFolder))
return;
const folderNote2 = getFolderNote(this.plugin, folder.path);
turnIntoFolderNote(this.plugin, file, folder, folderNote2);
});
});
}
if (!(file instanceof import_obsidian41.TFolder))
return;
const excludedFolder = getExcludedFolder(this.plugin, file.path, false);
const detachedExcludedFolder = getDetachedFolder(this.plugin, file.path);
if (excludedFolder && !excludedFolder.hideInSettings) {
folderMenu.addItem((item) => {
item.setTitle("Remove folder from excluded folders");
item.setIcon("trash");
item.onClick(() => {
this.plugin.settings.excludeFolders = this.plugin.settings.excludeFolders.filter((excluded) => excluded.path !== file.path || excluded.detached);
this.plugin.saveSettings(true);
new import_obsidian41.Notice("Successfully removed folder from excluded folders");
});
});
return;
}
if (detachedExcludedFolder) {
folderMenu.addItem((item) => {
item.setTitle("Remove folder from detached folders");
item.setIcon("trash");
item.onClick(() => {
deleteExcludedFolder(this.plugin, detachedExcludedFolder);
});
});
}
if (detachedExcludedFolder) {
return;
}
folderMenu.addItem((item) => {
item.setTitle("Exclude folder from folder notes");
item.setIcon("x-circle");
item.onClick(() => {
const newExcludedFolder = new ExcludedFolder(file.path, this.plugin.settings.excludeFolders.length, void 0, this.plugin);
this.plugin.settings.excludeFolders.push(newExcludedFolder);
this.plugin.saveSettings(true);
new import_obsidian41.Notice("Successfully excluded folder from folder notes");
});
});
if (!(file instanceof import_obsidian41.TFolder))
return;
const folderNote = getFolderNote(this.plugin, file.path);
if (folderNote instanceof import_obsidian41.TFile && !detachedExcludedFolder) {
folderMenu.addItem((item) => {
item.setTitle("Delete folder note");
item.setIcon("trash");
item.onClick(() => {
deleteFolderNote(this.plugin, folderNote, true);
});
});
folderMenu.addItem((item) => {
item.setTitle("Open folder note");
item.setIcon("chevron-right-square");
item.onClick(() => {
openFolderNote(this.plugin, folderNote);
});
});
folderMenu.addItem((item) => {
item.setTitle("Detach folder note");
item.setIcon("unlink");
item.onClick(() => {
detachFolderNote(this.plugin, folderNote);
});
});
folderMenu.addItem((item) => {
item.setTitle("Copy Obsidian URL");
item.setIcon("link");
item.onClick(() => {
this.app.copyObsidianUrl(folderNote);
});
});
if (this.plugin.settings.hideFolderNote) {
if (excludedFolder == null ? void 0 : excludedFolder.showFolderNote) {
folderMenu.addItem((item) => {
item.setTitle("Hide folder note in explorer");
item.setIcon("eye-off");
item.onClick(() => {
hideFolderNoteInFileExplorer(file.path, this.plugin);
});
});
} else {
folderMenu.addItem((item) => {
item.setTitle("Show folder note in explorer");
item.setIcon("eye");
item.onClick(() => {
showFolderNoteInFileExplorer(file.path, this.plugin);
});
});
}
}
} else {
folderMenu.addItem((item) => {
item.setTitle("Create markdown folder note");
item.setIcon("edit");
item.onClick(() => {
createFolderNote(this.plugin, file.path, true, ".md");
});
});
this.plugin.settings.supportedFileTypes.forEach((fileType) => {
if (fileType === "md")
return;
folderMenu.addItem((item) => {
item.setTitle(`Create ${fileType} folder note`);
item.setIcon("edit");
item.onClick(() => {
createFolderNote(this.plugin, file.path, true, "." + fileType);
});
});
});
}
};
if (import_obsidian41.Platform.isDesktop && !import_obsidian41.Platform.isTablet && this.plugin.settings.useSubmenus) {
menu.addItem(async (item) => {
item.setTitle("Folder Note Commands").setIcon("folder-edit");
let subMenu = item.setSubmenu();
addFolderNoteActions(subMenu);
});
} else {
addFolderNoteActions(menu);
}
}));
}
editorCommands() {
this.plugin.registerEvent(this.plugin.app.workspace.on("editor-menu", (menu, editor, view) => {
const text = editor.getSelection().trim();
if (!text || text.trim() === "")
return;
menu.addItem((item) => {
item.setTitle("Create folder note").setIcon("edit").onClick(() => {
const { file } = view;
if (!(file instanceof import_obsidian41.TFile))
return;
const blacklist = ["*", "\\", '"', "/", "<", ">", "?", "|", ":"];
for (const char of blacklist) {
if (text.includes(char)) {
new import_obsidian41.Notice('File name cannot contain any of the following characters: * " \\ / < > : | ?');
return;
}
}
if (text.endsWith(".")) {
new import_obsidian41.Notice("File name cannot end with a dot");
return;
}
let folder;
const folderPath = getFolderPathFromString(file.path);
const { folderNoteName } = this.plugin.settings;
const fileName = folderNoteName.replace("{{folder_name}}", text);
if (folderPath === "") {
folder = this.plugin.app.vault.getAbstractFileByPath(text);
if (folder instanceof import_obsidian41.TFolder) {
return new import_obsidian41.Notice("Folder note already exists");
}
this.plugin.app.vault.createFolder(text);
createFolderNote(this.plugin, text, false);
} else {
folder = this.plugin.app.vault.getAbstractFileByPath(folderPath + "/" + text);
if (folder instanceof import_obsidian41.TFolder) {
return new import_obsidian41.Notice("Folder note already exists");
}
if (this.plugin.settings.storageLocation === "parentFolder") {
if (this.app.vault.getAbstractFileByPath(folderPath + "/" + fileName + this.plugin.settings.folderNoteType)) {
return new import_obsidian41.Notice("File already exists");
}
}
this.plugin.app.vault.createFolder(folderPath + "/" + text);
createFolderNote(this.plugin, folderPath + "/" + text, false);
}
if (fileName !== text) {
editor.replaceSelection(`[[${fileName}]]`);
} else {
editor.replaceSelection(`[[${fileName}|${text}]]`);
}
});
});
}));
}
};
// src/events/MutationObserver.ts
var import_obsidian43 = require("obsidian");
// src/events/handleClick.ts
var import_obsidian42 = require("obsidian");
async function handleViewHeaderClick(event, plugin) {
if (!plugin.settings.openFolderNoteOnClickInPath)
return;
event.stopImmediatePropagation();
event.preventDefault();
event.stopPropagation();
if (!(event.target instanceof HTMLElement))
return;
const folderPath = event.target.getAttribute("data-path");
if (!folderPath) {
return;
}
if (await isExcludedFolder(event, plugin, folderPath))
return;
const folderNote = getFolderNote(plugin, folderPath);
if (folderNote) {
await openFolderNote(plugin, folderNote, event).then(() => handleFolderNoteReveal(plugin, folderNote));
return;
} else if (event.altKey || import_obsidian42.Keymap.isModEvent(event) === "tab") {
if (await handleFolderNoteCreation(event, plugin, folderPath))
return;
}
event.target.onclick = null;
event.target.click();
}
async function isExcludedFolder(event, plugin, folderPath) {
const excludedFolder = getExcludedFolder(plugin, folderPath, true);
if (excludedFolder == null ? void 0 : excludedFolder.disableFolderNote) {
event.target.onclick = null;
event.target.click();
return true;
} else if ((excludedFolder == null ? void 0 : excludedFolder.enableCollapsing) || plugin.settings.enableCollapsing) {
event.target.onclick = null;
event.target.click();
}
return false;
}
async function handleFolderNoteReveal(plugin, folderNote) {
const fileExplorerPlugin = plugin.app.internalPlugins.getEnabledPluginById("file-explorer");
if (fileExplorerPlugin && import_obsidian42.Platform.isMobile && plugin.settings.openSidebar.mobile) {
const OPEN_SIDEBAR_DELAY = 200;
setTimeout(() => {
fileExplorerPlugin.revealInFolder(folderNote);
}, OPEN_SIDEBAR_DELAY);
} else if (fileExplorerPlugin && import_obsidian42.Platform.isDesktop && plugin.settings.openSidebar.desktop) {
fileExplorerPlugin.revealInFolder(folderNote);
}
}
async function handleFolderNoteCreation(event, plugin, folderPath) {
const usedCtrl = import_obsidian42.Platform.isMacOS ? event.metaKey : event.ctrlKey;
if (plugin.settings.altKey && event.altKey || usedCtrl && import_obsidian42.Keymap.isModEvent(event) === "tab") {
await createFolderNote(plugin, folderPath, true, void 0, true);
addCSSClassToFileExplorerEl(folderPath, "has-folder-note", false, plugin);
removeCSSClassFromFileExplorerEL(folderPath, "has-not-folder-note", false, plugin);
return true;
}
return false;
}
// src/events/MutationObserver.ts
var fileExplorerMutationObserver = null;
function registerFileExplorerObserver(plugin) {
plugin.app.workspace.onLayoutReady(() => {
initializeFolderNoteFeatures(plugin);
initializeBreadcrumbs(plugin);
});
plugin.registerEvent(plugin.app.workspace.on("layout-change", () => {
var _a;
initializeFolderNoteFeatures(plugin);
const activeLeaf = (_a = plugin.app.workspace.getActiveFileView()) == null ? void 0 : _a.containerEl;
if (!activeLeaf)
return;
const titleContainer = activeLeaf.querySelector(".view-header-title-container");
if (!(titleContainer instanceof HTMLElement))
return;
updateFolderNamesInPath(plugin, titleContainer);
}));
}
function unregisterFileExplorerObserver() {
if (fileExplorerMutationObserver) {
fileExplorerMutationObserver.disconnect();
fileExplorerMutationObserver = null;
}
}
function initializeFolderNoteFeatures(plugin) {
initializeAllFolderTitles(plugin);
observeFolderTitleMutations(plugin);
}
function initializeBreadcrumbs(plugin) {
const titleContainers = document.querySelectorAll(".view-header-title-container");
if (!titleContainers.length)
return;
titleContainers.forEach((container) => {
if (!(container instanceof HTMLElement))
return;
scheduleIdle(() => updateFolderNamesInPath(plugin, container), { timeout: 1e3 });
});
}
function observeFolderTitleMutations(plugin) {
if (fileExplorerMutationObserver) {
fileExplorerMutationObserver.disconnect();
}
fileExplorerMutationObserver = new MutationObserver((mutations) => {
for (const mutation of mutations) {
for (const node of Array.from(mutation.addedNodes)) {
if (!(node instanceof HTMLElement))
continue;
processAddedFolders(node, plugin);
}
}
});
fileExplorerMutationObserver.observe(document, { childList: true, subtree: true });
}
function initializeAllFolderTitles(plugin) {
const allTitles = document.querySelectorAll(".nav-folder-title-content");
for (const title of Array.from(allTitles)) {
const folderTitle = title;
const folderEl = folderTitle.closest(".nav-folder-title");
if (!folderEl)
continue;
const folderPath = folderEl.getAttribute("data-path") || "";
setupFolderTitle(folderTitle, plugin, folderPath);
}
}
function processAddedFolders(node, plugin) {
const titles = [];
if (node.matches(".nav-folder-title-content")) {
titles.push(node);
}
node.querySelectorAll(".nav-folder-title-content").forEach((el) => {
titles.push(el);
});
titles.forEach((folderTitle) => {
const folderEl = folderTitle.closest(".nav-folder-title");
const folderPath = (folderEl == null ? void 0 : folderEl.getAttribute("data-path")) || "";
const RETRY_TIMEOUT = 50;
if (!folderEl || !folderPath) {
setTimeout(() => {
const retryFolderEl = folderTitle.closest(".nav-folder-title");
const retryFolderPath = (retryFolderEl == null ? void 0 : retryFolderEl.getAttribute("data-path")) || "";
if (retryFolderEl && retryFolderPath) {
setupFolderTitle(folderTitle, plugin, retryFolderPath);
}
}, RETRY_TIMEOUT);
return;
}
setupFolderTitle(folderTitle, plugin, folderPath);
});
}
async function setupFolderTitle(folderTitle, plugin, folderPath) {
var _a;
if (folderTitle.dataset.initialized === "true")
return;
if (!folderPath)
return;
folderTitle.dataset.initialized = "true";
await updateCSSClassesForFolder(folderPath, plugin);
if (plugin.settings.frontMatterTitle.enabled) {
(_a = plugin.fmtpHandler) == null ? void 0 : _a.fmptUpdateFolderName({ id: "", result: false, path: folderPath, pathOnly: false }, false);
}
if (import_obsidian43.Platform.isMobile && plugin.settings.disableOpenFolderNoteOnClick)
return;
plugin.registerDomEvent(folderTitle, "pointerover", (event) => {
plugin.hoveredElement = folderTitle;
plugin.mouseEvent = event;
if (!import_obsidian43.Keymap.isModEvent(event))
return;
if (!(event.target instanceof HTMLElement))
return;
const folderNote = getFolderNote(plugin, folderPath);
if (!folderNote)
return;
plugin.app.workspace.trigger("hover-link", {
event,
source: "preview",
hoverParent: { file: folderNote },
targetEl: event.target,
linktext: folderNote.basename,
sourcePath: folderNote.path
});
plugin.hoverLinkTriggered = true;
});
plugin.registerDomEvent(folderTitle, "pointerout", () => {
plugin.hoveredElement = null;
plugin.mouseEvent = null;
plugin.hoverLinkTriggered = false;
});
}
async function updateFolderNamesInPath(plugin, titleContainer) {
const headers = titleContainer.querySelectorAll("span.view-header-breadcrumb");
let path = "";
const TRAILING_SLASH_LENGTH = 1;
headers.forEach(async (breadcrumb) => {
var _a, _b;
path += (_a = breadcrumb.getAttribute("old-name")) != null ? _a : breadcrumb.innerText.trim();
path += "/";
const folderPath = path.slice(0, -TRAILING_SLASH_LENGTH);
const excludedFolder = getExcludedFolder(plugin, folderPath, true);
if (excludedFolder == null ? void 0 : excludedFolder.disableFolderNote)
return;
const folderNote = getFolderNote(plugin, folderPath);
if (!folderNote)
return;
if (folderNote)
breadcrumb.classList.add("has-folder-note");
breadcrumb == null ? void 0 : breadcrumb.setAttribute("data-path", path.slice(0, -TRAILING_SLASH_LENGTH));
if (!breadcrumb.onclick) {
breadcrumb.addEventListener("click", (e) => {
handleViewHeaderClick(e, plugin);
}, { capture: true });
}
if (plugin.settings.frontMatterTitle.enabled) {
(_b = plugin.fmtpHandler) == null ? void 0 : _b.fmptUpdateFolderName({ id: "", result: false, path: folderPath, pathOnly: true, breadcrumb }, true);
}
});
}
function scheduleIdle(callback, options) {
const DEFAULT_IDLE_TIMEOUT = 200;
if ("requestIdleCallback" in window) {
const windowWithIdle = window;
windowWithIdle.requestIdleCallback(callback, options);
} else {
setTimeout(callback, (options == null ? void 0 : options.timeout) || DEFAULT_IDLE_TIMEOUT);
}
}
// src/events/handleRename.ts
var import_obsidian44 = require("obsidian");
function handleRename(file, oldPath, plugin) {
let folder = file.parent;
const oldFolder = plugin.app.vault.getAbstractFileByPath(getFolderPathFromString(oldPath));
if (folder instanceof import_obsidian44.TFolder) {
if (plugin.isEmptyFolderNoteFolder(folder) && getFolderNote(plugin, folder.path)) {
addCSSClassToFileExplorerEl(folder.path, "only-has-folder-note", true, plugin);
} else {
removeCSSClassFromFileExplorerEL(folder.path, "only-has-folder-note", true, plugin);
}
}
if (oldFolder instanceof import_obsidian44.TFolder) {
if (plugin.isEmptyFolderNoteFolder(oldFolder) && getFolderNote(plugin, oldFolder.path)) {
addCSSClassToFileExplorerEl(oldFolder.path, "only-has-folder-note", true, plugin);
} else {
removeCSSClassFromFileExplorerEL(oldFolder.path, "only-has-folder-note", true, plugin);
}
}
if (file instanceof import_obsidian44.TFolder) {
folder = file;
plugin.tabManager.updateTab(folder.path);
updateExcludedFolderPath(folder, oldPath, plugin);
if (isFolderRename(folder, oldPath)) {
handleFolderRename(folder, oldPath, plugin);
return;
}
return handleFolderMove(folder, oldPath, plugin);
} else if (file instanceof import_obsidian44.TFile) {
if (isFileRename(file, oldPath)) {
handleFileRename(file, oldPath, plugin);
return;
}
handleFileMove(file, oldPath, plugin);
return;
}
}
function isFileRename(file, oldPath) {
var _a;
const oldFolderPath = getFolderPathFromString(oldPath);
const newFolderPath = (_a = file.parent) == null ? void 0 : _a.path;
const oldName = getFileNameFromPathString(oldPath);
const newName = file.name;
return oldFolderPath === newFolderPath && oldName !== newName;
}
function isFolderRename(folder, oldPath) {
var _a;
const oldName = getFileNameFromPathString(oldPath);
const newName = folder.name;
const oldParent = getFolderPathFromString(oldPath);
const newParent = (_a = folder.parent) == null ? void 0 : _a.path;
return oldParent === newParent && oldName !== newName;
}
function handleFolderMove(file, oldPath, plugin) {
var _a;
if (plugin.settings.storageLocation === "insideFolder") {
return;
}
if (!plugin.settings.syncMove) {
return;
}
const folderNote = getFolderNote(plugin, oldPath, plugin.settings.storageLocation);
if (!(file instanceof import_obsidian44.TFolder) || !folderNote)
return;
const newFolder = plugin.app.vault.getAbstractFileByPath(file.path);
if (!(newFolder instanceof import_obsidian44.TFolder))
return;
let newPath = folderNote.path;
if (newFolder.path === "/") {
newPath = folderNote.name;
} else {
newPath = `${(_a = newFolder.parent) == null ? void 0 : _a.path}/${folderNote.name}`;
}
plugin.app.fileManager.renameFile(folderNote, newPath);
}
async function handleFileMove(file, oldPath, plugin) {
var _a;
const { folderName, oldFileName, newFolder, excludedFolder, oldFolder, folderNote } = getArgs2(plugin, file, oldPath);
const isFolderNoteInNewFolder = folderName === (newFolder == null ? void 0 : newFolder.name);
const fileMovedFromOldFolderNote = oldFolder && oldFolder.name === oldFileName && (newFolder == null ? void 0 : newFolder.path) !== oldFolder.path;
const isFileWithExistingNote = folderName === (newFolder == null ? void 0 : newFolder.name) && folderNote;
if (isFileWithExistingNote) {
renameExistingFolderNote(file, oldPath, plugin, excludedFolder, oldFolder);
} else if (isFolderNoteInNewFolder) {
if (excludedFolder == null ? void 0 : excludedFolder.disableFolderNote) {
return;
}
markFileAsFolderNote(file, plugin);
if (newFolder instanceof import_obsidian44.TFolder) {
markFolderWithFolderNoteClasses(newFolder, plugin);
if (((_a = plugin.app.workspace.getActiveFile()) == null ? void 0 : _a.path) === file.path) {
removeActiveFolder(plugin);
setActiveFolder(newFolder.path, plugin);
}
}
if (oldFolder instanceof import_obsidian44.TFolder) {
hideFolderNoteInFileExplorer(oldFolder.path, plugin);
unmarkFolderAsFolderNote(oldFolder, plugin);
}
} else if (fileMovedFromOldFolderNote) {
unmarkFileAsFolderNote(file, plugin);
if (oldFolder instanceof import_obsidian44.TFolder) {
removeActiveFolder(plugin);
hideFolderNoteInFileExplorer(oldFolder.path, plugin);
unmarkFolderAsFolderNote(oldFolder, plugin);
}
}
}
function getArgs2(plugin, file, oldPath) {
const folderName = extractFolderName(plugin.settings.folderNoteName, file.basename) || file.basename;
const oldFileName = removeExtension(getFileNameFromPathString(oldPath));
const newFolder = getFolderNoteFolder(plugin, file, file.basename);
let excludedFolder = getExcludedFolder(plugin, (newFolder == null ? void 0 : newFolder.path) || "", true);
const oldFolder = getFolderNoteFolder(plugin, oldPath, oldFileName);
const folderNote = getFolderNote(plugin, oldPath, plugin.settings.storageLocation, file);
return {
folderName,
oldFileName,
newFolder,
excludedFolder,
oldFolder,
folderNote
};
}
function renameExistingFolderNote(file, oldPath, plugin, excludedFolder, oldFolder) {
let excludedFolderExisted = true;
let disabledSync = false;
if (!excludedFolder) {
excludedFolderExisted = false;
excludedFolder = new ExcludedFolder((oldFolder == null ? void 0 : oldFolder.path) || "", plugin.settings.excludeFolders.length, void 0, plugin);
addExcludedFolder(plugin, excludedFolder);
} else if (!excludedFolder.disableSync) {
disabledSync = false;
excludedFolder.disableSync = true;
updateExcludedFolder(plugin, excludedFolder, excludedFolder);
}
plugin.app.fileManager.renameFile(file, oldPath).then(() => {
if (!excludedFolder) {
return;
}
if (!excludedFolderExisted) {
deleteExcludedFolder(plugin, excludedFolder);
} else if (!disabledSync) {
excludedFolder.disableSync = false;
updateExcludedFolder(plugin, excludedFolder, excludedFolder);
}
});
}
async function handleFolderRename(file, oldPath, plugin) {
const fileName = plugin.settings.folderNoteName.replace("{{folder_name}}", file.name);
const oldFileName = plugin.settings.folderNoteName.replace("{{folder_name}}", getFileNameFromPathString(oldPath));
if (fileName === oldFileName) {
return;
}
const folderNote = getFolderNote(plugin, oldPath);
if (!(folderNote instanceof import_obsidian44.TFile))
return;
const excludedFolder = getExcludedFolder(plugin, file.path, true);
if ((excludedFolder == null ? void 0 : excludedFolder.disableSync) && !folderNote) {
return removeCSSClassFromFileExplorerEL(file.path, "has-folder-note", false, plugin);
}
if (!plugin.settings.syncFolderName) {
return;
}
let newPath = "";
if (plugin.settings.storageLocation === "parentFolder") {
const parentFolderPath = getFolderPathFromString(file.path);
const oldParentFolderPath = getFolderPathFromString(oldPath);
if (parentFolderPath !== oldParentFolderPath) {
if (!plugin.settings.syncMove) {
return;
}
newPath = `${parentFolderPath}/${fileName}.${folderNote.extension}`;
} else if (parentFolderPath.trim() === "") {
folderNote.path = `${folderNote.name}`;
newPath = `${fileName}.${folderNote.extension}`;
} else {
folderNote.path = `${parentFolderPath}/${folderNote.name}`;
newPath = `${parentFolderPath}/${fileName}.${folderNote.extension}`;
}
} else {
folderNote.path = `${file.path}/${folderNote.name}`;
newPath = `${file.path}/${fileName}.${folderNote.extension}`;
}
plugin.app.fileManager.renameFile(folderNote, newPath);
}
async function handleFileRename(file, oldPath, plugin) {
const oldFileName = removeExtension(getFileNameFromPathString(oldPath));
const newFileName = file.basename;
if (oldFileName === newFileName) {
return;
}
const oldFolder = getFolderNoteFolder(plugin, oldPath, oldFileName);
const folderName = extractFolderName(plugin.settings.folderNoteName, file.basename) || file.basename;
const oldFolderName = extractFolderName(plugin.settings.folderNoteName, oldFileName) || oldFileName;
const newFolder = getFolderNoteFolder(plugin, file, file.basename);
const excludedFolder = getExcludedFolder(plugin, (newFolder == null ? void 0 : newFolder.path) || "", true);
const detachedExcludedFolder = getDetachedFolder(plugin, (newFolder == null ? void 0 : newFolder.path) || "");
const folderNote = getFolderNote(plugin, oldPath, plugin.settings.storageLocation, file);
if (shouldCreateFolderNote(excludedFolder, folderName, newFolder, detachedExcludedFolder)) {
if (newFolder) {
handleFolderNoteCreation2(file, newFolder, plugin);
}
return;
}
if (shouldRemoveFolderNoteClasses(excludedFolder, folderName, newFolder)) {
handleFolderNoteRemoval(file, newFolder, plugin);
}
if ((excludedFolder == null ? void 0 : excludedFolder.disableSync) || !plugin.settings.syncFolderName) {
return;
}
if (folderName === (newFolder == null ? void 0 : newFolder.name) && newFolder) {
handleSameFolderRename(file, newFolder, oldFolder, plugin);
return;
}
if (shouldRenameFolderOnFileRename(oldFolderName, oldFolder, newFolder, folderNote)) {
return renameFolderOnFileRename(file, oldPath, oldFolder, plugin);
}
}
async function renameFolderOnFileRename(file, oldPath, oldFolder, plugin) {
var _a, _b;
const newFolderName = extractFolderName(plugin.settings.folderNoteName, file.basename);
if (!newFolderName) {
removeCSSClassFromFileExplorerEL(oldFolder.path, "has-folder-note", false, plugin);
removeCSSClassFromFileExplorerEL(file.path, "is-folder-note", false, plugin);
return;
} else if (newFolderName === oldFolder.name) {
addCSSClassToFileExplorerEl(oldFolder.path, "has-folder-note", false, plugin);
addCSSClassToFileExplorerEl(file.path, "is-folder-note", false, plugin);
return;
}
let newFolderPath = "";
if (plugin.settings.storageLocation === "insideFolder") {
if (((_a = oldFolder.parent) == null ? void 0 : _a.path) === "/") {
newFolderPath = `${newFolderName}`;
} else {
newFolderPath = ((_b = oldFolder.parent) == null ? void 0 : _b.path) + "/" + newFolderName;
}
} else {
const parentFolderPath = getFolderPathFromString(file.path);
if (parentFolderPath.trim() === "" || parentFolderPath.trim() === "/") {
newFolderPath = `${newFolderName}`;
} else {
newFolderPath = `${parentFolderPath}/${newFolderName}`;
}
}
if (plugin.app.vault.getAbstractFileByPath(newFolderPath)) {
await plugin.app.fileManager.renameFile(file, oldPath);
new import_obsidian44.Notice("A folder with the same name already exists");
return;
}
plugin.app.fileManager.renameFile(oldFolder, newFolderPath);
}
function updateExcludedFolderPath(folder, oldPath, plugin) {
const excludedFolders = plugin.settings.excludeFolders.filter((excludedFolder) => {
var _a;
return (_a = excludedFolder.path) == null ? void 0 : _a.includes(oldPath);
});
excludedFolders.forEach((excludedFolder) => {
if (excludedFolder.path === oldPath) {
excludedFolder.path = folder.path;
return;
}
if (!excludedFolder.path)
return;
const folders = excludedFolder.path.split("/");
if (folders.length < 1) {
folders.push(excludedFolder.path);
}
folders[folders.indexOf(folder.name)] = folder.name;
excludedFolder.path = folders.join("/");
});
plugin.saveSettings();
}
function shouldCreateFolderNote(excludedFolder, folderName, newFolder, detachedExcludedFolder) {
return !(excludedFolder == null ? void 0 : excludedFolder.disableFolderNote) && folderName === (newFolder == null ? void 0 : newFolder.name) && !detachedExcludedFolder;
}
function shouldRemoveFolderNoteClasses(excludedFolder, folderName, newFolder) {
return (excludedFolder == null ? void 0 : excludedFolder.disableFolderNote) || folderName !== (newFolder == null ? void 0 : newFolder.name);
}
function handleFolderNoteCreation2(file, newFolder, plugin) {
addCSSClassToFileExplorerEl(file.path, "is-folder-note", false, plugin);
addCSSClassToFileExplorerEl(newFolder.path, "has-folder-note", false, plugin);
}
function handleFolderNoteRemoval(file, newFolder, plugin) {
removeCSSClassFromFileExplorerEL(file.path, "is-folder-note", false, plugin);
removeCSSClassFromFileExplorerEL((newFolder == null ? void 0 : newFolder.path) || "", "has-folder-note", false, plugin);
}
function handleSameFolderRename(file, newFolder, oldFolder, plugin) {
addCSSClassToFileExplorerEl(file.path, "is-folder-note", false, plugin);
removeCSSClassFromFileExplorerEL(oldFolder == null ? void 0 : oldFolder.path, "has-folder-note", false, plugin);
addCSSClassToFileExplorerEl(newFolder.path, "has-folder-note", false, plugin);
}
function shouldRenameFolderOnFileRename(oldFolderName, oldFolder, newFolder, folderNote) {
if (!oldFolder)
return false;
const oldFolderAsFolder = oldFolder;
const newFolderAsFolder = newFolder;
return oldFolderName === oldFolderAsFolder.name && (newFolderAsFolder == null ? void 0 : newFolderAsFolder.path) === oldFolderAsFolder.path || folderNote !== null && oldFolderName === oldFolderAsFolder.name;
}
// src/events/handleCreate.ts
var import_obsidian45 = require("obsidian");
async function handleCreate(file, plugin) {
if (!plugin.app.workspace.layoutReady)
return;
const folder = file.parent;
if (folder instanceof import_obsidian45.TFolder) {
if (plugin.isEmptyFolderNoteFolder(folder) && getFolderNote(plugin, folder.path)) {
addCSSClassToFileExplorerEl(folder.path, "only-has-folder-note", true, plugin);
} else {
removeCSSClassFromFileExplorerEL(folder.path, "only-has-folder-note", true, plugin);
}
}
if (file instanceof import_obsidian45.TFile) {
handleFileCreation(file, plugin);
} else if (file instanceof import_obsidian45.TFolder && plugin.settings.autoCreate) {
handleFolderCreation(file, plugin);
}
}
async function handleFileCreation(file, plugin) {
const folder = getFolder(plugin, file);
if (!(folder instanceof import_obsidian45.TFolder) && plugin.settings.autoCreateForFiles) {
if (!file.parent) {
return;
}
const newFolder = await plugin.app.fileManager.createNewFolder(file.parent);
turnIntoFolderNote(plugin, file, newFolder);
} else if (folder instanceof import_obsidian45.TFolder) {
if (folder.children.length >= 1) {
removeCSSClassFromFileExplorerEL(folder.path, "fn-empty-folder", false, plugin);
}
const detachedFolder = getExcludedFolder(plugin, folder.path, true);
if (detachedFolder) {
return;
}
const folderNote = getFolderNote(plugin, folder.path);
if (folderNote && folderNote.path === file.path) {
addCSSClassToFileExplorerEl(folder.path, "has-folder-note", false, plugin);
addCSSClassToFileExplorerEl(file.path, "is-folder-note", false, plugin);
} else if (plugin.settings.autoCreateForFiles) {
if (!file.parent) {
return;
}
const newFolder = await plugin.app.fileManager.createNewFolder(file.parent);
turnIntoFolderNote(plugin, file, newFolder);
}
}
}
async function handleFolderCreation(folder, plugin) {
let openFile = plugin.settings.autoCreateFocusFiles;
const attachmentFolderPath = plugin.app.vault.getConfig("attachmentFolderPath");
const cleanAttachmentFolderPath = (attachmentFolderPath == null ? void 0 : attachmentFolderPath.replace("./", "")) || "";
const attachmentsAreInRootFolder = attachmentFolderPath === "./" || attachmentFolderPath === "";
addCSSClassToFileExplorerEl(folder.path, "fn-empty-folder", false, plugin);
if (!plugin.settings.autoCreateForAttachmentFolder) {
if (!attachmentsAreInRootFolder && cleanAttachmentFolderPath === folder.name)
return;
} else if (!attachmentsAreInRootFolder && cleanAttachmentFolderPath === folder.name) {
openFile = false;
}
const excludedFolder = getExcludedFolder(plugin, folder.path, true);
if (excludedFolder == null ? void 0 : excludedFolder.disableAutoCreate)
return;
const folderNote = getFolderNote(plugin, folder.path);
if (folderNote)
return;
createFolderNote(plugin, folder.path, openFile, void 0, true);
addCSSClassToFileExplorerEl(folder.path, "has-folder-note", false, plugin);
}
// src/events/TabManager.ts
var import_obsidian46 = require("obsidian");
var TabManager = class {
constructor(plugin) {
this.plugin = plugin;
this.app = plugin.app;
}
resetTabs() {
if (!this.isEnabled())
return;
this.app.workspace.iterateAllLeaves((leaf) => {
var _a;
if (!(leaf.view instanceof import_obsidian46.EditableFileView))
return;
const file = (_a = leaf.view) == null ? void 0 : _a.file;
if (!file)
return;
leaf.tabHeaderInnerTitleEl.setText(file.basename);
});
}
updateTabs() {
if (!this.isEnabled())
return;
this.app.workspace.iterateAllLeaves((leaf) => {
var _a;
if (!(leaf.view instanceof import_obsidian46.EditableFileView))
return;
const file = (_a = leaf.view) == null ? void 0 : _a.file;
if (!file)
return;
const folder = getFolder(this.plugin, file);
if (!folder)
return;
leaf.tabHeaderInnerTitleEl.setText(folder.name);
});
}
updateTab(folderPath) {
if (!this.isEnabled())
return;
const folder = this.app.vault.getAbstractFileByPath(folderPath);
if (!(folder instanceof import_obsidian46.TFolder))
return;
const folderNote = getFolderNote(this.plugin, folder.path);
if (!folderNote)
return;
this.app.workspace.iterateAllLeaves((leaf) => {
var _a;
if (!(leaf.view instanceof import_obsidian46.EditableFileView))
return;
const file = (_a = leaf.view) == null ? void 0 : _a.file;
if (!file)
return;
if (file.path === folderNote.path) {
leaf.tabHeaderInnerTitleEl.setText(folder.name);
}
});
}
isEnabled() {
if (this.plugin.settings.folderNoteName === "{{folder_name}}")
return false;
return this.plugin.settings.tabManagerEnabled;
}
};
// src/events/handleDelete.ts
var import_obsidian47 = require("obsidian");
function handleDelete(file, plugin) {
const folder = plugin.app.vault.getAbstractFileByPath(getFolderPathFromString(file.path));
if (folder instanceof import_obsidian47.TFolder) {
if (plugin.isEmptyFolderNoteFolder(folder) && getFolderNote(plugin, folder.path)) {
addCSSClassToFileExplorerEl(folder.path, "only-has-folder-note", true, plugin);
} else {
removeCSSClassFromFileExplorerEL(folder.path, "only-has-folder-note", true, plugin);
}
}
if (file instanceof import_obsidian47.TFile) {
const folderNoteFolder = getFolder(plugin, file);
if (!folderNoteFolder) {
return;
}
const folderNote2 = getFolderNote(plugin, folderNoteFolder.path);
if (folderNote2) {
return;
}
removeCSSClassFromFileExplorerEL(folderNoteFolder.path, "has-folder-note", false, plugin);
removeCSSClassFromFileExplorerEL(folderNoteFolder.path, "only-has-folder-note", true, plugin);
hideFolderNoteInFileExplorer(folderNoteFolder.path, plugin);
}
if (!(file instanceof import_obsidian47.TFolder)) {
return;
}
const folderNote = getFolderNote(plugin, file.path);
if (!folderNote) {
return;
}
removeCSSClassFromFileExplorerEL(folderNote.path, "is-folder-note", false, plugin);
if (!plugin.settings.syncDelete) {
return;
}
deleteFolderNote(plugin, folderNote, false);
}
// src/obsidian-folder-overview/src/view.ts
var import_obsidian51 = require("obsidian");
// src/obsidian-folder-overview/src/main.ts
var import_obsidian50 = require("obsidian");
// src/obsidian-folder-overview/src/Commands.ts
var import_obsidian48 = require("obsidian");
function registerOverviewCommands(plugin) {
plugin.addCommand({
id: "open-folder-overview-settings",
name: "Edit folder overview",
callback: () => {
plugin.activateOverviewView();
}
});
plugin.addCommand({
id: "insert-folder-overview",
name: "Insert folder overview",
editorCheckCallback: (checking, editor) => {
const line = editor.getCursor().line;
const lineText = editor.getLine(line);
if (lineText.trim() === "" || lineText.trim() === ">") {
if (!checking) {
insertOverview(editor, plugin);
}
return true;
}
return false;
}
});
plugin.registerEvent(plugin.app.workspace.on("editor-menu", (menu, editor, _view) => {
const { line } = editor.getCursor();
const lineText = editor.getLine(line);
if (lineText.trim() === "" || lineText.trim() === ">") {
menu.addItem((item) => {
item.setTitle("Insert folder overview").setIcon("edit").onClick(() => {
if (plugin.settings.firstTimeInsertOverview) {
plugin.settings.firstTimeInsertOverview = false;
plugin.saveSettings();
const frag = document.createDocumentFragment();
const text = document.createTextNode('You can edit the overview using the "Edit folder overview" command from the command palette. To find more about folder overview, check the plugin documentation: ');
const link = document.createElement("a");
link.href = "https://lostpaul.github.io/obsidian-folder-notes/Folder%20overview/";
link.textContent = "https://lostpaul.github.io/obsidian-folder-notes/Folder%20overview/";
frag.appendChild(text);
frag.appendChild(link);
new import_obsidian48.Notice(frag);
}
insertOverview(editor, plugin);
});
});
}
}));
}
function insertOverview(editor, plugin) {
const { line: cursorLine } = editor.getCursor();
const currentLineText = editor.getLine(cursorLine);
const json = getDefaultOverviewJson(plugin);
json.id = crypto.randomUUID();
const yaml = (0, import_obsidian48.stringifyYaml)(json);
let overviewBlock = getOverviewBlock(yaml);
if (shouldUseActualLinks(plugin)) {
overviewBlock = addLinkSpans(overviewBlock, json.id);
}
if (currentLineText.trim() === "") {
editor.replaceSelection(overviewBlock);
} else if (currentLineText.trim() === ">") {
const yamlLines = yaml.split("\n");
const quotedLines = yamlLines.map((yamlLine) => `> ${yamlLine}`);
let quotedBlock = `\`\`\`folder-overview
${quotedLines.join("\n")}\`\`\`
`;
if (shouldUseActualLinks(plugin)) {
quotedBlock = addLinkSpans(quotedBlock, json.id);
}
editor.replaceSelection(quotedBlock);
}
if (plugin.fvIndexDB.active) {
const activeFile = plugin.app.workspace.getActiveFile();
if (activeFile) {
plugin.fvIndexDB.addNote(activeFile);
}
}
}
function getDefaultOverviewJson(plugin) {
const isOverviewPlugin = plugin instanceof FolderOverviewPlugin;
const defaultSettings = isOverviewPlugin ? plugin.settings.defaultOverviewSettings : plugin.settings.defaultOverview;
return Object.assign({}, defaultSettings);
}
function shouldUseActualLinks(plugin) {
if (plugin instanceof FolderOverviewPlugin) {
return plugin.settings.defaultOverviewSettings.useActualLinks;
}
return plugin.settings.defaultOverview.useActualLinks;
}
function getOverviewBlock(yaml) {
return `\`\`\`folder-overview
${yaml}\`\`\`
`;
}
function addLinkSpans(block, id) {
return `${block}<span class="fv-link-list-start" id="${id}"></span>
<span class="fv-link-list-end" id="${id}"></span>
`;
}
// src/obsidian-folder-overview/src/utils/FmtpHandler.ts
var import_front_matter_plugin_api_provider2 = __toESM(require_lib());
var FrontMatterTitlePluginHandler2 = class {
constructor(plugin) {
this.api = null;
this.deffer = null;
this.modifiedFolders = /* @__PURE__ */ new Map();
this.plugin = plugin;
this.app = plugin.app;
(async () => {
var _a;
this.deffer = (0, import_front_matter_plugin_api_provider2.getDefer)(this.app);
if (this.deffer.isPluginReady()) {
this.api = this.deffer.getApi();
} else {
await this.deffer.awaitPlugin();
this.api = this.deffer.getApi();
if (!this.deffer.isFeaturesReady()) {
await this.deffer.awaitFeatures();
}
}
const dispatcher = (_a = this.api) == null ? void 0 : _a.getEventDispatcher();
if (dispatcher) {
this.dispatcher = dispatcher;
}
})();
}
deleteEvent() {
if (this.eventRef) {
this.dispatcher.removeListener(this.eventRef);
}
}
async getNewFileName(file) {
var _a, _b, _c;
const resolver = (_b = (_a = this.api) == null ? void 0 : _a.getResolverFactory()) == null ? void 0 : _b.createResolver("#feature-id#");
const changedName = resolver == null ? void 0 : resolver.resolve((_c = file == null ? void 0 : file.path) != null ? _c : "");
return changedName != null ? changedName : null;
}
};
// src/obsidian-folder-overview/src/utils/IndexDB.ts
var import_obsidian49 = require("obsidian");
var FvIndexDB = class {
constructor(plugin) {
this.name = "fn-folder-overview";
this.version = 1;
this.storeName = "files";
this.keyPath = "sourcePath";
this.active = false;
this.indexDB = null;
this.plugin = plugin;
}
init(showNotice) {
this.active = true;
const openRequest = indexedDB.open(this.name, this.version);
openRequest.onupgradeneeded = (event) => {
const target = event.target;
if (!target)
return;
const db = target.result;
if (!db.objectStoreNames.contains(this.storeName)) {
db.createObjectStore(this.storeName, { keyPath: this.keyPath });
}
this.indexDB = db;
this.indexFiles(showNotice);
};
openRequest.onsuccess = (event) => {
const target = event.target;
if (!target)
return;
this.indexDB = target.result;
openRequest.onblocked = (blockedEvent) => {
console.warn("IndexedDB is blocked:", blockedEvent);
};
this.indexDB.onclose = () => {
this.indexDB = null;
};
this.resetDatabase();
this.indexFiles(showNotice);
};
openRequest.onerror = (event) => {
const target = event.target;
const error = target == null ? void 0 : target.error;
if (error && error.name === "VersionError") {
const deleteRequest = indexedDB.deleteDatabase(this.name);
deleteRequest.onsuccess = () => {
this.init(showNotice);
};
}
};
}
async indexFiles(showNotice) {
if (showNotice)
new import_obsidian49.Notice("Indexing files for folder overview plugin...");
const files = this.plugin.app.vault.getMarkdownFiles();
for (const file of files) {
if (!await hasOverviewYaml(this.plugin, file))
continue;
this.addNote(file);
}
if (showNotice)
new import_obsidian49.Notice("Indexed files for folder overview plugin.");
}
addNote(note) {
if (!this.active || !this.indexDB)
return;
const transaction = this.indexDB.transaction([this.storeName], "readwrite");
const store = transaction.objectStore(this.storeName);
store.put({ sourcePath: note.path });
}
removeNote(notePath) {
if (!this.active || !this.indexDB)
return;
const transaction = this.indexDB.transaction([this.storeName], "readwrite");
const store = transaction.objectStore(this.storeName);
store.delete(notePath);
}
getNote(path) {
if (!this.active)
return Promise.resolve(null);
return new Promise((resolve, reject) => {
if (!this.indexDB)
return resolve(null);
const transaction = this.indexDB.transaction([this.storeName], "readonly");
const store = transaction.objectStore(this.storeName);
const request = store.get(path);
request.onsuccess = (event) => {
var _a;
const target = event.target;
resolve((_a = target == null ? void 0 : target.result) != null ? _a : null);
};
request.onerror = (event) => {
reject(event);
};
});
}
getAllNotes() {
if (!this.active)
return Promise.resolve([]);
return new Promise((resolve, reject) => {
if (!this.indexDB)
return resolve([]);
const transaction = this.indexDB.transaction([this.storeName], "readonly");
const store = transaction.objectStore(this.storeName);
const request = store.getAll();
request.onsuccess = (event) => {
var _a;
const target = event.target;
const result = (_a = target == null ? void 0 : target.result) != null ? _a : [];
resolve(result.map((data) => data.sourcePath));
};
request.onerror = (event) => {
reject(event);
};
});
}
resetDatabase() {
if (!this.indexDB)
return;
const transaction = this.indexDB.transaction([this.storeName], "readwrite");
const store = transaction.objectStore(this.storeName);
store.clear();
}
};
// src/obsidian-folder-overview/src/main.ts
var FolderOverviewPlugin = class extends import_obsidian50.Plugin {
constructor() {
super(...arguments);
this.updateOverviewView = updateOverviewView;
this.updateViewDropdown = updateViewDropdown;
}
async onload() {
await this.loadSettings();
this.settingsTab = new SettingsTab(this);
this.addSettingTab(this.settingsTab);
this.settingsTab.display();
registerOverviewCommands(this);
this.fvIndexDB = new FvIndexDB(this);
this.app.workspace.onLayoutReady(async () => {
this.registerView(FOLDER_OVERVIEW_VIEW, (leaf) => {
return new FolderOverviewView(leaf, this);
});
if (this.app.plugins.getPlugin("obsidian-front-matter-title-plugin")) {
this.fmtpHandler = new FrontMatterTitlePluginHandler2(this);
}
if (this.settings.globalSettings.autoUpdateLinks) {
this.fvIndexDB.init(false);
}
});
this.app.vault.on("rename", () => this.handleVaultChange());
this.app.vault.on("create", () => this.handleVaultChange());
this.app.vault.on("delete", () => this.handleVaultChange());
this.registerMarkdownCodeBlockProcessor("folder-overview", (source, el, ctx) => {
this.handleOverviewBlock(source, el, ctx);
});
console.log("loading Folder Overview plugin");
}
handleVaultChange() {
const DEBOUNCE_DELAY_MS = 2e3;
if (!this.settings.globalSettings.autoUpdateLinks)
return;
(0, import_obsidian50.debounce)(() => {
updateAllOverviews(this);
}, DEBOUNCE_DELAY_MS, true)();
}
async handleOverviewBlock(source, el, ctx) {
const observer = new MutationObserver(() => {
var _a;
const editButton = (_a = el.parentElement) == null ? void 0 : _a.childNodes.item(1);
if (editButton) {
editButton.addEventListener("click", (e) => {
e.stopImmediatePropagation();
e.preventDefault();
e.stopPropagation();
new FolderOverviewSettings(this.app, this, (0, import_obsidian50.parseYaml)(source), ctx, el, this.settings.defaultOverviewSettings).open();
}, { capture: true });
}
});
observer.observe(el, {
childList: true,
subtree: true
});
try {
this.app.workspace.onLayoutReady(async () => {
const folderOverview = new FolderOverview(this, ctx, source, el, this.settings.defaultOverviewSettings);
await folderOverview.create(this, el, ctx);
this.updateOverviewView(this);
});
} catch (e) {
new import_obsidian50.Notice("Error creating folder overview (folder notes plugin) - check console for more details");
console.error(e);
}
}
async onunload() {
console.log("Unloading Folder Overview plugin");
}
async loadSettings() {
var _a;
const data = await this.loadData();
this.settings = Object.assign({}, DEFAULT_SETTINGS, data);
if (!this.settings.defaultOverviewSettings) {
this.settings.defaultOverviewSettings = {
...DEFAULT_SETTINGS.defaultOverviewSettings,
...(_a = data == null ? void 0 : data.defaultOverviewSettings) != null ? _a : {}
};
}
if ((data == null ? void 0 : data.firstTimeInsertOverview) === void 0) {
this.settings.firstTimeInsertOverview = true;
}
}
async saveSettings() {
await this.saveData(this.settings);
}
async activateOverviewView() {
const { workspace } = this.app;
let leaf = null;
const leaves = workspace.getLeavesOfType(FOLDER_OVERVIEW_VIEW);
if (leaves.length > 0) {
leaf = leaves[0];
} else {
leaf = workspace.getRightLeaf(false);
await (leaf == null ? void 0 : leaf.setViewState({ type: FOLDER_OVERVIEW_VIEW, active: true }));
}
if (!leaf)
return;
workspace.revealLeaf(leaf);
}
};
async function updateOverviewView(plugin, newYaml) {
const { workspace } = plugin.app;
const leaf = workspace.getLeavesOfType(FOLDER_OVERVIEW_VIEW)[0];
if (!leaf)
return;
const view = leaf.view;
if (!view)
return;
if (!view.yaml)
return;
const yaml = view.yaml.id === "" ? view.yaml : newYaml;
view.display(view.contentEl, yaml != null ? yaml : view.yaml, plugin, view.defaultSettings, view.display, void 0, void 0, view.activeFile, plugin.settingsTab, view.modal, "all");
}
async function updateViewDropdown(plugin) {
const { workspace } = plugin.app;
const leaf = workspace.getLeavesOfType(FOLDER_OVERVIEW_VIEW)[0];
if (!leaf)
return;
const view = leaf.view;
view.display(view.contentEl, view.yaml, plugin, view.defaultSettings, view.display, void 0, void 0, view.activeFile, plugin.settingsTab, view.modal, "dropdown");
}
// src/obsidian-folder-overview/src/view.ts
var FOLDER_OVERVIEW_VIEW = "folder-overview-view";
var FolderOverviewView = class extends import_obsidian51.ItemView {
constructor(leaf, plugin) {
super(leaf);
this.contentEl = this.containerEl.children[1];
this.plugin = plugin;
this.display = this.display.bind(this);
if (plugin instanceof FolderOverviewPlugin) {
this.defaultSettings = plugin.settings.defaultOverviewSettings;
} else if (plugin instanceof FolderNotesPlugin) {
this.defaultSettings = plugin.settings.defaultOverview;
}
this.registerEvent(this.plugin.app.workspace.on("file-open", (file) => {
this.activeFile = file;
this.display(this.contentEl, this.yaml, this.plugin, this.defaultSettings, this.display, void 0, void 0, file, void 0, void 0, "all");
}));
}
getViewType() {
return FOLDER_OVERVIEW_VIEW;
}
getDisplayText() {
return "Folder Overview settings";
}
getIcon() {
return "settings";
}
async onOpen() {
this.display(this.contentEl, this.yaml, this.plugin, this.defaultSettings, this.display, void 0, void 0, this.activeFile);
}
async display(contentEl, yaml, plugin, defaultSettings, display, el, ctx, file, settingsTab, modal, changedSection) {
this.contentEl = contentEl;
this.yaml = yaml;
this.defaultSettings = defaultSettings;
this.changedSection = changedSection;
if (file) {
this.activeFile = file;
}
let header = contentEl.querySelector(".fn-folder-overview-header");
if (!header) {
header = contentEl.createEl("h4", {
cls: "fn-folder-overview-header",
text: "Folder Overview settings"
});
}
const activeFile = plugin.app.workspace.getActiveFile();
const overviews = await getOverviews(plugin, activeFile);
let settingsContainer = contentEl.querySelector(".fn-settings-container");
if (!settingsContainer) {
settingsContainer = contentEl.createDiv({ cls: "fn-settings-container" });
}
let dropdown = settingsContainer.querySelector(".fn-select-overview-setting");
if (!dropdown || changedSection === "all" || changedSection === "dropdown") {
if (dropdown) {
settingsContainer.empty();
}
dropdown = settingsContainer.createDiv({ cls: "fn-select-overview-setting" });
const overviewSetting = new import_obsidian51.Setting(dropdown);
overviewSetting.setName("Select overview").setClass("fn-select-overview-setting").addDropdown((cb) => {
var _a;
if (activeFile) {
const titleCounts = {};
const options = overviews.reduce((acc, overview) => {
var _a2;
const title = parseOverviewTitle(overview, plugin, activeFile.parent, ((_a2 = activeFile.parent) == null ? void 0 : _a2.path) || "", activeFile);
const count = (titleCounts[title] || 0) + 1;
titleCounts[title] = count;
acc[overview.id] = count > 1 ? `${title} (${count})` : title;
return acc;
}, {});
cb.addOptions(options);
}
cb.addOption("default", "Default");
cb.setValue((_a = yaml == null ? void 0 : yaml.id) != null ? _a : "default");
const isDefault = cb.getValue() === "default";
const isYamlIdEmpty = !(yaml == null ? void 0 : yaml.id.trim());
const isCbValueEmpty = cb.getValue().trim() === "";
if (isDefault || isYamlIdEmpty || isCbValueEmpty) {
yaml = defaultSettings;
cb.setValue("default");
} else {
const foundOverview = overviews.find((overview) => overview.id === yaml.id);
yaml = foundOverview;
}
cb.onChange(async (value) => {
if (value === "default") {
yaml = defaultSettings;
} else {
const foundOverview = overviews.find((overview) => overview.id === value);
yaml = foundOverview;
}
await display(contentEl, yaml, plugin, defaultSettings, display, void 0, void 0, activeFile, void 0, void 0, "all");
});
});
}
this.yaml = yaml;
await createOverviewSettings(settingsContainer, yaml, plugin, defaultSettings, display, void 0, void 0, activeFile, void 0, void 0, changedSection);
}
};
// src/main.ts
var FolderNotesPlugin = class extends import_obsidian52.Plugin {
constructor() {
super(...arguments);
this.fmtpHandler = null;
this.hoveredElement = null;
this.mouseEvent = null;
this.hoverLinkTriggered = false;
this.settingsOpened = false;
this.askModalCurrentlyOpen = false;
this.updateOverviewView = updateOverviewView;
this.updateViewDropdown = updateViewDropdown;
}
async onload() {
console.log("loading folder notes plugin");
await this.loadSettings();
this.settingsTab = new SettingsTab2(this.app, this);
this.addSettingTab(this.settingsTab);
this.saveSettings();
this.fvIndexDB = new FvIndexDB(this);
document.body.classList.add("folder-notes-plugin");
if (this.settings.hideFolderNote) {
document.body.classList.add("hide-folder-note");
}
if (this.settings.hideCollapsingIconForEmptyFolders) {
document.body.classList.add("fn-hide-empty-collapse-icon");
}
if (this.settings.underlineFolder) {
document.body.classList.add("folder-note-underline");
}
if (this.settings.boldName) {
document.body.classList.add("folder-note-bold");
}
if (this.settings.cursiveName) {
document.body.classList.add("folder-note-cursive");
}
if (this.settings.boldNameInPath) {
document.body.classList.add("folder-note-bold-path");
}
if (this.settings.cursiveNameInPath) {
document.body.classList.add("folder-note-cursive-path");
}
if (this.settings.underlineFolderInPath) {
document.body.classList.add("folder-note-underline-path");
}
if (this.settings.stopWhitespaceCollapsing) {
document.body.classList.add("fn-whitespace-stop-collapsing");
}
if (this.settings.hideCollapsingIcon) {
document.body.classList.add("fn-hide-collapse-icon");
}
if (this.settings.ignoreAttachmentFolder) {
document.body.classList.add("fn-ignore-attachment-folder");
}
if (!this.settings.highlightFolder) {
document.body.classList.add("disable-folder-highlight");
}
if ((0, import_obsidian52.requireApiVersion)("1.7.2")) {
document.body.classList.add("version-1-7-2");
}
new Commands(this.app, this).registerCommands();
registerOverviewCommands(this);
this.app.workspace.onLayoutReady(this.onLayoutReady.bind(this));
if (!this.settings.persistentSettingsTab.afterRestart) {
this.settings.settingsTab = "general";
}
this.registerDomEvent(window, "keydown", (event) => {
var _a;
const { hoveredElement } = this;
if (this.hoverLinkTriggered)
return;
if (!hoveredElement)
return;
if (!import_obsidian52.Keymap.isModEvent(event))
return;
const folderPath = ((_a = hoveredElement == null ? void 0 : hoveredElement.parentElement) == null ? void 0 : _a.getAttribute("data-path")) || "";
const folderNote = getFolderNote(this, folderPath);
if (!folderNote)
return;
this.app.workspace.trigger("hover-link", {
event: this.mouseEvent,
source: "preview",
hoverParent: {
file: folderNote
},
targetEl: hoveredElement,
linktext: folderNote == null ? void 0 : folderNote.basename,
sourcePath: folderNote == null ? void 0 : folderNote.path
});
this.hoverLinkTriggered = true;
});
this.registerEvent(this.app.workspace.on("file-open", async (openFile) => {
removeActiveFolder(this);
if (!openFile || !openFile.basename) {
return;
}
const folder = getFolder(this, openFile);
if (!folder) {
return;
}
const excludedFolder = getExcludedFolder(this, folder.path, true);
if (excludedFolder == null ? void 0 : excludedFolder.disableFolderNote)
return;
const folderNote = getFolderNote(this, folder.path);
if (!folderNote) {
return;
}
if (folderNote.path !== openFile.path) {
return;
}
setActiveFolder(folder.path, this);
}));
this.registerEvent(this.app.vault.on("create", (file) => {
handleCreate(file, this);
this.handleVaultChange();
}));
this.registerEvent(this.app.vault.on("rename", (file, oldPath) => {
handleRename(file, oldPath, this);
this.handleVaultChange();
}));
this.registerEvent(this.app.vault.on("delete", (file) => {
handleDelete(file, this);
this.handleVaultChange();
}));
this.registerMarkdownCodeBlockProcessor("folder-overview", (source, el, ctx) => {
this.handleOverviewBlock(source, el, ctx);
});
}
onLayoutReady() {
var _a, _b, _c;
if (!this._loaded) {
return;
}
registerFileExplorerObserver(this);
this.registerView(FOLDER_OVERVIEW_VIEW, (leaf2) => {
return new FolderOverviewView(leaf2, this);
});
if (this.app.plugins.getPlugin("obsidian-front-matter-title-plugin")) {
this.fmtpHandler = new FrontMatterTitlePluginHandler(this);
}
this.tabManager = new TabManager(this);
this.tabManager.updateTabs();
this.registerDomEvent(document, "click", (evt) => {
this.handleFileExplorerClick(evt);
}, true);
this.registerDomEvent(document, "auxclick", (evt) => {
this.handleFileExplorerClick(evt);
}, true);
const fileExplorerPlugin = this.app.internalPlugins.getEnabledPluginById("file-explorer");
if (fileExplorerPlugin) {
const originalRevealInFolder = fileExplorerPlugin.revealInFolder.bind(fileExplorerPlugin);
fileExplorerPlugin.revealInFolder = (file) => {
if (file instanceof import_obsidian52.TFile) {
const folder = getFolder(this, file);
if (folder instanceof import_obsidian52.TFolder) {
const folderNote = getFolderNote(this, folder.path);
if (!folderNote || folderNote.path !== file.path) {
return originalRevealInFolder.call(fileExplorerPlugin, file);
}
document.body.classList.remove("hide-folder-note");
originalRevealInFolder.call(fileExplorerPlugin, folder);
const FOLDER_REVEAL_DELAY = 100;
setTimeout(() => {
document.body.classList.add("hide-folder-note");
}, FOLDER_REVEAL_DELAY);
return;
}
}
return originalRevealInFolder.call(fileExplorerPlugin, file);
};
}
const leaf = this.app.workspace.getLeavesOfType("markdown").first();
const view = leaf == null ? void 0 : leaf.view;
if (!view) {
return;
}
const editMode = (_c = (_a = view.editMode) != null ? _a : view.sourceMode) != null ? _c : (_b = this.app.workspace.activeEditor) == null ? void 0 : _b.editMode;
const plugin = this;
if (!editMode) {
return;
}
const clipboardProto = editMode.clipboardManager.constructor.prototype;
const originalHandleDragOver = clipboardProto.handleDragOver;
const originalHandleDrop = clipboardProto.handleDrop;
clipboardProto.handleDragOver = function(evt, ...args) {
const { dragManager } = this.app;
const draggable = dragManager == null ? void 0 : dragManager.draggable;
if ((draggable == null ? void 0 : draggable.file) instanceof import_obsidian52.TFolder) {
const folderNote = getFolderNote(plugin, draggable.file.path);
if (folderNote) {
dragManager.setAction(window.i18next.t("interface.drag-and-drop.insert-link-here"));
return;
}
}
return originalHandleDragOver.call(this, evt, ...args);
};
clipboardProto.handleDrop = function(evt, ...args) {
const { dragManager } = this.app;
const draggable = dragManager == null ? void 0 : dragManager.draggable;
if ((draggable == null ? void 0 : draggable.file) instanceof import_obsidian52.TFolder) {
const folderNote = getFolderNote(plugin, draggable.file.path);
if (folderNote) {
draggable.file = folderNote;
draggable.type = "file";
}
}
return originalHandleDrop.call(this, evt, ...args);
};
if (this.settings.fvGlobalSettings.autoUpdateLinks) {
this.fvIndexDB.init(false);
}
}
handleVaultChange() {
if (!this.settings.fvGlobalSettings.autoUpdateLinks)
return;
const DEBOUNCE_DELAY = 2e3;
(0, import_obsidian52.debounce)(() => {
updateAllOverviews(this);
}, DEBOUNCE_DELAY, true)();
}
handleFileExplorerClick(evt) {
const target = evt.target;
if (evt.shiftKey)
return;
if (this.isMobileClickDisabled())
return;
const { folderTitleEl, onlyClickedOnFolderTitle } = this.getFolderTitleInfo(target);
if (!folderTitleEl)
return;
if (this.shouldIgnoreClickByWhitespaceOrCollapse(target, onlyClickedOnFolderTitle))
return;
const folderPath = this.getValidFolderPath(folderTitleEl);
if (!folderPath)
return;
const usedCtrl = this.isCtrlUsed(evt);
const folderNote = getFolderNote(this, folderPath);
if (!folderNote && this.shouldCreateNote(evt, usedCtrl)) {
this.createNoteAndMark(folderPath);
return;
}
if (!(folderNote instanceof import_obsidian52.TFile))
return;
if (!this.shouldOpenNote(usedCtrl, evt))
return;
if (!this.settings.enableCollapsing || usedCtrl) {
evt.preventDefault();
evt.stopImmediatePropagation();
}
openFolderNote(this, folderNote, evt);
}
isMobileClickDisabled() {
return import_obsidian52.Platform.isMobile && this.settings.disableOpenFolderNoteOnClick;
}
getFolderTitleInfo(target) {
const folderTitleEl = target.closest(".nav-folder-title");
const onlyClickedOnFolderTitle = !!target.closest(".nav-folder-title-content");
return { folderTitleEl, onlyClickedOnFolderTitle };
}
shouldIgnoreClickByWhitespaceOrCollapse(target, onlyClickedOnFolderTitle) {
if (!this.settings.stopWhitespaceCollapsing && !onlyClickedOnFolderTitle)
return true;
if (target.closest(".collapse-icon"))
return true;
return false;
}
getValidFolderPath(folderTitleEl) {
const folderPath = folderTitleEl.getAttribute("data-path");
if (!folderPath)
return null;
const excludedFolder = getExcludedFolder(this, folderPath, true);
if (excludedFolder == null ? void 0 : excludedFolder.disableFolderNote)
return null;
return folderPath;
}
isCtrlUsed(evt) {
return import_obsidian52.Platform.isMacOS ? evt.metaKey : evt.ctrlKey;
}
shouldCreateNote(evt, usedCtrl) {
const isTabMod = import_obsidian52.Keymap.isModEvent(evt) === "tab";
if (!(evt.altKey || isTabMod))
return false;
return this.settings.altKey && evt.altKey || usedCtrl && this.settings.ctrlKey;
}
createNoteAndMark(folderPath) {
createFolderNote(this, folderPath, true, void 0, true);
addCSSClassToFileExplorerEl(folderPath, "has-folder-note", false, this);
removeCSSClassFromFileExplorerEL(folderPath, "has-not-folder-note", false, this);
}
shouldOpenNote(usedCtrl, evt) {
if (this.settings.openWithCtrl && !usedCtrl)
return false;
if (this.settings.openWithAlt && !evt.altKey)
return false;
return true;
}
handleOverviewBlock(source, el, ctx) {
const observer = new MutationObserver(() => {
var _a;
const editButton = (_a = el.parentElement) == null ? void 0 : _a.childNodes.item(1);
if (editButton) {
editButton.addEventListener("click", (e) => {
e.stopImmediatePropagation();
e.preventDefault();
e.stopPropagation();
new FolderOverviewSettings(this.app, this, (0, import_obsidian52.parseYaml)(source), ctx, el, this.settings.defaultOverview).open();
}, { capture: true });
}
});
observer.observe(el, {
childList: true,
subtree: true
});
try {
if (this.app.workspace.layoutReady) {
const { defaultOverview } = this.settings;
const folderOverview = new FolderOverview(this, ctx, source, el, defaultOverview);
folderOverview.create(this, el, ctx);
} else {
this.app.workspace.onLayoutReady(() => {
const folderOverview = new FolderOverview(this, ctx, source, el, this.settings.defaultOverview);
folderOverview.create(this, el, ctx);
});
}
} catch (e) {
new import_obsidian52.Notice("Error creating folder overview (folder notes plugin) - check console for more details");
console.error(e);
}
}
async activateOverviewView() {
const { workspace } = this.app;
let leaf = null;
const leaves = workspace.getLeavesOfType(FOLDER_OVERVIEW_VIEW);
if (leaves.length > 0) {
leaf = leaves[0];
} else {
leaf = workspace.getRightLeaf(false);
await (leaf == null ? void 0 : leaf.setViewState({ type: FOLDER_OVERVIEW_VIEW, active: true }));
}
if (!leaf)
return;
workspace.revealLeaf(leaf);
}
isEmptyFolderNoteFolder(folder) {
let attachmentFolderPath = this.app.vault.getConfig("attachmentFolderPath");
const cleanAttachmentFolderPath = (attachmentFolderPath == null ? void 0 : attachmentFolderPath.replace("./", "")) || "";
const attachmentsAreInRootFolder = attachmentFolderPath === "./" || attachmentFolderPath === "";
const threshold = this.settings.storageLocation === "insideFolder" ? 1 : 0;
if (folder.children.length === 0) {
addCSSClassToFileExplorerEl(folder.path, "fn-empty-folder", false, this);
}
attachmentFolderPath = `${folder.path}/${cleanAttachmentFolderPath}`;
if (folder.children.length === threshold) {
addCSSClassToFileExplorerEl(folder.path, "fn-empty-folder", false, this);
return true;
} else if (folder.children.length > threshold) {
if (attachmentsAreInRootFolder) {
return false;
} else if (this.app.vault.getAbstractFileByPath(attachmentFolderPath) instanceof import_obsidian52.TFolder) {
const attachmentFolder = this.app.vault.getAbstractFileByPath(attachmentFolderPath);
if (attachmentFolder instanceof import_obsidian52.TFolder && folder.children.length <= threshold + 1) {
addCSSClassToFileExplorerEl(folder.path, "fn-empty-folder", false, this);
addCSSClassToFileExplorerEl(folder.path, "fn-has-attachment-folder", false, this);
}
return folder.children.length <= threshold + 1;
}
return false;
}
return true;
}
async changeFolderNameInExplorer(folder, newName, waitForCreate = false, count = 0) {
const MAX_RETRY_COUNT = 5;
const RETRY_DELAY_MS = 500;
if (!newName)
newName = folder.name;
let fileExplorerItem = getFileExplorerElement(folder.path, this);
if (!fileExplorerItem) {
if (waitForCreate && count < MAX_RETRY_COUNT) {
await new Promise((resolve) => setTimeout(resolve, RETRY_DELAY_MS));
void this.changeFolderNameInExplorer(folder, newName, waitForCreate, count + 1);
return;
}
return;
}
fileExplorerItem = fileExplorerItem == null ? void 0 : fileExplorerItem.querySelector("div.nav-folder-title-content");
if (!fileExplorerItem) {
return;
}
if (this.settings.frontMatterTitle.explorer && this.settings.frontMatterTitle.enabled) {
fileExplorerItem.innerText = newName;
fileExplorerItem.setAttribute("old-name", folder.name);
} else {
fileExplorerItem.innerText = folder.name;
fileExplorerItem.removeAttribute("old-name");
}
}
async changeFolderNameInPath(folder, newName, breadcrumb) {
if (!newName)
newName = folder.name;
breadcrumb.textContent = folder.newName || folder.name;
breadcrumb.setAttribute("old-name", folder.name);
breadcrumb.setAttribute("data-path", folder.path);
}
updateAllBreadcrumbs(remove) {
if (!this.settings.frontMatterTitle.path && !remove) {
return;
}
const viewHeaderItems = document.querySelectorAll("span.view-header-breadcrumb");
const files = this.app.vault.getAllLoadedFiles().filter((file) => file instanceof import_obsidian52.TFolder);
viewHeaderItems.forEach((item) => {
if (!item.hasAttribute("data-path")) {
return;
}
const path = item.getAttribute("data-path");
const folder = files.find((file) => file.path === path);
if (!(folder instanceof import_obsidian52.TFolder)) {
return;
}
if (remove) {
item.textContent = folder.name;
item.removeAttribute("old-name");
} else {
item.textContent = folder.newName || folder.name;
item.setAttribute("old-name", folder.name);
item.setAttribute("data-path", folder.path);
}
});
}
onunload() {
unregisterFileExplorerObserver();
document.body.classList.remove("folder-notes-plugin");
document.body.classList.remove("folder-note-underline");
document.body.classList.remove("hide-folder-note");
document.body.classList.remove("fn-whitespace-stop-collapsing");
removeActiveFolder(this);
if (this.fmtpHandler) {
this.fmtpHandler.deleteEvent();
}
}
async loadSettings() {
const data = await this.loadData();
if (data) {
if (data.allowWhitespaceCollapsing === true) {
data.stopWhitespaceCollapsing = false;
delete data.allowWhitespaceCollapsing;
} else if (data.allowWhitespaceCollapsing === false) {
data.stopWhitespaceCollapsing = true;
delete data.allowWhitespaceCollapsing;
}
}
this.settings = Object.assign({}, DEFAULT_SETTINGS2, data);
if (!this.settings.oldFolderNoteName) {
this.settings.oldFolderNoteName = this.settings.folderNoteName;
}
if (!data) {
return;
}
const overview = data.defaultOverview;
if (!overview) {
return;
}
this.settings.defaultOverview = Object.assign({}, DEFAULT_SETTINGS2.defaultOverview, overview);
}
async saveSettings(reloadStyles) {
await this.saveData(this.settings);
if ((!this.settingsOpened || reloadStyles === true) && reloadStyles !== false) {
refreshAllFolderStyles(true, this);
}
}
};
/* nosourcemap */