/*
THIS IS A GENERATED/BUNDLED FILE BY ESBUILD
if you want to view the source, please visit the github repository of this plugin
*/

var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
  for (var name in all)
    __defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
  if (from && typeof from === "object" || typeof from === "function") {
    for (let key of __getOwnPropNames(from))
      if (!__hasOwnProp.call(to, key) && key !== except)
        __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  }
  return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);

// main.ts
var main_exports = {};
__export(main_exports, {
  MultiSuggest: () => MultiSuggest,
  VirtualContentView: () => VirtualContentView,
  default: () => VirtualFooterPlugin
});
module.exports = __toCommonJS(main_exports);
var import_obsidian = require("obsidian");
var RuleType = /* @__PURE__ */ ((RuleType2) => {
  RuleType2["Folder"] = "folder";
  RuleType2["Tag"] = "tag";
  RuleType2["Property"] = "property";
  RuleType2["Multi"] = "multi";
  RuleType2["Dataview"] = "dataview";
  return RuleType2;
})(RuleType || {});
var ContentSource = /* @__PURE__ */ ((ContentSource2) => {
  ContentSource2["Text"] = "text";
  ContentSource2["File"] = "file";
  return ContentSource2;
})(ContentSource || {});
var DEFAULT_SETTINGS = {
  rules: [{
    name: "Default Rule",
    enabled: true,
    type: "folder" /* Folder */,
    path: "",
    // Matches all files by default
    recursive: true,
    contentSource: "text" /* Text */,
    footerText: "",
    // Default content is empty
    renderLocation: "footer" /* Footer */,
    showInSeparateTab: false,
    sidebarTabName: "",
    multiConditionLogic: "any",
    renderAboveProperties: false,
    renderAboveBacklinks: false
  }],
  refreshOnFileOpen: false,
  // Default to false
  renderInSourceMode: false,
  // Default to false
  refreshOnMetadataChange: false
  // Default to false
};
var CSS_DYNAMIC_CONTENT_ELEMENT = "virtual-footer-dynamic-content-element";
var CSS_HEADER_GROUP_ELEMENT = "virtual-footer-header-group";
var CSS_FOOTER_GROUP_ELEMENT = "virtual-footer-footer-group";
var CSS_HEADER_RENDERED_CONTENT = "virtual-footer-header-rendered-content";
var CSS_FOOTER_RENDERED_CONTENT = "virtual-footer-footer-rendered-content";
var CSS_VIRTUAL_FOOTER_CM_PADDING = "virtual-footer-cm-padding";
var CSS_VIRTUAL_FOOTER_REMOVE_FLEX = "virtual-footer-remove-flex";
var CSS_ABOVE_BACKLINKS = "virtual-footer-above-backlinks";
var SELECTOR_EDITOR_CONTENT_AREA = ".cm-editor .cm-content";
var SELECTOR_EDITOR_CONTENT_CONTAINER_PARENT = ".markdown-source-view.mod-cm6 .cm-contentContainer";
var SELECTOR_LIVE_PREVIEW_CONTENT_CONTAINER = ".cm-contentContainer";
var SELECTOR_EDITOR_SIZER = ".cm-sizer";
var SELECTOR_PREVIEW_HEADER_AREA = ".mod-header.mod-ui";
var SELECTOR_PREVIEW_FOOTER_AREA = ".mod-footer";
var SELECTOR_EMBEDDED_BACKLINKS = ".embedded-backlinks";
var SELECTOR_METADATA_CONTAINER = ".metadata-container";
var VIRTUAL_CONTENT_VIEW_TYPE = "virtual-content-view";
var VIRTUAL_CONTENT_SEPARATE_VIEW_TYPE_PREFIX = "virtual-content-separate-view-";
var MultiSuggest = class extends import_obsidian.AbstractInputSuggest {
  /**
   * Creates an instance of MultiSuggest.
   * @param inputEl The HTML input element to attach the suggester to.
   * @param content The set of strings to use as suggestions.
   * @param onSelectCb Callback function executed when a suggestion is selected.
   * @param app The Obsidian App instance.
   */
  constructor(inputEl, content, onSelectCb, app) {
    super(app, inputEl);
    this.inputEl = inputEl;
    this.content = content;
    this.onSelectCb = onSelectCb;
  }
  /**
   * Filters the content set to find suggestions matching the input string.
   * @param inputStr The current string in the input field.
   * @returns An array of matching suggestion strings.
   */
  getSuggestions(inputStr) {
    const lowerCaseInputStr = inputStr.toLocaleLowerCase();
    return [...this.content].filter(
      (contentItem) => contentItem.toLocaleLowerCase().includes(lowerCaseInputStr)
    );
  }
  /**
   * Renders a single suggestion item in the suggestion list.
   * @param content The suggestion string to render.
   * @param el The HTMLElement to render the suggestion into.
   */
  renderSuggestion(content, el) {
    el.setText(content);
  }
  /**
   * Handles the selection of a suggestion.
   * @param content The selected suggestion string.
   * @param _evt The mouse or keyboard event that triggered the selection.
   */
  selectSuggestion(content, _evt) {
    this.onSelectCb(content);
    this.inputEl.value = content;
    this.inputEl.blur();
    this.close();
  }
};
var VirtualContentView = class extends import_obsidian.ItemView {
  constructor(leaf, plugin, viewId, tabName, contentProvider) {
    super(leaf);
    this.plugin = plugin;
    this.viewId = viewId;
    this.tabName = tabName;
    this.contentProvider = contentProvider;
  }
  getViewType() {
    return this.viewId;
  }
  getDisplayText() {
    return this.tabName;
  }
  getIcon() {
    return "text-select";
  }
  async onOpen() {
    this.component = new import_obsidian.Component();
    this.component.load();
    const container = this.containerEl.children[1];
    container.empty();
    this.viewContent = container.createDiv({ cls: "virtual-content-sidebar-view" });
    this.update();
  }
  async onClose() {
    this.component.unload();
  }
  update() {
    if (!this.viewContent) return;
    this.viewContent.empty();
    this.component.unload();
    this.component = new import_obsidian.Component();
    this.component.load();
    const data = this.contentProvider();
    if (data && data.content && data.content.trim() !== "") {
      import_obsidian.MarkdownRenderer.render(this.app, data.content, this.viewContent, data.sourcePath, this.component);
      this.plugin.attachInternalLinkHandlers(this.viewContent, data.sourcePath, this.component);
    } else {
      this.viewContent.createEl("p", {
        text: "No virtual content to display for the current note.",
        cls: "virtual-content-sidebar-empty"
      });
    }
  }
};
var VirtualFooterPlugin = class extends import_obsidian.Plugin {
  constructor() {
    super(...arguments);
    /** Stores pending content injections for preview mode, awaiting DOM availability. */
    this.pendingPreviewInjections = /* @__PURE__ */ new WeakMap();
    /** Manages MutationObservers for views in preview mode to detect when injection targets are ready. */
    this.previewObservers = /* @__PURE__ */ new WeakMap();
    this.initialLayoutReadyProcessed = false;
    this.lastSidebarContent = null;
    this.lastSeparateTabContents = /* @__PURE__ */ new Map();
    /**
     * Handles changes to the active Markdown view, triggering content processing.
     */
    this.handleActiveViewChange = () => {
      const activeView = this.app.workspace.getActiveViewOfType(import_obsidian.MarkdownView);
      this._processView(activeView);
    };
  }
  /**
   * Called when the plugin is loaded.
   */
  async onload() {
    await this.loadSettings();
    this.addSettingTab(new VirtualFooterSettingTab(this.app, this));
    this.registerView(
      VIRTUAL_CONTENT_VIEW_TYPE,
      (leaf) => new VirtualContentView(leaf, this, VIRTUAL_CONTENT_VIEW_TYPE, "Virtual Content", () => this.getLastSidebarContent())
    );
    this.registerDynamicViews();
    this.addRibbonIcon("text-select", "Open virtual content in sidebar", () => {
      this.activateView(VIRTUAL_CONTENT_VIEW_TYPE);
    });
    this.addCommand({
      id: "open-virtual-content-sidebar",
      name: "Open virtual content in sidebar",
      callback: () => {
        this.activateView(VIRTUAL_CONTENT_VIEW_TYPE);
      }
    });
    this.addCommand({
      id: "open-all-virtual-content-sidebar-tabs",
      name: "Open all virtual footer sidebar tabs",
      callback: () => {
        this.activateAllSidebarViews();
      }
    });
    const handleViewUpdate = () => {
      if (this.initialLayoutReadyProcessed) {
        this.handleActiveViewChange();
      }
    };
    const handleFocusChange = () => {
      if (this.settings.refreshOnFileOpen && this.initialLayoutReadyProcessed) {
        this.handleActiveViewChange();
      }
    };
    this.registerEvent(
      this.app.workspace.on("file-open", handleViewUpdate)
    );
    this.registerEvent(
      this.app.workspace.on("layout-change", handleViewUpdate)
    );
    this.registerEvent(
      this.app.workspace.on("active-leaf-change", handleFocusChange)
    );
    this.registerEvent(
      this.app.metadataCache.on("changed", (file) => {
        if (this.settings.refreshOnMetadataChange && this.initialLayoutReadyProcessed) {
          const activeView = this.app.workspace.getActiveViewOfType(import_obsidian.MarkdownView);
          if (activeView && activeView.file && file.path === activeView.file.path) {
            this.handleActiveViewChange();
          }
        }
      })
    );
    this.app.workspace.onLayoutReady(() => {
      if (!this.initialLayoutReadyProcessed) {
        this.handleActiveViewChange();
        this.initialLayoutReadyProcessed = true;
      }
    });
  }
  /**
   * Called when the plugin is unloaded.
   * Cleans up all injected content and observers.
   */
  async onunload() {
    this.app.workspace.detachLeavesOfType(VIRTUAL_CONTENT_VIEW_TYPE);
    this.settings.rules.forEach((rule, index) => {
      if (rule.renderLocation === "sidebar" /* Sidebar */ && rule.showInSeparateTab) {
        this.app.workspace.detachLeavesOfType(this.getSeparateViewId(index));
      }
    });
    this.clearAllViewsDynamicContent();
    document.querySelectorAll(`.${CSS_DYNAMIC_CONTENT_ELEMENT}`).forEach((el) => {
      const componentHolder = el;
      if (componentHolder.component) {
        componentHolder.component.unload();
      }
      el.remove();
    });
    document.querySelectorAll(`.${CSS_VIRTUAL_FOOTER_CM_PADDING}`).forEach((el) => el.classList.remove(CSS_VIRTUAL_FOOTER_CM_PADDING));
    document.querySelectorAll(`.${CSS_VIRTUAL_FOOTER_REMOVE_FLEX}`).forEach((el) => el.classList.remove(CSS_VIRTUAL_FOOTER_REMOVE_FLEX));
    this.previewObservers = /* @__PURE__ */ new WeakMap();
    this.pendingPreviewInjections = /* @__PURE__ */ new WeakMap();
  }
  /**
   * Processes a given Markdown view to inject or update dynamic content.
   * @param view The MarkdownView to process.
   */
  async _processView(view) {
    var _a;
    if (!view || !view.file) {
      if (!this.settings.refreshOnFileOpen || this.app.workspace.getLeavesOfType("markdown").length === 0) {
        this.lastSidebarContent = null;
        this.lastSeparateTabContents.clear();
        this.updateAllSidebarViews();
      }
      return;
    }
    await this.removeDynamicContentFromView(view);
    const applicableRulesWithContent = await this._getApplicableRulesAndContent(view.file.path);
    const viewState = view.getState();
    let combinedHeaderText = "";
    let combinedFooterText = "";
    let combinedSidebarText = "";
    let hasFooterRule = false;
    const contentSeparator = "\n\n";
    this.lastSeparateTabContents.clear();
    const headerContentGroups = { normal: [], aboveProperties: [] };
    const footerContentGroups = { normal: [], aboveBacklinks: [] };
    for (const { rule, contentText, index } of applicableRulesWithContent) {
      if (!contentText || contentText.trim() === "") continue;
      if (rule.renderLocation === "header" /* Header */) {
        if (rule.renderAboveProperties) {
          headerContentGroups.aboveProperties.push(contentText);
        } else {
          headerContentGroups.normal.push(contentText);
        }
      } else if (rule.renderLocation === "footer" /* Footer */) {
        if (rule.renderAboveBacklinks) {
          footerContentGroups.aboveBacklinks.push(contentText);
        } else {
          footerContentGroups.normal.push(contentText);
        }
        hasFooterRule = true;
      } else if (rule.renderLocation === "sidebar" /* Sidebar */) {
        if (rule.showInSeparateTab) {
          const viewId = this.getSeparateViewId(index);
          const existingContent = ((_a = this.lastSeparateTabContents.get(viewId)) == null ? void 0 : _a.content) || "";
          this.lastSeparateTabContents.set(viewId, {
            content: (existingContent ? existingContent + contentSeparator : "") + contentText,
            sourcePath: view.file.path
          });
        } else {
          combinedSidebarText += (combinedSidebarText ? contentSeparator : "") + contentText;
        }
      }
    }
    this.lastSidebarContent = { content: combinedSidebarText, sourcePath: view.file.path };
    this.updateAllSidebarViews();
    const isLivePreview = viewState.mode === "source" && !viewState.source;
    const isSourceMode = viewState.mode === "source" && viewState.source;
    const isReadingMode = viewState.mode === "preview";
    const shouldRenderInSource = isSourceMode && this.settings.renderInSourceMode;
    const shouldRenderInLivePreview = isLivePreview;
    const shouldRenderInReading = isReadingMode;
    if ((shouldRenderInLivePreview || shouldRenderInSource) && hasFooterRule) {
      this.applyLivePreviewFooterStyles(view);
    }
    let pendingHeaderDiv = null;
    let pendingFooterDiv = null;
    let pendingHeaderAbovePropertiesDiv = null;
    let pendingFooterAboveBacklinksDiv = null;
    if (shouldRenderInReading || shouldRenderInLivePreview || shouldRenderInSource) {
      if (headerContentGroups.normal.length > 0) {
        const combinedContent = headerContentGroups.normal.join(contentSeparator);
        const result = await this.renderAndInjectGroupedContent(view, combinedContent, "header" /* Header */, false);
        if (result && shouldRenderInReading) {
          pendingHeaderDiv = result;
        }
      }
      if (headerContentGroups.aboveProperties.length > 0) {
        const combinedContent = headerContentGroups.aboveProperties.join(contentSeparator);
        const result = await this.renderAndInjectGroupedContent(view, combinedContent, "header" /* Header */, true);
        if (result && shouldRenderInReading) {
          pendingHeaderAbovePropertiesDiv = result;
        }
      }
      if (footerContentGroups.normal.length > 0) {
        const combinedContent = footerContentGroups.normal.join(contentSeparator);
        const result = await this.renderAndInjectGroupedContent(view, combinedContent, "footer" /* Footer */, false, false);
        if (result && shouldRenderInReading) {
          pendingFooterDiv = result;
        }
      }
      if (footerContentGroups.aboveBacklinks.length > 0) {
        const combinedContent = footerContentGroups.aboveBacklinks.join(contentSeparator);
        const result = await this.renderAndInjectGroupedContent(view, combinedContent, "footer" /* Footer */, false, true);
        if (result && shouldRenderInReading) {
          pendingFooterAboveBacklinksDiv = result;
        }
      }
    }
    if (pendingHeaderDiv || pendingFooterDiv || pendingHeaderAbovePropertiesDiv || pendingFooterAboveBacklinksDiv) {
      this.pendingPreviewInjections.set(view, {
        headerDiv: pendingHeaderDiv || void 0,
        footerDiv: pendingFooterDiv || void 0,
        headerAbovePropertiesDiv: pendingHeaderAbovePropertiesDiv || void 0,
        footerAboveBacklinksDiv: pendingFooterAboveBacklinksDiv || void 0,
        filePath: view.file.path
      });
      this.ensurePreviewObserver(view);
    }
  }
  /**
   * Renders combined Markdown content and injects it into the specified location in the view.
   * @param view The MarkdownView to inject content into.
   * @param combinedContentText The combined Markdown string to render.
   * @param renderLocation Specifies whether to render in the header or footer.
   * @param renderAboveProperties For header content, whether to render above properties section.
   * @param renderAboveBacklinks For footer content, whether to render above backlinks section.
   * @returns The rendered HTMLElement if injection is deferred (for preview mode), otherwise null.
   */
  async renderAndInjectGroupedContent(view, combinedContentText, renderLocation, renderAboveProperties = false, renderAboveBacklinks = false) {
    var _a, _b, _c, _d;
    if (!combinedContentText || combinedContentText.trim() === "") {
      return null;
    }
    const isRenderInHeader = renderLocation === "header" /* Header */;
    const sourcePath = ((_a = view.file) == null ? void 0 : _a.path) || "";
    const groupDiv = document.createElement("div");
    groupDiv.className = CSS_DYNAMIC_CONTENT_ELEMENT;
    groupDiv.classList.add(
      isRenderInHeader ? CSS_HEADER_GROUP_ELEMENT : CSS_FOOTER_GROUP_ELEMENT,
      isRenderInHeader ? CSS_HEADER_RENDERED_CONTENT : CSS_FOOTER_RENDERED_CONTENT
    );
    if (!isRenderInHeader && renderAboveBacklinks) {
      groupDiv.classList.add(CSS_ABOVE_BACKLINKS);
      groupDiv.classList.add("virtual-footer-above-backlinks");
    }
    if (isRenderInHeader && renderAboveProperties) {
      groupDiv.classList.add("virtual-footer-above-properties");
    }
    const component = new import_obsidian.Component();
    component.load();
    groupDiv.component = component;
    try {
      await import_obsidian.MarkdownRenderer.render(this.app, combinedContentText, groupDiv, sourcePath, component);
    } catch (error) {
      console.log("VirtualFooter: Error during initial render, will retry after delay:", error);
      const placeholderEl = groupDiv.createEl("div", { cls: "virtual-footer-loading" });
      placeholderEl.createEl("p", { text: "Loading virtual content..." });
      setTimeout(async () => {
        try {
          placeholderEl.remove();
          await import_obsidian.MarkdownRenderer.render(this.app, combinedContentText, groupDiv, sourcePath, component);
          this.attachInternalLinkHandlers(groupDiv, sourcePath, component);
        } catch (secondError) {
          console.error("VirtualFooter: Failed to render content after retry:", secondError);
          const errorEl = groupDiv.createEl("div", { cls: "virtual-footer-error" });
          errorEl.createEl("p", { text: "Error rendering virtual content. Please reload the page or check the content for errors." });
        }
      }, 2e3);
    }
    let injectionSuccessful = false;
    const viewState = view.getState();
    if (viewState.mode === "preview") {
      const previewContentParent = view.previewMode.containerEl;
      let targetParent = null;
      if (isRenderInHeader) {
        if (renderAboveProperties) {
          targetParent = previewContentParent.querySelector(SELECTOR_METADATA_CONTAINER);
        }
        if (!targetParent) {
          targetParent = previewContentParent.querySelector(SELECTOR_PREVIEW_HEADER_AREA);
        }
      } else {
        if (renderAboveBacklinks) {
          targetParent = previewContentParent.querySelector(SELECTOR_EMBEDDED_BACKLINKS);
        }
        if (!targetParent) {
          targetParent = previewContentParent.querySelector(SELECTOR_PREVIEW_FOOTER_AREA);
        }
      }
      if (targetParent) {
        if (isRenderInHeader && renderAboveProperties) {
          view.previewMode.containerEl.querySelectorAll(`.${CSS_HEADER_GROUP_ELEMENT}.virtual-footer-above-properties`).forEach((el) => {
            var _a2;
            const holder = el;
            (_a2 = holder.component) == null ? void 0 : _a2.unload();
            el.remove();
          });
        } else if (isRenderInHeader && !renderAboveProperties) {
          targetParent.querySelectorAll(`.${CSS_HEADER_GROUP_ELEMENT}:not(.virtual-footer-above-properties)`).forEach((el) => {
            var _a2;
            const holder = el;
            (_a2 = holder.component) == null ? void 0 : _a2.unload();
            el.remove();
          });
        } else if (!isRenderInHeader && renderAboveBacklinks) {
          view.previewMode.containerEl.querySelectorAll(`.${CSS_FOOTER_GROUP_ELEMENT}.virtual-footer-above-backlinks`).forEach((el) => {
            var _a2;
            const holder = el;
            (_a2 = holder.component) == null ? void 0 : _a2.unload();
            el.remove();
          });
        } else if (!isRenderInHeader && !renderAboveBacklinks) {
          targetParent.querySelectorAll(`.${CSS_FOOTER_GROUP_ELEMENT}:not(.virtual-footer-above-backlinks)`).forEach((el) => {
            var _a2;
            const holder = el;
            (_a2 = holder.component) == null ? void 0 : _a2.unload();
            el.remove();
          });
        }
        if (isRenderInHeader && !renderAboveProperties) {
          targetParent.appendChild(groupDiv);
        } else if (!isRenderInHeader && !renderAboveBacklinks) {
          targetParent.appendChild(groupDiv);
        } else {
          (_b = targetParent.parentElement) == null ? void 0 : _b.insertBefore(groupDiv, targetParent);
        }
        injectionSuccessful = true;
      }
    } else if (viewState.mode === "source") {
      if (isRenderInHeader) {
        let targetParent = null;
        if (renderAboveProperties) {
          targetParent = view.containerEl.querySelector(SELECTOR_METADATA_CONTAINER);
        }
        if (!targetParent) {
          const cmContentContainer = view.containerEl.querySelector(SELECTOR_LIVE_PREVIEW_CONTENT_CONTAINER);
          if (cmContentContainer == null ? void 0 : cmContentContainer.parentElement) {
            cmContentContainer.parentElement.querySelectorAll(`.${CSS_HEADER_GROUP_ELEMENT}:not(.virtual-footer-above-properties)`).forEach((el) => {
              var _a2;
              const holder = el;
              (_a2 = holder.component) == null ? void 0 : _a2.unload();
              el.remove();
            });
            cmContentContainer.parentElement.insertBefore(groupDiv, cmContentContainer);
            injectionSuccessful = true;
          }
        } else {
          view.containerEl.querySelectorAll(`.${CSS_HEADER_GROUP_ELEMENT}.virtual-footer-above-properties`).forEach((el) => {
            var _a2;
            const holder = el;
            (_a2 = holder.component) == null ? void 0 : _a2.unload();
            el.remove();
          });
          (_c = targetParent.parentElement) == null ? void 0 : _c.insertBefore(groupDiv, targetParent);
          injectionSuccessful = true;
        }
      } else {
        let targetParent = null;
        if (renderAboveBacklinks) {
          targetParent = view.containerEl.querySelector(SELECTOR_EMBEDDED_BACKLINKS);
        }
        if (!targetParent) {
          targetParent = view.containerEl.querySelector(SELECTOR_EDITOR_SIZER);
        }
        if (targetParent) {
          if (renderAboveBacklinks) {
            view.containerEl.querySelectorAll(`.${CSS_FOOTER_GROUP_ELEMENT}.virtual-footer-above-backlinks`).forEach((el) => {
              var _a2;
              const holder = el;
              (_a2 = holder.component) == null ? void 0 : _a2.unload();
              el.remove();
            });
          } else {
            targetParent.querySelectorAll(`.${CSS_FOOTER_GROUP_ELEMENT}:not(.virtual-footer-above-backlinks)`).forEach((el) => {
              var _a2;
              const holder = el;
              (_a2 = holder.component) == null ? void 0 : _a2.unload();
              el.remove();
            });
          }
          if (!renderAboveBacklinks || targetParent.matches(SELECTOR_EDITOR_SIZER)) {
            targetParent.appendChild(groupDiv);
          } else {
            (_d = targetParent.parentElement) == null ? void 0 : _d.insertBefore(groupDiv, targetParent);
          }
          injectionSuccessful = true;
        }
      }
    }
    if (injectionSuccessful) {
      this.attachInternalLinkHandlers(groupDiv, sourcePath, component);
      return null;
    } else {
      if (viewState.mode === "preview") {
        console.log(`VirtualFooter: Deferring injection for ${renderLocation} in preview mode. Target not found yet.`);
        return groupDiv;
      } else {
        component.unload();
        console.warn(`VirtualFooter: Failed to find injection point for dynamic content group (${renderLocation}). View mode: ${viewState.mode}.`);
        return null;
      }
    }
  }
  /**
   * Ensures a MutationObserver is set up for a view in preview mode to handle deferred content injection.
   * The observer watches for the appearance of target DOM elements and is careful not to act on stale data.
   * @param view The MarkdownView to observe.
   */
  ensurePreviewObserver(view) {
    var _a;
    if (this.previewObservers.has(view) || !view.file || !((_a = view.previewMode) == null ? void 0 : _a.containerEl)) {
      return;
    }
    const observerPath = view.file.path;
    const observer = new MutationObserver((_mutations) => {
      var _a2, _b;
      const pending = this.pendingPreviewInjections.get(view);
      if (!view.file || view.file.path !== observerPath || !pending || pending.filePath !== observerPath) {
        observer.disconnect();
        if (this.previewObservers.get(view) === observer) {
          this.previewObservers.delete(view);
        }
        return;
      }
      if (!pending.headerDiv && !pending.footerDiv && !pending.headerAbovePropertiesDiv && !pending.footerAboveBacklinksDiv) {
        observer.disconnect();
        if (this.previewObservers.get(view) === observer) {
          this.previewObservers.delete(view);
        }
        this.pendingPreviewInjections.delete(view);
        return;
      }
      let allResolved = true;
      const sourcePath = view.file.path;
      if (pending.headerDiv) {
        const headerTargetParent = view.previewMode.containerEl.querySelector(SELECTOR_PREVIEW_HEADER_AREA);
        if (headerTargetParent) {
          headerTargetParent.querySelectorAll(`.${CSS_HEADER_GROUP_ELEMENT}`).forEach((el) => {
            var _a3;
            const holder = el;
            (_a3 = holder.component) == null ? void 0 : _a3.unload();
            el.remove();
          });
          headerTargetParent.appendChild(pending.headerDiv);
          if (pending.headerDiv.component) {
            this.attachInternalLinkHandlers(pending.headerDiv, sourcePath, pending.headerDiv.component);
          }
          delete pending.headerDiv;
        } else {
          allResolved = false;
        }
      }
      if (pending.headerAbovePropertiesDiv) {
        const headerTargetParent = view.previewMode.containerEl.querySelector(SELECTOR_METADATA_CONTAINER);
        if (headerTargetParent) {
          view.previewMode.containerEl.querySelectorAll(`.${CSS_HEADER_GROUP_ELEMENT}.virtual-footer-above-properties`).forEach((el) => {
            var _a3;
            const holder = el;
            (_a3 = holder.component) == null ? void 0 : _a3.unload();
            el.remove();
          });
          pending.headerAbovePropertiesDiv.classList.add("virtual-footer-above-properties");
          (_a2 = headerTargetParent.parentElement) == null ? void 0 : _a2.insertBefore(pending.headerAbovePropertiesDiv, headerTargetParent);
          if (pending.headerAbovePropertiesDiv.component) {
            this.attachInternalLinkHandlers(pending.headerAbovePropertiesDiv, sourcePath, pending.headerAbovePropertiesDiv.component);
          }
          delete pending.headerAbovePropertiesDiv;
        } else {
          allResolved = false;
        }
      }
      if (pending.footerDiv) {
        const footerTargetParent = view.previewMode.containerEl.querySelector(SELECTOR_PREVIEW_FOOTER_AREA);
        if (footerTargetParent) {
          footerTargetParent.querySelectorAll(`.${CSS_FOOTER_GROUP_ELEMENT}`).forEach((el) => {
            var _a3;
            const holder = el;
            (_a3 = holder.component) == null ? void 0 : _a3.unload();
            el.remove();
          });
          footerTargetParent.appendChild(pending.footerDiv);
          if (pending.footerDiv.component) {
            this.attachInternalLinkHandlers(pending.footerDiv, sourcePath, pending.footerDiv.component);
          }
          delete pending.footerDiv;
        } else {
          allResolved = false;
        }
      }
      if (pending.footerAboveBacklinksDiv) {
        const footerTargetParent = view.previewMode.containerEl.querySelector(SELECTOR_EMBEDDED_BACKLINKS);
        if (footerTargetParent) {
          view.previewMode.containerEl.querySelectorAll(`.${CSS_FOOTER_GROUP_ELEMENT}.virtual-footer-above-backlinks`).forEach((el) => {
            var _a3;
            const holder = el;
            (_a3 = holder.component) == null ? void 0 : _a3.unload();
            el.remove();
          });
          pending.footerAboveBacklinksDiv.classList.add("virtual-footer-above-backlinks");
          (_b = footerTargetParent.parentElement) == null ? void 0 : _b.insertBefore(pending.footerAboveBacklinksDiv, footerTargetParent);
          if (pending.footerAboveBacklinksDiv.component) {
            this.attachInternalLinkHandlers(pending.footerAboveBacklinksDiv, sourcePath, pending.footerAboveBacklinksDiv.component);
          }
          delete pending.footerAboveBacklinksDiv;
        } else {
          allResolved = false;
        }
      }
      if (allResolved) {
        observer.disconnect();
        if (this.previewObservers.get(view) === observer) {
          this.previewObservers.delete(view);
        }
        this.pendingPreviewInjections.delete(view);
      }
    });
    observer.observe(view.previewMode.containerEl, { childList: true, subtree: true });
    this.previewObservers.set(view, observer);
  }
  /**
   * Applies CSS classes to adjust CodeMirror (Live Preview) layout for footer content.
   * @param view The MarkdownView in Live Preview mode.
   */
  applyLivePreviewFooterStyles(view) {
    const contentEl = view.containerEl.querySelector(SELECTOR_EDITOR_CONTENT_AREA);
    const containerEl = view.containerEl.querySelector(SELECTOR_EDITOR_CONTENT_CONTAINER_PARENT);
    contentEl == null ? void 0 : contentEl.classList.add(CSS_VIRTUAL_FOOTER_CM_PADDING);
    containerEl == null ? void 0 : containerEl.classList.add(CSS_VIRTUAL_FOOTER_REMOVE_FLEX);
  }
  /**
   * Removes CSS classes used for Live Preview footer layout adjustments.
   * @param viewOrContainer The MarkdownView or a specific HTMLElement container.
   */
  removeLivePreviewFooterStyles(viewOrContainer) {
    const container = viewOrContainer instanceof import_obsidian.MarkdownView ? viewOrContainer.containerEl : viewOrContainer;
    const contentEl = container.querySelector(SELECTOR_EDITOR_CONTENT_AREA);
    const containerEl = container.querySelector(SELECTOR_EDITOR_CONTENT_CONTAINER_PARENT);
    contentEl == null ? void 0 : contentEl.classList.remove(CSS_VIRTUAL_FOOTER_CM_PADDING);
    containerEl == null ? void 0 : containerEl.classList.remove(CSS_VIRTUAL_FOOTER_REMOVE_FLEX);
  }
  /**
   * Removes all plugin-injected DOM elements from a given container.
   * @param containerEl The HTMLElement to search within.
   */
  async removeInjectedContentDOM(containerEl) {
    containerEl.querySelectorAll(`.${CSS_DYNAMIC_CONTENT_ELEMENT}`).forEach((el) => {
      const componentHolder = el;
      if (componentHolder.component) {
        componentHolder.component.unload();
      }
      el.remove();
    });
  }
  /**
   * Removes all dynamic content, styles, and observers associated with a specific view.
   * @param view The MarkdownView to clean up.
   */
  async removeDynamicContentFromView(view) {
    var _a, _b, _c, _d;
    this.removeLivePreviewFooterStyles(view);
    await this.removeInjectedContentDOM(view.containerEl);
    const observer = this.previewObservers.get(view);
    if (observer) {
      observer.disconnect();
      this.previewObservers.delete(view);
    }
    const pending = this.pendingPreviewInjections.get(view);
    if (pending) {
      (_b = (_a = pending.headerDiv) == null ? void 0 : _a.component) == null ? void 0 : _b.unload();
      (_d = (_c = pending.footerDiv) == null ? void 0 : _c.component) == null ? void 0 : _d.unload();
      this.pendingPreviewInjections.delete(view);
    }
  }
  /**
   * Clears dynamic content from all currently open Markdown views.
   * Typically used during plugin unload or when global settings change significantly.
   */
  clearAllViewsDynamicContent() {
    this.app.workspace.getLeavesOfType("markdown").forEach((leaf) => {
      if (leaf.view instanceof import_obsidian.MarkdownView) {
        this.removeDynamicContentFromView(leaf.view);
      }
    });
    this.lastSidebarContent = null;
    this.lastSeparateTabContents.clear();
    this.updateAllSidebarViews();
  }
  /**
   * Determines which rules apply to a given file path and fetches their content.
   * @param filePath The path of the file to check against rules.
   * @returns A promise that resolves to an array of objects, each containing an applicable rule and its content.
   */
  async _getApplicableRulesAndContent(filePath) {
    const allApplicable = [];
    const abstractFile = this.app.vault.getAbstractFileByPath(filePath);
    if (!(abstractFile instanceof import_obsidian.TFile)) {
      return [];
    }
    const file = abstractFile;
    let fileTags = null;
    const fileCache = this.app.metadataCache.getFileCache(file);
    const hasEnabledTagRule = this.settings.rules.some((r) => r.enabled && (r.type === "tag" /* Tag */ || r.type === "multi" /* Multi */));
    if (hasEnabledTagRule && fileCache) {
      const allTagsInFileWithHash = (0, import_obsidian.getAllTags)(fileCache);
      fileTags = allTagsInFileWithHash ? allTagsInFileWithHash.map((tag) => tag.substring(1)) : [];
    }
    for (const [index, currentRule] of this.settings.rules.entries()) {
      if (!currentRule.enabled) {
        continue;
      }
      let isMatch = false;
      if (currentRule.type === "folder" /* Folder */) {
        isMatch = this._checkFolderMatch(file, currentRule);
      } else if (currentRule.type === "tag" /* Tag */) {
        isMatch = this._checkTagMatch(fileTags, currentRule);
      } else if (currentRule.type === "property" /* Property */) {
        isMatch = this._checkPropertyMatch(fileCache == null ? void 0 : fileCache.frontmatter, currentRule);
      } else if (currentRule.type === "multi" /* Multi */) {
        if (currentRule.conditions && currentRule.conditions.length > 0) {
          const checkCondition = (condition) => {
            let result = false;
            if (condition.type === "folder") {
              result = this._checkFolderMatch(file, condition);
            } else if (condition.type === "tag") {
              result = this._checkTagMatch(fileTags, condition);
            } else if (condition.type === "property") {
              result = this._checkPropertyMatch(fileCache == null ? void 0 : fileCache.frontmatter, condition);
            }
            return condition.negated ? !result : result;
          };
          if (currentRule.multiConditionLogic === "all") {
            isMatch = currentRule.conditions.every(checkCondition);
          } else {
            isMatch = currentRule.conditions.some(checkCondition);
          }
        }
      } else if (currentRule.type === "dataview" /* Dataview */) {
        isMatch = await this._checkDataviewMatch(file, currentRule.dataviewQuery || "");
      }
      if (currentRule.type !== "multi" /* Multi */ && currentRule.negated) {
        isMatch = !isMatch;
      }
      if (isMatch) {
        const contentText = await this._fetchContentForRule(currentRule);
        allApplicable.push({ rule: currentRule, contentText, index });
      }
    }
    return allApplicable;
  }
  _checkFolderMatch(file, rule) {
    var _a, _b, _c;
    if (rule.path === void 0) return false;
    const ruleRecursive = rule.recursive === void 0 ? true : rule.recursive;
    if (rule.path === "") {
      return true;
    } else if (rule.path === "/") {
      return ruleRecursive ? true : (_b = (_a = file.parent) == null ? void 0 : _a.isRoot()) != null ? _b : false;
    } else {
      let normalizedRuleFolderPath = rule.path.endsWith("/") ? rule.path.slice(0, -1) : rule.path;
      if (ruleRecursive) {
        return file.path.startsWith(normalizedRuleFolderPath + "/");
      } else {
        return ((_c = file.parent) == null ? void 0 : _c.path) === normalizedRuleFolderPath;
      }
    }
  }
  _checkTagMatch(fileTags, rule) {
    var _a;
    if (!rule.tag || !fileTags) return false;
    const ruleTag = rule.tag;
    const includeSubtags = (_a = rule.includeSubtags) != null ? _a : false;
    for (const fileTag of fileTags) {
      if (includeSubtags) {
        if (fileTag === ruleTag || fileTag.startsWith(ruleTag + "/")) {
          return true;
        }
      } else {
        if (fileTag === ruleTag) {
          return true;
        }
      }
    }
    return false;
  }
  _checkPropertyMatch(frontmatter, rule) {
    if (!rule.propertyName || !frontmatter) return false;
    const propertyKey = rule.propertyName;
    const expectedPropertyValue = rule.propertyValue;
    const actualPropertyValue = frontmatter[propertyKey];
    if (actualPropertyValue !== void 0 && actualPropertyValue !== null) {
      if (!expectedPropertyValue || expectedPropertyValue.trim() === "") {
        return true;
      }
      if (typeof actualPropertyValue === "string") {
        return actualPropertyValue === expectedPropertyValue;
      } else if (Array.isArray(actualPropertyValue)) {
        return actualPropertyValue.map(String).includes(expectedPropertyValue);
      } else if (typeof actualPropertyValue === "number" || typeof actualPropertyValue === "boolean") {
        return String(actualPropertyValue) === expectedPropertyValue;
      }
    }
    return false;
  }
  /**
   * Checks if a file matches a Dataview query rule
   * @param file The file to check against the dataview query
   * @param query The dataview query string
   * @returns True if the file matches the dataview query, false otherwise
   */
  async _checkDataviewMatch(file, query) {
    var _a;
    const dataviewPlugin = (_a = this.app.plugins.plugins) == null ? void 0 : _a.dataview;
    if (!dataviewPlugin) {
      console.warn("VirtualFooter: Dataview plugin is required for dataview rules but is not installed or enabled.");
      return false;
    }
    try {
      const dataviewApi = dataviewPlugin.api;
      if (!dataviewApi) {
        console.warn("VirtualFooter: Cannot access Dataview API.");
        return false;
      }
      const results = await dataviewApi.query(query);
      if (!results || !results.successful || !results.value || !Array.isArray(results.value.values)) {
        console.warn(`VirtualFooter: Dataview query did not return valid results for query: ${query} in file: ${file.path} Dataview error:`, results);
        return false;
      }
      const resultPaths = [];
      for (const page of results.value.values) {
        if (page.path) {
          resultPaths.push(page.path);
        }
      }
      return resultPaths.includes(file.path);
    } catch (error) {
      console.error(`VirtualFooter: Error executing Dataview query: ${query}`, error);
      return false;
    }
  }
  /**
   * Fetches the content for a given rule, either from direct text or from a specified file.
   * @param rule The rule for which to fetch content.
   * @returns A promise that resolves to the content string.
   */
  async _fetchContentForRule(rule) {
    if (rule.contentSource === "file" /* File */ && rule.footerFilePath) {
      const file = this.app.vault.getAbstractFileByPath(rule.footerFilePath);
      if (file instanceof import_obsidian.TFile) {
        try {
          return await this.app.vault.cachedRead(file);
        } catch (error) {
          console.error(`VirtualFooter: Error reading content file ${rule.footerFilePath}`, error);
          return `<!-- Error reading content file: ${rule.footerFilePath} -->`;
        }
      } else {
        console.warn(`VirtualFooter: Content file not found for rule: ${rule.footerFilePath}`);
        return `<!-- Content file not found: ${rule.footerFilePath} -->`;
      }
    }
    return rule.footerText || "";
  }
  /**
   * Attaches event handlers to the injected content for internal link navigation.
   * @param container The HTMLElement containing the rendered Markdown.
   * @param sourcePath The path of the file where the content is injected, for link resolution.
   * @param component The Obsidian Component associated with this content, for event registration.
   */
  attachInternalLinkHandlers(container, sourcePath, component) {
    component.registerDomEvent(container, "click", (event) => {
      if (event.button !== 0) return;
      const target = event.target;
      const linkElement = target.closest("a.internal-link");
      if (linkElement) {
        event.preventDefault();
        const href = linkElement.dataset.href;
        if (href) {
          const inNewPane = event.ctrlKey || event.metaKey;
          this.app.workspace.openLinkText(href, sourcePath, inNewPane);
        }
      }
    });
    component.registerDomEvent(container, "auxclick", (event) => {
      if (event.button !== 1) return;
      const target = event.target;
      const linkElement = target.closest("a.internal-link");
      if (linkElement) {
        event.preventDefault();
        const href = linkElement.dataset.href;
        if (href) {
          this.app.workspace.openLinkText(href, sourcePath, true);
        }
      }
    });
  }
  /**
   * Loads plugin settings from storage, migrating old formats if necessary.
   */
  async loadSettings() {
    const loadedData = await this.loadData();
    this.settings = JSON.parse(JSON.stringify(DEFAULT_SETTINGS));
    if (loadedData) {
      const oldGlobalRenderLocation = loadedData.renderLocation;
      if (loadedData.rules && Array.isArray(loadedData.rules)) {
        this.settings.rules = loadedData.rules.map(
          (loadedRule) => this._migrateRule(loadedRule, oldGlobalRenderLocation)
        );
      }
      if (typeof loadedData.refreshOnFileOpen === "boolean") {
        this.settings.refreshOnFileOpen = loadedData.refreshOnFileOpen;
      }
      if (typeof loadedData.renderInSourceMode === "boolean") {
        this.settings.renderInSourceMode = loadedData.renderInSourceMode;
      }
      if (typeof loadedData.refreshOnMetadataChange === "boolean") {
        this.settings.refreshOnMetadataChange = loadedData.refreshOnMetadataChange;
      }
    }
    if (!this.settings.rules || this.settings.rules.length === 0) {
      this.settings.rules = [JSON.parse(JSON.stringify(DEFAULT_SETTINGS.rules[0]))];
      this.normalizeRule(this.settings.rules[0]);
    } else {
      this.settings.rules.forEach((rule) => this.normalizeRule(rule));
    }
    if (typeof this.settings.refreshOnFileOpen !== "boolean") {
      this.settings.refreshOnFileOpen = DEFAULT_SETTINGS.refreshOnFileOpen;
    }
    if (typeof this.settings.renderInSourceMode !== "boolean") {
      this.settings.renderInSourceMode = DEFAULT_SETTINGS.renderInSourceMode;
    }
    if (typeof this.settings.refreshOnMetadataChange !== "boolean") {
      this.settings.refreshOnMetadataChange = DEFAULT_SETTINGS.refreshOnMetadataChange;
    }
  }
  /**
   * Migrates a rule from an older settings format to the current Rule interface.
   * @param loadedRule The rule object loaded from storage.
   * @param globalRenderLocation An optional global render location from a very old settings format.
   * @returns A migrated and normalized Rule object.
   */
  _migrateRule(loadedRule, globalRenderLocation) {
    let type;
    if (Object.values(RuleType).includes(loadedRule.type)) {
      type = loadedRule.type;
    } else if (typeof loadedRule.folderPath === "string") {
      type = "folder" /* Folder */;
    } else {
      type = DEFAULT_SETTINGS.rules[0].type;
    }
    let contentSource;
    if (Object.values(ContentSource).includes(loadedRule.contentSource)) {
      contentSource = loadedRule.contentSource;
    } else {
      contentSource = typeof loadedRule.folderPath === "string" && loadedRule.contentSource === void 0 ? "text" /* Text */ : DEFAULT_SETTINGS.rules[0].contentSource;
    }
    const migratedRule = {
      name: loadedRule.name || DEFAULT_SETTINGS.rules[0].name,
      enabled: loadedRule.enabled !== void 0 ? loadedRule.enabled : DEFAULT_SETTINGS.rules[0].enabled,
      type,
      contentSource,
      footerText: loadedRule.footerText || "",
      // Retain name for compatibility
      renderLocation: loadedRule.renderLocation || globalRenderLocation || DEFAULT_SETTINGS.rules[0].renderLocation,
      recursive: loadedRule.recursive !== void 0 ? loadedRule.recursive : true,
      showInSeparateTab: loadedRule.showInSeparateTab || false,
      sidebarTabName: loadedRule.sidebarTabName || "",
      multiConditionLogic: loadedRule.multiConditionLogic || "any",
      renderAboveProperties: loadedRule.renderAboveProperties !== void 0 ? loadedRule.renderAboveProperties : void 0,
      renderAboveBacklinks: loadedRule.renderAboveBacklinks !== void 0 ? loadedRule.renderAboveBacklinks : void 0,
      dataviewQuery: loadedRule.dataviewQuery || "",
      footerFilePath: loadedRule.footerFilePath || ""
      // Retained name for compatibility
    };
    if (migratedRule.type === "folder" /* Folder */) {
      migratedRule.path = loadedRule.path !== void 0 ? loadedRule.path : loadedRule.folderPath !== void 0 ? loadedRule.folderPath : DEFAULT_SETTINGS.rules[0].path;
    } else if (migratedRule.type === "tag" /* Tag */) {
      migratedRule.tag = loadedRule.tag !== void 0 ? loadedRule.tag : "";
      migratedRule.includeSubtags = loadedRule.includeSubtags !== void 0 ? loadedRule.includeSubtags : false;
    } else if (migratedRule.type === "property" /* Property */) {
      migratedRule.propertyName = loadedRule.propertyName || "";
      migratedRule.propertyValue = loadedRule.propertyValue || "";
    } else if (migratedRule.type === "multi" /* Multi */) {
      migratedRule.conditions = loadedRule.conditions || [];
    }
    if (migratedRule.contentSource === "file" /* File */) {
      migratedRule.footerFilePath = loadedRule.footerFilePath || "";
    }
    return migratedRule;
  }
  /**
   * Normalizes a rule object, ensuring all required fields are present and defaults are applied.
   * Also cleans up fields that are not relevant to the rule's current type or content source.
   * @param rule The rule to normalize.
   */
  normalizeRule(rule) {
    const originalRule = { ...rule };
    rule.name = rule.name === void 0 ? DEFAULT_SETTINGS.rules[0].name : rule.name;
    rule.enabled = typeof rule.enabled === "boolean" ? rule.enabled : DEFAULT_SETTINGS.rules[0].enabled;
    rule.type = rule.type || DEFAULT_SETTINGS.rules[0].type;
    delete rule.path;
    delete rule.recursive;
    delete rule.tag;
    delete rule.includeSubtags;
    delete rule.propertyName;
    delete rule.propertyValue;
    delete rule.conditions;
    delete rule.multiConditionLogic;
    delete rule.dataviewQuery;
    if (rule.type === "folder" /* Folder */) {
      rule.path = originalRule.path === void 0 ? DEFAULT_SETTINGS.rules[0].path || "" : originalRule.path;
      rule.recursive = rule.path === "" ? true : typeof originalRule.recursive === "boolean" ? originalRule.recursive : true;
    } else if (rule.type === "tag" /* Tag */) {
      rule.tag = originalRule.tag === void 0 ? "" : originalRule.tag;
      rule.includeSubtags = typeof originalRule.includeSubtags === "boolean" ? originalRule.includeSubtags : false;
    } else if (rule.type === "property" /* Property */) {
      rule.propertyName = originalRule.propertyName === void 0 ? "" : originalRule.propertyName;
      rule.propertyValue = originalRule.propertyValue === void 0 ? "" : originalRule.propertyValue;
    } else if (rule.type === "multi" /* Multi */) {
      rule.conditions = Array.isArray(originalRule.conditions) ? originalRule.conditions : [];
      rule.multiConditionLogic = originalRule.multiConditionLogic === "all" ? "all" : "any";
    } else if (rule.type === "dataview" /* Dataview */) {
      rule.dataviewQuery = originalRule.dataviewQuery === void 0 ? "" : originalRule.dataviewQuery;
    }
    rule.contentSource = originalRule.contentSource || DEFAULT_SETTINGS.rules[0].contentSource;
    rule.footerText = originalRule.footerText || "";
    rule.renderLocation = originalRule.renderLocation || DEFAULT_SETTINGS.rules[0].renderLocation;
    if (rule.contentSource === "file" /* File */) {
      rule.footerFilePath = originalRule.footerFilePath || "";
    } else {
      delete rule.footerFilePath;
    }
    if (rule.renderLocation === "sidebar" /* Sidebar */) {
      rule.showInSeparateTab = typeof originalRule.showInSeparateTab === "boolean" ? originalRule.showInSeparateTab : false;
      rule.sidebarTabName = originalRule.sidebarTabName || "";
    } else {
      delete rule.showInSeparateTab;
      delete rule.sidebarTabName;
    }
    if (rule.renderLocation === "header" /* Header */) {
      rule.renderAboveProperties = typeof originalRule.renderAboveProperties === "boolean" ? originalRule.renderAboveProperties : false;
      delete rule.renderAboveBacklinks;
    } else if (rule.renderLocation === "footer" /* Footer */) {
      rule.renderAboveBacklinks = typeof originalRule.renderAboveBacklinks === "boolean" ? originalRule.renderAboveBacklinks : false;
      delete rule.renderAboveProperties;
    } else {
      delete rule.renderAboveProperties;
      delete rule.renderAboveBacklinks;
    }
  }
  /**
   * Saves the current plugin settings to storage and triggers a view refresh.
   */
  async saveSettings() {
    this.settings.rules.forEach((rule) => this.normalizeRule(rule));
    await this.saveData(this.settings);
    this.registerDynamicViews();
    this.handleActiveViewChange();
  }
  async activateView(viewId) {
    this.app.workspace.detachLeavesOfType(viewId);
    const leaf = this.app.workspace.getRightLeaf(true);
    if (leaf) {
      await leaf.setViewState({
        type: viewId,
        active: true
      });
      this.app.workspace.revealLeaf(leaf);
    }
  }
  activateAllSidebarViews() {
    this.activateView(VIRTUAL_CONTENT_VIEW_TYPE);
    this.settings.rules.forEach((rule, index) => {
      if (rule.enabled && rule.renderLocation === "sidebar" /* Sidebar */ && rule.showInSeparateTab) {
        this.activateView(this.getSeparateViewId(index));
      }
    });
  }
  updateAllSidebarViews() {
    const leaves = this.app.workspace.getLeavesOfType(VIRTUAL_CONTENT_VIEW_TYPE);
    for (const leaf of leaves) {
      if (leaf.view instanceof VirtualContentView) {
        leaf.view.update();
      }
    }
    this.settings.rules.forEach((rule, index) => {
      if (rule.renderLocation === "sidebar" /* Sidebar */ && rule.showInSeparateTab) {
        const viewId = this.getSeparateViewId(index);
        const separateLeaves = this.app.workspace.getLeavesOfType(viewId);
        for (const leaf of separateLeaves) {
          if (leaf.view instanceof VirtualContentView) {
            leaf.view.update();
          }
        }
      }
    });
  }
  getLastSidebarContent() {
    return this.lastSidebarContent;
  }
  getSeparateTabContent(viewId) {
    return this.lastSeparateTabContents.get(viewId) || null;
  }
  getSeparateViewId(ruleIndex) {
    return `${VIRTUAL_CONTENT_SEPARATE_VIEW_TYPE_PREFIX}${ruleIndex}`;
  }
  registerDynamicViews() {
    this.settings.rules.forEach((rule, index) => {
      var _a;
      if (rule.renderLocation === "sidebar" /* Sidebar */ && rule.showInSeparateTab) {
        const viewId = this.getSeparateViewId(index);
        const tabName = ((_a = rule.sidebarTabName) == null ? void 0 : _a.trim()) ? `Virtual Content: ${rule.sidebarTabName}` : `Virtual Content: Rule ${index + 1}`;
        this.registerView(
          viewId,
          (leaf) => new VirtualContentView(leaf, this, viewId, tabName, () => this.getSeparateTabContent(viewId))
        );
      }
    });
  }
};
var VirtualFooterSettingTab = class extends import_obsidian.PluginSettingTab {
  constructor(app, plugin) {
    super(app, plugin);
    this.plugin = plugin;
    // Caches for suggestion lists to improve performance
    this.allFolderPathsCache = null;
    this.allTagsCache = null;
    this.allMarkdownFilePathsCache = null;
    this.allPropertyNamesCache = null;
    this.ruleExpandedStates = [];
    this.debouncedSave = (0, import_obsidian.debounce)(() => this.plugin.saveSettings(), 1e3, true);
    this.debouncedSaveAndRefresh = (0, import_obsidian.debounce)(() => {
      this.plugin.saveSettings().then(() => this.display());
    }, 1e3, true);
  }
  /**
   * Lazily gets and caches all unique folder paths in the vault.
   * Includes special paths "" (all files) and "/" (root).
   * @returns A set of available folder paths.
   */
  getAvailableFolderPaths() {
    if (this.allFolderPathsCache) return this.allFolderPathsCache;
    const paths = /* @__PURE__ */ new Set(["/", ""]);
    this.app.vault.getAllLoadedFiles().forEach((file) => {
      if (file.parent) {
        const parentPath = file.parent.isRoot() ? "/" : file.parent.path.endsWith("/") ? file.parent.path : file.parent.path + "/";
        if (parentPath !== "/") paths.add(parentPath);
      }
      if ("children" in file && file.path !== "/") {
        const folderPath = file.path.endsWith("/") ? file.path : file.path + "/";
        paths.add(folderPath);
      }
    });
    this.allFolderPathsCache = paths;
    return paths;
  }
  /**
   * Lazily gets and caches all unique tags (without '#') present in Markdown files.
   * @returns A set of available tags.
   */
  getAvailableTags() {
    if (this.allTagsCache) return this.allTagsCache;
    const collectedTags = /* @__PURE__ */ new Set();
    this.app.vault.getMarkdownFiles().forEach((file) => {
      const fileCache = this.app.metadataCache.getFileCache(file);
      if (fileCache) {
        const tagsInFile = (0, import_obsidian.getAllTags)(fileCache);
        tagsInFile == null ? void 0 : tagsInFile.forEach((tag) => {
          collectedTags.add(tag.substring(1));
        });
      }
    });
    this.allTagsCache = collectedTags;
    return collectedTags;
  }
  /**
   * Lazily gets and caches all Markdown file paths in the vault.
   * @returns A set of available Markdown file paths.
   */
  getAvailableMarkdownFilePaths() {
    if (this.allMarkdownFilePathsCache) return this.allMarkdownFilePathsCache;
    const paths = /* @__PURE__ */ new Set();
    this.app.vault.getMarkdownFiles().forEach((file) => {
      paths.add(file.path);
    });
    this.allMarkdownFilePathsCache = paths;
    return paths;
  }
  /**
   * Lazily gets and caches all unique frontmatter property keys from Markdown files.
   * @returns A set of available property names.
   */
  getAvailablePropertyNames() {
    var _a, _b;
    if (this.allPropertyNamesCache) return this.allPropertyNamesCache;
    const keys = ((_b = (_a = this.app.metadataCache).getFrontmatterPropertyKeys) == null ? void 0 : _b.call(_a)) || [];
    this.allPropertyNamesCache = new Set(keys);
    return this.allPropertyNamesCache;
  }
  /**
   * Renders the settings tab UI.
   * This method is called by Obsidian when the settings tab is opened.
   */
  display() {
    const { containerEl } = this;
    containerEl.empty();
    containerEl.createEl("h2", { text: "Virtual Content Settings" });
    containerEl.createEl("p", { text: "Define rules to dynamically add content to the header or footer of notes based on their folder, tags, or properties." });
    new import_obsidian.Setting(containerEl).setName("Render in source mode").setDesc("If enabled, virtual content will be rendered in source mode. By default, content only appears in Live Preview and Reading modes.").addToggle((toggle) => toggle.setValue(this.plugin.settings.renderInSourceMode).onChange(async (value) => {
      this.plugin.settings.renderInSourceMode = value;
      await this.plugin.saveSettings();
    }));
    new import_obsidian.Setting(containerEl).setName("Refresh on focus change").setDesc("If enabled, virtual content will refresh when switching files. This may cause a slight flicker but is useful if you frequently change the text of virtual content and need immediate updates. If disabled the virtual content will be updated on file open and view change (editing/reading view). To prevent virtual content in the sidebar disappearing when clicking out of a note, it will always keep the last notes virtual content open, which means new tabs will show the virtual content of the last used note. Disabled by default.").addToggle((toggle) => toggle.setValue(this.plugin.settings.refreshOnFileOpen).onChange(async (value) => {
      this.plugin.settings.refreshOnFileOpen = value;
      await this.plugin.saveSettings();
    }));
    new import_obsidian.Setting(containerEl).setName("Refresh on metadata change").setDesc("If enabled, virtual content will refresh when the current note's metadata (frontmatter, tags) changes. This is useful for rules that depend on properties or tags and need to update immediately when those values change.").addToggle((toggle) => toggle.setValue(this.plugin.settings.refreshOnMetadataChange).onChange(async (value) => {
      this.plugin.settings.refreshOnMetadataChange = value;
      await this.plugin.saveSettings();
    }));
    containerEl.createEl("h3", { text: "Rules" });
    this.allFolderPathsCache = null;
    this.allTagsCache = null;
    this.allMarkdownFilePathsCache = null;
    this.allPropertyNamesCache = null;
    const numRules = this.plugin.settings.rules.length;
    while (this.ruleExpandedStates.length < numRules) {
      this.ruleExpandedStates.push(false);
    }
    if (this.ruleExpandedStates.length > numRules) {
      this.ruleExpandedStates.length = numRules;
    }
    const rulesContainer = containerEl.createDiv("rules-container virtual-footer-rules-container");
    if (!this.plugin.settings.rules) {
      this.plugin.settings.rules = [];
    }
    if (this.plugin.settings.rules.length === 0) {
      const newRule = JSON.parse(JSON.stringify(DEFAULT_SETTINGS.rules[0]));
      this.plugin.normalizeRule(newRule);
      this.plugin.settings.rules.push(newRule);
      if (this.ruleExpandedStates.length === 0) {
        this.ruleExpandedStates.push(false);
      }
    }
    this.plugin.settings.rules.forEach((rule, index) => {
      this.renderRuleControls(rule, index, rulesContainer);
    });
    new import_obsidian.Setting(containerEl).addButton((button) => button.setButtonText("Add new rule").setCta().setClass("virtual-footer-add-button").onClick(async () => {
      const newRule = JSON.parse(JSON.stringify(DEFAULT_SETTINGS.rules[0]));
      this.plugin.normalizeRule(newRule);
      this.plugin.settings.rules.push(newRule);
      this.ruleExpandedStates.push(true);
      await this.plugin.saveSettings();
      this.display();
    }));
  }
  /**
   * Renders the UI controls for a single rule within the settings tab.
   * @param rule The rule object to render controls for.
   * @param index The index of the rule in the settings array.
   * @param containerEl The parent HTMLElement to append the rule controls to.
   */
  renderRuleControls(rule, index, containerEl) {
    const ruleDiv = containerEl.createDiv("rule-item virtual-footer-rule-item");
    if (!this.ruleExpandedStates[index]) {
      ruleDiv.addClass("is-collapsed");
    }
    const ruleNameDisplay = rule.name && rule.name.trim() !== "" ? rule.name : "Unnamed Rule";
    const ruleHeadingText = `Rule ${index + 1}: ${ruleNameDisplay}`;
    const ruleHeading = ruleDiv.createEl("h4", { text: ruleHeadingText });
    ruleHeading.addClass("virtual-footer-rule-heading");
    const ruleContentContainer = ruleDiv.createDiv("virtual-footer-rule-content");
    ruleHeading.addEventListener("click", () => {
      const isNowExpanded = !ruleDiv.classList.toggle("is-collapsed");
      this.ruleExpandedStates[index] = isNowExpanded;
    });
    new import_obsidian.Setting(ruleContentContainer).setName("Rule name").setDesc('A descriptive name for this rule (e.g., "Project Notes Footer").').addText((text) => text.setPlaceholder("e.g., Blog Post Footer").setValue(rule.name || "").onChange((value) => {
      rule.name = value;
      const newNameDisplay = value && value.trim() !== "" ? value : "Unnamed Rule";
      ruleHeading.textContent = `Rule ${index + 1}: ${newNameDisplay}`;
      this.debouncedSave();
    }));
    new import_obsidian.Setting(ruleContentContainer).setName("Enabled").setDesc("If disabled, this rule will not be applied.").addToggle((toggle) => toggle.setValue(rule.enabled).onChange(async (value) => {
      rule.enabled = value;
      await this.plugin.saveSettings();
    }));
    new import_obsidian.Setting(ruleContentContainer).setName("Rule type").setDesc("Apply this rule based on folder, tag, property, or a combination.").addDropdown((dropdown) => dropdown.addOption("folder" /* Folder */, "Folder").addOption("tag" /* Tag */, "Tag").addOption("property" /* Property */, "Property").addOption("multi" /* Multi */, "Multi-condition").addOption("dataview" /* Dataview */, "Dataview").setValue(rule.type).onChange(async (value) => {
      rule.type = value;
      if (rule.type === "multi" /* Multi */) {
        const oldRule = { ...rule };
        rule.conditions = [];
      }
      this.plugin.normalizeRule(rule);
      await this.plugin.saveSettings();
      this.display();
    }));
    if (rule.type === "folder" /* Folder */) {
      new import_obsidian.Setting(ruleContentContainer).setName("Condition").setDesc("Choose whether this condition should be met or not met.").addDropdown(
        (dropdown) => dropdown.addOption("is", "is").addOption("not", "not").setValue(rule.negated ? "not" : "is").onChange(async (value) => {
          rule.negated = value === "not";
          await this.plugin.saveSettings();
        })
      );
      new import_obsidian.Setting(ruleContentContainer).setName("Folder path").setDesc('Path for the rule. Use "" for all files, "/" for root folder, or "FolderName/" for specific folders (ensure trailing slash for non-root folders).').addText((text) => {
        text.setPlaceholder("e.g., Meetings/, /, or empty for all").setValue(rule.path || "").onChange((value) => {
          rule.path = value;
          this.plugin.normalizeRule(rule);
          this.debouncedSaveAndRefresh();
        });
        new MultiSuggest(text.inputEl, this.getAvailableFolderPaths(), (selectedPath) => {
          rule.path = selectedPath;
          this.plugin.normalizeRule(rule);
          text.setValue(selectedPath);
          this.plugin.saveSettings().then(() => this.display());
        }, this.plugin.app);
      });
      new import_obsidian.Setting(ruleContentContainer).setName("Include subfolders (recursive)").setDesc('If enabled, rule applies to files in subfolders. For "all files" (empty path), this is always true. For root path ("/"), enabling applies to all vault files, disabling applies only to files directly in the root.').addToggle((toggle) => {
        toggle.setValue(rule.recursive).onChange(async (value) => {
          rule.recursive = value;
          await this.plugin.saveSettings();
        });
        if (rule.path === "") {
          toggle.setDisabled(true);
        }
      });
    } else if (rule.type === "tag" /* Tag */) {
      new import_obsidian.Setting(ruleContentContainer).setName("Condition").setDesc("Choose whether this condition should be met or not met.").addDropdown(
        (dropdown) => dropdown.addOption("is", "is").addOption("not", "not").setValue(rule.negated ? "not" : "is").onChange(async (value) => {
          rule.negated = value === "not";
          await this.plugin.saveSettings();
        })
      );
      new import_obsidian.Setting(ruleContentContainer).setName("Tag value").setDesc('Tag to match (without the # prefix). E.g., "project" or "status/done".').addText((text) => {
        text.setPlaceholder("e.g., important or project/alpha").setValue(rule.tag || "").onChange((value) => {
          rule.tag = value.startsWith("#") ? value.substring(1) : value;
          this.debouncedSave();
        });
        new MultiSuggest(text.inputEl, this.getAvailableTags(), (selectedTag) => {
          const normalizedTag = selectedTag.startsWith("#") ? selectedTag.substring(1) : selectedTag;
          rule.tag = normalizedTag;
          text.setValue(normalizedTag);
          this.plugin.saveSettings();
        }, this.plugin.app);
      });
      new import_obsidian.Setting(ruleContentContainer).setName("Include subtags").setDesc("If enabled, a rule for 'tag' will also apply to 'tag/subtag1', 'tag/subtag2/subtag3', etc. If disabled, it only applies to the exact tag.").addToggle((toggle) => {
        toggle.setValue(rule.includeSubtags).onChange(async (value) => {
          rule.includeSubtags = value;
          await this.plugin.saveSettings();
        });
      });
    } else if (rule.type === "property" /* Property */) {
      new import_obsidian.Setting(ruleContentContainer).setName("Condition").setDesc("Choose whether this condition should be met or not met.").addDropdown(
        (dropdown) => dropdown.addOption("is", "is").addOption("not", "not").setValue(rule.negated ? "not" : "is").onChange(async (value) => {
          rule.negated = value === "not";
          await this.plugin.saveSettings();
        })
      );
      new import_obsidian.Setting(ruleContentContainer).setName("Property name").setDesc("The name of the Obsidian property (frontmatter key) to match.").addText((text) => {
        text.setPlaceholder("e.g., status, type, author").setValue(rule.propertyName || "").onChange((value) => {
          rule.propertyName = value;
          this.debouncedSave();
        });
        new MultiSuggest(text.inputEl, this.getAvailablePropertyNames(), (selectedName) => {
          rule.propertyName = selectedName;
          text.setValue(selectedName);
          this.plugin.saveSettings();
        }, this.plugin.app);
      });
      new import_obsidian.Setting(ruleContentContainer).setName("Property value").setDesc("The value the property should have. Leave empty to match any file that has this property (regardless of value). For list/array properties, matches if this value is one of the items.").addText((text) => text.setPlaceholder("e.g., complete, article, John Doe (or leave empty)").setValue(rule.propertyValue || "").onChange((value) => {
        rule.propertyValue = value;
        this.debouncedSave();
      }));
    } else if (rule.type === "multi" /* Multi */) {
      this.renderMultiConditionControls(rule, ruleContentContainer);
    } else if (rule.type === "dataview" /* Dataview */) {
      new import_obsidian.Setting(ruleContentContainer).setName("Condition").setDesc("Choose whether this condition should be met or not met.").addDropdown(
        (dropdown) => dropdown.addOption("is", "is").addOption("not", "not").setValue(rule.negated ? "not" : "is").onChange(async (value) => {
          rule.negated = value === "not";
          await this.plugin.saveSettings();
        })
      );
      new import_obsidian.Setting(ruleContentContainer).setName("Dataview query").setDesc("Enter a Dataview LIST query to match notes where this rule should apply.").addTextArea((text) => text.setPlaceholder('LIST FROM "References/Authors" WHERE startswith(file.name, "Test") OR startswith(file.name, "Example")').setValue(rule.dataviewQuery || "").onChange((value) => {
        rule.dataviewQuery = value;
        this.debouncedSave();
      }));
      const infoDiv = ruleContentContainer.createDiv("dataview-info");
      infoDiv.createEl("p", {
        text: "Note: The Dataview plugin must be installed for this rule type to work.",
        cls: "setting-item-description"
      });
    }
    new import_obsidian.Setting(ruleContentContainer).setName("Content source").setDesc("Where to get the content from: direct text input or a separate Markdown file.").addDropdown((dropdown) => dropdown.addOption("text" /* Text */, "Direct text").addOption("file" /* File */, "Markdown file").setValue(rule.contentSource || "text" /* Text */).onChange(async (value) => {
      rule.contentSource = value;
      this.plugin.normalizeRule(rule);
      await this.plugin.saveSettings();
      this.display();
    }));
    if (rule.contentSource === "file" /* File */) {
      new import_obsidian.Setting(ruleContentContainer).setName("Content file path").setDesc('Path to the .md file to use as content (e.g., "templates/common-footer.md").').addText((text) => {
        text.setPlaceholder("e.g., templates/common-footer.md").setValue(rule.footerFilePath || "").onChange((value) => {
          rule.footerFilePath = value;
          this.debouncedSave();
        });
        new MultiSuggest(text.inputEl, this.getAvailableMarkdownFilePaths(), (selectedPath) => {
          rule.footerFilePath = selectedPath;
          text.setValue(selectedPath);
          this.plugin.saveSettings();
        }, this.plugin.app);
      });
    } else {
      new import_obsidian.Setting(ruleContentContainer).setName("Content text").setDesc("Markdown text to display. This will be rendered.").addTextArea((text) => text.setPlaceholder("Enter your markdown content here...\nSupports multiple lines and **Markdown** formatting.").setValue(rule.footerText || "").onChange((value) => {
        rule.footerText = value;
        this.debouncedSave();
      }));
    }
    new import_obsidian.Setting(ruleContentContainer).setName("Render location").setDesc("Choose whether this rule renders its content in the header, footer, or a dedicated sidebar tab.").addDropdown((dropdown) => dropdown.addOption("footer" /* Footer */, "Footer").addOption("header" /* Header */, "Header").addOption("sidebar" /* Sidebar */, "Sidebar").setValue(rule.renderLocation || "footer" /* Footer */).onChange(async (value) => {
      rule.renderLocation = value;
      this.plugin.normalizeRule(rule);
      await this.plugin.saveSettings();
      this.display();
    }));
    if (rule.renderLocation === "sidebar" /* Sidebar */) {
      new import_obsidian.Setting(ruleContentContainer).setName("Show in separate tab").setDesc("If enabled, this content will appear in its own sidebar tab instead of being combined with other sidebar rules.").addToggle((toggle) => toggle.setValue(rule.showInSeparateTab).onChange(async (value) => {
        rule.showInSeparateTab = value;
        await this.plugin.saveSettings();
        this.display();
      }));
      if (rule.showInSeparateTab) {
        new import_obsidian.Setting(ruleContentContainer).setName("Sidebar tab name").setDesc("The name for the separate sidebar tab. If empty, a default name will be used.").addText((text) => text.setPlaceholder("e.g., Related Notes").setValue(rule.sidebarTabName || "").onChange((value) => {
          rule.sidebarTabName = value;
          this.debouncedSave();
        }));
      }
    }
    if (rule.renderLocation === "header" /* Header */) {
      new import_obsidian.Setting(ruleContentContainer).setName("Render above properties").setDesc("If enabled, header content will be rendered above the frontmatter properties section.").addToggle((toggle) => toggle.setValue(rule.renderAboveProperties || false).onChange(async (value) => {
        rule.renderAboveProperties = value;
        await this.plugin.saveSettings();
      }));
    }
    if (rule.renderLocation === "footer" /* Footer */) {
      new import_obsidian.Setting(ruleContentContainer).setName("Render above backlinks").setDesc("If enabled, footer content will be rendered above the embedded backlinks section. It is recommended to only enable this if you have backlinks enabled in the note, otherwise the note height may be affected.").addToggle((toggle) => toggle.setValue(rule.renderAboveBacklinks || false).onChange(async (value) => {
        rule.renderAboveBacklinks = value;
        await this.plugin.saveSettings();
      }));
    }
    const ruleActionsSetting = new import_obsidian.Setting(ruleContentContainer).setClass("virtual-footer-rule-actions");
    ruleActionsSetting.addButton((button) => button.setIcon("arrow-up").setTooltip("Move rule up").setClass("virtual-footer-move-button").setDisabled(index === 0).onClick(async () => {
      if (index > 0) {
        const rules = this.plugin.settings.rules;
        const ruleToMove = rules.splice(index, 1)[0];
        rules.splice(index - 1, 0, ruleToMove);
        const expandedStateToMove = this.ruleExpandedStates.splice(index, 1)[0];
        this.ruleExpandedStates.splice(index - 1, 0, expandedStateToMove);
        await this.plugin.saveSettings();
        this.display();
      }
    }));
    ruleActionsSetting.addButton((button) => button.setIcon("arrow-down").setTooltip("Move rule down").setClass("virtual-footer-move-button").setDisabled(index === this.plugin.settings.rules.length - 1).onClick(async () => {
      if (index < this.plugin.settings.rules.length - 1) {
        const rules = this.plugin.settings.rules;
        const ruleToMove = rules.splice(index, 1)[0];
        rules.splice(index + 1, 0, ruleToMove);
        const expandedStateToMove = this.ruleExpandedStates.splice(index, 1)[0];
        this.ruleExpandedStates.splice(index + 1, 0, expandedStateToMove);
        await this.plugin.saveSettings();
        this.display();
      }
    }));
    ruleActionsSetting.controlEl.createDiv({ cls: "virtual-footer-actions-spacer" });
    ruleActionsSetting.addButton((button) => button.setButtonText("Delete rule").setWarning().setClass("virtual-footer-delete-button").onClick(async () => {
      this.plugin.settings.rules.splice(index, 1);
      this.ruleExpandedStates.splice(index, 1);
      await this.plugin.saveSettings();
      this.display();
    }));
  }
  renderMultiConditionControls(rule, containerEl) {
    var _a;
    new import_obsidian.Setting(containerEl).setName("Condition logic").setDesc("Choose whether any condition or all conditions must be met.").addDropdown((dropdown) => dropdown.addOption("any", "Any condition").addOption("all", "All conditions").setValue(rule.multiConditionLogic || "any").onChange(async (value) => {
      rule.multiConditionLogic = value;
      await this.plugin.saveSettings();
    }));
    const conditionsSetting = new import_obsidian.Setting(containerEl).setName("Conditions").setDesc("This rule will apply if the selected logic is met by the following conditions.");
    const descEl = conditionsSetting.settingEl.querySelector(".setting-item-description");
    if (descEl) {
      const hintEl = document.createElement("p");
      hintEl.className = "setting-item-description";
      hintEl.innerText = "Hint: For very complex rules, consider using the Dataview rule type instead.";
      descEl.insertAdjacentElement("afterend", hintEl);
    }
    const conditionsContainer = containerEl.createDiv("virtual-footer-conditions-container");
    (_a = rule.conditions) == null ? void 0 : _a.forEach((condition, index) => {
      this.renderSubConditionControls(condition, index, rule, conditionsContainer);
    });
    new import_obsidian.Setting(containerEl).addButton((button) => button.setButtonText("Add condition").setCta().onClick(async () => {
      rule.conditions = rule.conditions || [];
      rule.conditions.push({ type: "folder", path: "", recursive: true, negated: false });
      await this.plugin.saveSettings();
      this.display();
    }));
  }
  renderSubConditionControls(condition, index, rule, containerEl) {
    const conditionDiv = containerEl.createDiv("virtual-footer-sub-condition-item");
    const setting = new import_obsidian.Setting(conditionDiv).addDropdown(
      (dropdown) => dropdown.addOption("is", "is").addOption("not", "not").setValue(condition.negated ? "not" : "is").onChange(async (value) => {
        condition.negated = value === "not";
        await this.plugin.saveSettings();
      })
    ).addDropdown(
      (dropdown) => dropdown.addOption("folder", "Folder").addOption("tag", "Tag").addOption("property", "Property").setValue(condition.type).onChange(async (value) => {
        condition.type = value;
        delete condition.path;
        delete condition.recursive;
        delete condition.tag;
        delete condition.includeSubtags;
        delete condition.propertyName;
        delete condition.propertyValue;
        await this.plugin.saveSettings();
        this.display();
      })
    );
    if (condition.type === "folder") {
      setting.addText((text) => {
        text.setPlaceholder("Folder path").setValue(condition.path || "").onChange((value) => {
          condition.path = value;
          this.debouncedSave();
        });
        new MultiSuggest(text.inputEl, this.getAvailableFolderPaths(), (selected) => {
          condition.path = selected;
          text.setValue(selected);
          this.plugin.saveSettings();
        }, this.plugin.app);
      });
      setting.addToggle(
        (toggle) => {
          var _a;
          return toggle.setTooltip("Include subfolders").setValue((_a = condition.recursive) != null ? _a : true).onChange(async (value) => {
            condition.recursive = value;
            await this.plugin.saveSettings();
          });
        }
      );
    } else if (condition.type === "tag") {
      setting.addText((text) => {
        text.setPlaceholder("Tag value (no #)").setValue(condition.tag || "").onChange((value) => {
          condition.tag = value.startsWith("#") ? value.substring(1) : value;
          this.debouncedSave();
        });
        new MultiSuggest(text.inputEl, this.getAvailableTags(), (selected) => {
          const normalized = selected.startsWith("#") ? selected.substring(1) : selected;
          condition.tag = normalized;
          text.setValue(normalized);
          this.plugin.saveSettings();
        }, this.plugin.app);
      });
      setting.addToggle(
        (toggle) => {
          var _a;
          return toggle.setTooltip("Include subtags").setValue((_a = condition.includeSubtags) != null ? _a : false).onChange(async (value) => {
            condition.includeSubtags = value;
            await this.plugin.saveSettings();
          });
        }
      );
    } else if (condition.type === "property") {
      setting.addText((text) => {
        text.setPlaceholder("Property name").setValue(condition.propertyName || "").onChange((value) => {
          condition.propertyName = value;
          this.debouncedSave();
        });
        new MultiSuggest(text.inputEl, this.getAvailablePropertyNames(), (selected) => {
          condition.propertyName = selected;
          text.setValue(selected);
          this.plugin.saveSettings();
        }, this.plugin.app);
      });
      setting.addText(
        (text) => text.setPlaceholder("Property value (or leave empty)").setValue(condition.propertyValue || "").onChange((value) => {
          condition.propertyValue = value;
          this.debouncedSave();
        })
      );
    }
    setting.addButton(
      (button) => button.setIcon("trash").setTooltip("Delete condition").setWarning().onClick(async () => {
        var _a;
        (_a = rule.conditions) == null ? void 0 : _a.splice(index, 1);
        await this.plugin.saveSettings();
        this.display();
      })
    );
  }
};


/* nosourcemap */