obsidian#WorkspaceLeaf TypeScript Examples

The following examples show how to use obsidian#WorkspaceLeaf. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: utility.ts    From quickadd with MIT License 7 votes vote down vote up
export async function openFile(app: App, file: TFile, optional?: {openInNewTab?: boolean, direction?: NewTabDirection, mode?: FileViewMode, focus?: boolean}) {
    let leaf: WorkspaceLeaf;

    if (optional?.openInNewTab && optional?.direction) {
        leaf = app.workspace.splitActiveLeaf(optional.direction);
    } else {
        leaf = app.workspace.getUnpinnedLeaf();
    }

    await leaf.openFile(file)

    if (optional?.mode || optional?.focus) {
        await leaf.setViewState({
            ...leaf.getViewState(),
            state: optional.mode && optional.mode !== 'default' ? {...leaf.view.getState(), mode: optional.mode} : leaf.view.getState(),
            popstate: true,
        } as ViewState, { focus: optional?.focus });
    }
}
Example #2
Source File: utils.ts    From obsidian-map-view with GNU General Public License v3.0 7 votes vote down vote up
export async function getEditor(
    app: App,
    leafToUse?: WorkspaceLeaf
): Promise<Editor> {
    let view =
        leafToUse && leafToUse.view instanceof MarkdownView
            ? leafToUse.view
            : app.workspace.getActiveViewOfType(MarkdownView);
    if (view) return view.editor;
    return null;
}
Example #3
Source File: handler.ts    From obsidian-switcher-plus with GNU General Public License v3.0 6 votes vote down vote up
/**
   * Reveals and optionally bring into focus a WorkspaceLeaf, including leaves
   * from the side panels.
   * @param  {WorkspaceLeaf} leaf
   * @param  {boolean} pushHistory?
   * @param  {Record<string} eState?
   * @param  {} unknown>
   * @returns void
   */
  activateLeaf(
    leaf: WorkspaceLeaf,
    pushHistory?: boolean,
    eState?: Record<string, unknown>,
  ): void {
    const { workspace } = this.app;
    const isInSidePanel = !this.isMainPanelLeaf(leaf);
    const state = { focus: true, ...eState };

    if (isInSidePanel) {
      workspace.revealLeaf(leaf);
    }

    workspace.setActiveLeaf(leaf, pushHistory);
    leaf.view.setEphemeralState(state);
  }
Example #4
Source File: active-folder.ts    From alx-folder-note with MIT License 6 votes vote down vote up
private handleActiveLeafChange(leaf: WorkspaceLeaf | null) {
    let folder;
    if (
      leaf &&
      leaf.view instanceof MarkdownView &&
      (folder = this.fncApi.getFolderFromNote(leaf.view.file))
    ) {
      this.activeFolder = folder;
    } else {
      this.activeFolder = null;
    }
  }
Example #5
Source File: PumlView.ts    From obsidian-plantuml with MIT License 6 votes vote down vote up
constructor(leaf: WorkspaceLeaf, plugin: PlantumlPlugin) {
        super(leaf);
        this.plugin = plugin;

        this.debounced = debounce(this.plugin.getProcessor().png, this.plugin.settings.debounce * 1000, true);

        this.sourceEl = this.contentEl.createDiv({cls: 'plantuml-source-view', attr: {'style': 'display: block'}});
        this.previewEl = this.contentEl.createDiv({cls: 'plantuml-preview-view', attr: {'style': 'display: none'}});

        const vault = (this.app.vault as any);

        if (vault.getConfig("showLineNumber")) {
            this.extensions.push(lineNumbers());
        }
        if(vault.getConfig("lineWrap")) {
            this.extensions.push(EditorView.lineWrapping);
        }

        this.editor = new EditorView({
            state: EditorState.create({
                extensions: this.extensions,
                doc: this.data,
            }),
            parent: this.sourceEl,
            dispatch: syncDispatch(views.length),
        });
        this.dispatchId = views.push(this.editor) - 1;

    }
Example #6
Source File: modeHandler.ts    From obsidian-switcher-plus with GNU General Public License v3.0 6 votes vote down vote up
determineRunMode(
    query: string,
    activeSugg: AnySuggestion,
    activeLeaf: WorkspaceLeaf,
  ): InputInfo {
    const input = query ?? '';
    const info = new InputInfo(input);

    if (input.length === 0) {
      this.reset();
    }

    this.validatePrefixCommands(info, activeSugg, activeLeaf);
    this.validateSourcedCommands(info, activeSugg, activeLeaf);

    return info;
  }
Example #7
Source File: main.tsx    From obsidian-annotator with GNU Affero General Public License v3.0 6 votes vote down vote up
public async openAnnotationTarget(annotationTargetFile: TFile, onNewPane: boolean, annotationId: string) {
        const leaves = this.app.workspace.getLeavesOfType(VIEW_TYPE_PDF_ANNOTATOR);
        let leaf: WorkspaceLeaf = null;

        if (leaves?.length > 0) {
            leaf = leaves[0];
        }
        if (!leaf) {
            leaf = this.app.workspace.activeLeaf;
        }

        if (!leaf) {
            leaf = this.app.workspace.getLeaf();
        }

        if (onNewPane) {
            leaf = this.app.workspace.createLeafBySplit(leaf);
        }

        await leaf.setViewState({
            type: VIEW_TYPE_PDF_ANNOTATOR,
            state: { file: annotationTargetFile.path }
        });

        this.scrollToAnnotation(annotationId);
    }
Example #8
Source File: fixtureUtils.ts    From obsidian-switcher-plus with GNU General Public License v3.0 6 votes vote down vote up
export function makeLeaf(sourceFile?: TFile): MockProxy<WorkspaceLeaf> {
  const mockView = mock<MarkdownView>({
    file: sourceFile ?? new TFile(),
    editor: mock<Editor>(),
  });

  mockView.getViewType.mockReturnValue('markdown');

  return mock<WorkspaceLeaf>({
    view: mockView,
  });
}
Example #9
Source File: customContextMenu.ts    From obsidian-dictionary with GNU Affero General Public License v3.0 6 votes vote down vote up
export default function handleContextMenu(menu: Menu, instance: Editor, plugin: DictionaryPlugin): void {
    if (!plugin.settings.shouldShowCustomContextMenu) {
        return;
    }
    const selection = instance.getSelection();

    if (selection && selection.trim().split(" ").length === 1) {
        if (!plugin.settings.shouldShowSynonymPopover) {
            menu.addItem((item) => {
                item.setTitle(t('Show Synonyms'))
                    .setIcon('synonyms')
                    .onClick(async (_) => {
                        plugin.handlePointerUp();
                    });
            });
        }
        menu.addItem((item) => {
            item.setTitle(t('Look up'))
                .setIcon('quote-glyph')
                .onClick(async (_) => {
                    let leaf: WorkspaceLeaf = plugin.app.workspace.getLeavesOfType(VIEW_TYPE).first();
                    if(!leaf){
                        leaf = plugin.app.workspace.getRightLeaf(false);
                        await leaf.setViewState({
                            type: VIEW_TYPE,
                        });
                    }
                    // eslint-disable-next-line @typescript-eslint/ban-ts-comment
                    //@ts-ignore
                    leaf.view.query(selection.trim());
                    plugin.app.workspace.revealLeaf(leaf);
                });
        });
    }
}
Example #10
Source File: handler.ts    From obsidian-switcher-plus with GNU General Public License v3.0 6 votes vote down vote up
protected getSourceInfoFromSuggestion(suggestion: AnySuggestion): SourceInfo {
    let file: TFile = null;
    let leaf: WorkspaceLeaf = null;

    // Can't use a symbol, workspace, unresolved (non-existent file) suggestions as
    // the target for another symbol command, because they don't point to a file
    const isFileBasedSuggestion =
      suggestion &&
      !isSymbolSuggestion(suggestion) &&
      !isUnresolvedSuggestion(suggestion) &&
      !isWorkspaceSuggestion(suggestion) &&
      !isCommandSuggestion(suggestion);

    if (isFileBasedSuggestion) {
      file = suggestion.file;
    }

    if (isEditorSuggestion(suggestion)) {
      leaf = suggestion.item;
    }

    const isValidSource = !!file;

    return { isValidSource, leaf, file, suggestion };
  }
Example #11
Source File: view.ts    From obsidian-fantasy-calendar with MIT License 6 votes vote down vote up
constructor(
        public plugin: FantasyCalendar,
        public leaf: WorkspaceLeaf,
        public options: { calendar?: Calendar; full?: boolean } = {}
    ) {
        super(leaf);
        this.containerEl.addClass("fantasy-calendar-view");
        this.contentEl.addClass("fantasy-calendar-view-content");
        this.registerEvent(
            this.plugin.app.workspace.on("fantasy-calendars-updated", () => {
                this.plugin.onSettingsLoad(() => this.updateCalendars());
            })
        );
        this.registerEvent(
            this.plugin.app.workspace.on("layout-change", () => {
                if (!this._app) return;
                this._app.$set({
                    fullView: this.full,
                    ...(this.full ? { dayView: false } : {})
                });
            })
        );
        /* window.view = this; */
    }
Example #12
Source File: main.tsx    From obsidian-annotator with GNU Affero General Public License v3.0 6 votes vote down vote up
public async setMarkdownView(leaf: WorkspaceLeaf) {
        await leaf.setViewState(
            {
                type: 'markdown',
                state: leaf.view.getState(),
                popstate: true
            } as ViewState,
            { focus: true }
        );
    }
Example #13
Source File: main.ts    From obsidian-map-view with GNU General Public License v3.0 6 votes vote down vote up
private async openMapWithState(
        state: MapState,
        ctrlKey: boolean,
        forceAutoFit?: boolean
    ) {
        // Find the best candidate for a leaf to open the map view on.
        // If there's an open map view, use that, otherwise use the current leaf.
        // If Ctrl is pressed, override that behavior and always use the current leaf.
        const maps = this.app.workspace.getLeavesOfType(consts.MAP_VIEW_NAME);
        let chosenLeaf: WorkspaceLeaf = null;
        if (maps && !ctrlKey) chosenLeaf = maps[0];
        else chosenLeaf = this.app.workspace.getLeaf();
        if (!chosenLeaf) chosenLeaf = this.app.workspace.activeLeaf;
        await chosenLeaf.setViewState({
            type: consts.MAP_VIEW_NAME,
            state: state,
        });
        if (forceAutoFit) {
            if (chosenLeaf.view instanceof MapView)
                chosenLeaf.view.autoFitMapToMarkers();
        }
    }
Example #14
Source File: ViewLoader.ts    From obsidian-rss with GNU General Public License v3.0 5 votes vote down vote up
constructor(leaf: WorkspaceLeaf, plugin: RssReaderPlugin) {
        super(leaf);
        this.plugin = plugin;
    }
Example #15
Source File: view.ts    From obsidian-checklist-plugin with MIT License 5 votes vote down vote up
constructor(leaf: WorkspaceLeaf, private plugin: TodoPlugin) {
    super(leaf)
  }
Example #16
Source File: main.ts    From obsidian-calendar-plugin with MIT License 5 votes vote down vote up
async onload(): Promise<void> {
    this.register(
      settings.subscribe((value) => {
        this.options = value;
      })
    );

    this.registerView(
      VIEW_TYPE_CALENDAR,
      (leaf: WorkspaceLeaf) => (this.view = new CalendarView(leaf))
    );

    this.addCommand({
      id: "show-calendar-view",
      name: "Open view",
      checkCallback: (checking: boolean) => {
        if (checking) {
          return (
            this.app.workspace.getLeavesOfType(VIEW_TYPE_CALENDAR).length === 0
          );
        }
        this.initLeaf();
      },
    });

    this.addCommand({
      id: "open-weekly-note",
      name: "Open Weekly Note",
      checkCallback: (checking) => {
        if (checking) {
          return !appHasPeriodicNotesPluginLoaded();
        }
        this.view.openOrCreateWeeklyNote(window.moment(), false);
      },
    });

    this.addCommand({
      id: "reveal-active-note",
      name: "Reveal active note",
      callback: () => this.view.revealActiveNote(),
    });

    await this.loadOptions();

    this.addSettingTab(new CalendarSettingsTab(this.app, this));

    if (this.app.workspace.layoutReady) {
      this.initLeaf();
    } else {
      this.registerEvent(
        this.app.workspace.on("layout-ready", this.initLeaf.bind(this))
      );
    }
  }
Example #17
Source File: view.ts    From better-word-count with MIT License 5 votes vote down vote up
constructor(leaf: WorkspaceLeaf) {
    super(leaf);
  }
Example #18
Source File: dictionaryView.ts    From obsidian-dictionary with GNU Affero General Public License v3.0 5 votes vote down vote up
constructor(leaf: WorkspaceLeaf, plugin: DictionaryPlugin) {
        super(leaf);
        this.plugin = plugin;
    }
Example #19
Source File: sidebar.ts    From obsidian-spaced-repetition with MIT License 5 votes vote down vote up
constructor(leaf: WorkspaceLeaf, plugin: SRPlugin) {
        super(leaf);

        this.plugin = plugin;
        this.registerEvent(this.app.workspace.on("file-open", () => this.redraw()));
        this.registerEvent(this.app.vault.on("rename", () => this.redraw()));
    }
Example #20
Source File: main.ts    From obsidian-jupyter with MIT License 5 votes vote down vote up
constructor(leaf: WorkspaceLeaf, interpreter: string) {
		super(leaf);
		// Show a placeholder before we've converted the notebook.
		this.contentEl.innerHTML = 'Converting notebook...';
		this.interpreter = interpreter;
	}
Example #21
Source File: view.ts    From obsidian-initiative-tracker with GNU General Public License v3.0 5 votes vote down vote up
constructor(public leaf: WorkspaceLeaf, public plugin: InitiativeTracker) {
        super(leaf);
        if (this.plugin.data.state?.creatures?.length) {
            this.newEncounterFromState(this.plugin.data.state);
        } else {
            this.newEncounter();
        }
    }
Example #22
Source File: modeHandler.test.ts    From obsidian-switcher-plus with GNU General Public License v3.0 5 votes vote down vote up
function makeLeaf(): MockProxy<WorkspaceLeaf> {
  const view = mock<View>({ file: new TFile() });
  return mock<WorkspaceLeaf>({ view });
}
Example #23
Source File: misc.ts    From alx-folder-note with MIT License 5 votes vote down vote up
getViewOfType = <V extends View = View>(
  type: string,
  app: App,
): V | null => {
  const vc = app.viewRegistry.getViewCreatorByType(type);
  return vc ? (vc(new (WorkspaceLeaf as any)(app)) as V) : null;
}
Example #24
Source File: editorHandler.test.ts    From obsidian-switcher-plus with GNU General Public License v3.0 5 votes vote down vote up
function makeLeafWithRoot(text: string, root: WorkspaceItem): MockProxy<WorkspaceLeaf> {
  const mockLeaf = makeLeaf();

  mockLeaf.getDisplayText.mockImplementation(() => text);
  mockLeaf.getRoot.mockImplementation(() => root);

  return mockLeaf;
}
Example #25
Source File: mapView.ts    From obsidian-map-view with GNU General Public License v3.0 5 votes vote down vote up
/**
     * Construct a new map instance
     * @param leaf The leaf the map should be put in
     * @param settings The plugin settings
     * @param plugin The plugin instance
     */
    constructor(
        leaf: WorkspaceLeaf,
        settings: PluginSettings,
        plugin: MapViewPlugin
    ) {
        super(leaf);
        this.navigation = true;
        this.settings = settings;
        this.plugin = plugin;
        // Create the default state by the configuration
        this.defaultState = this.settings.defaultState;

        // Listen to file changes so we can update markers accordingly
        this.app.vault.on('delete', (file) =>
            this.updateMarkersWithRelationToFile(file.path, null, true)
        );
        this.app.metadataCache.on('changed', (file) =>
            this.updateMarkersWithRelationToFile(file.path, file, false)
        );
        // On rename we don't need to do anything because the markers hold a TFile, and the TFile object doesn't change
        // when the file name changes. Only its internal path field changes accordingly.
        // this.app.vault.on('rename', (file, oldPath) => this.updateMarkersWithRelationToFile(oldPath, file, true));
        this.app.workspace.on('css-change', () => {
            console.log('Map view: map refresh due to CSS change');
            this.refreshMap();
        });
        this.app.workspace.on('file-open', async (file: TFile) => {
            if (this.getState().followActiveNote && file) {
                let viewState = this.leaf?.getViewState();
                if (viewState) {
                    let mapState = viewState.state as MapState;
                    const newQuery = `path:"${file.path}"`;
                    // Change the map state only if the file has actually changed. If the user just went back
                    // and forth and the map is still focused on the same file, don't ruin the user's possible
                    // zoom and pan
                    if (mapState.query != newQuery) {
                        mapState.query = newQuery;
                        await this.setViewState(mapState, true, true);
                    }
                }
            }
        });
    }
Example #26
Source File: modeHandler.ts    From obsidian-switcher-plus with GNU General Public License v3.0 5 votes vote down vote up
private validatePrefixCommands(
    inputInfo: InputInfo,
    activeSugg: AnySuggestion,
    activeLeaf: WorkspaceLeaf,
  ): void {
    const { inputText } = inputInfo;
    const {
      editorListCommand,
      workspaceListCommand,
      headingsListCommand,
      starredListCommand,
      commandListCommand,
    } = this.settings;

    const escEditorCmd = escapeRegExp(editorListCommand);
    const escWorkspaceCmd = escapeRegExp(workspaceListCommand);
    const escHeadingsCmd = escapeRegExp(headingsListCommand);
    const escStarredCmd = escapeRegExp(starredListCommand);
    const escCommandListCmd = escapeRegExp(commandListCommand);

    // account for potential overlapping command strings
    const prefixCmds = [
      `(?<ep>${escEditorCmd})`,
      `(?<wp>${escWorkspaceCmd})`,
      `(?<hp>${escHeadingsCmd})`,
      `(?<sp>${escStarredCmd})`,
      `(?<cp>${escCommandListCmd})`,
    ].sort((a, b) => b.length - a.length);

    // regex that matches editor, workspace, headings prefixes, and extract filter text
    // ^(?:(?<ep>edt )|(?<wp>+)|(?<hp>#)|(?<sp>*))(?<ft>.*)$
    const match = new RegExp(
      `^(?:${prefixCmds[0]}|${prefixCmds[1]}|${prefixCmds[2]}|${prefixCmds[3]}|${prefixCmds[4]})(?<ft>.*)$`,
    ).exec(inputText);

    if (match?.groups) {
      let mode: Mode = null;
      const {
        index,
        groups: { ep, wp, hp, sp, cp, ft },
      } = match;

      if (ep) {
        mode = Mode.EditorList;
      } else if (wp) {
        mode = Mode.WorkspaceList;
      } else if (hp) {
        mode = Mode.HeadingsList;
      } else if (sp) {
        mode = Mode.StarredList;
      } else if (cp) {
        mode = Mode.CommandList;
      }

      if (mode) {
        this.getHandler(mode).validateCommand(
          inputInfo,
          index,
          ft,
          activeSugg,
          activeLeaf,
        );
      }
    }
  }
Example #27
Source File: annotatorView.tsx    From obsidian-annotator with GNU Affero General Public License v3.0 5 votes vote down vote up
constructor(leaf: WorkspaceLeaf, plugin: AnnotatorPlugin) {
        super(leaf);
        this.useDarkMode = plugin.settings.deafultDarkMode;
        this.plugin = plugin;
        this.plugin.views.add(this);
    }
Example #28
Source File: main.ts    From obsidian-rss with GNU General Public License v3.0 4 votes vote down vote up
async onload(): Promise<void> {
        console.log('loading plugin rss reader');

        //update settings object whenever store contents change.
        this.register(
            settingsStore.subscribe((value: RssReaderSettings) => {
                this.settings = value;
            })
        );

        await this.loadSettings();

        this.addCommand({
            id: "rss-open",
            name: t("open"),
            checkCallback: (checking: boolean) => {
                if (checking) {
                    return (this.app.workspace.getLeavesOfType(VIEW_ID).length === 0);
                }
                this.initLeaf();
            }
        });


        this.addCommand({
            id: 'rss-refresh',
            name: t("refresh_feeds"),
            callback: async () => {
                await this.updateFeeds();
            }
        });

        this.addCommand({
            id: 'rss-cleanup',
            name: t("cleanup"),
            callback: async () => {
                new CleanupModal(this).open();
            }
        });

        this.addCommand({
            id: 'rss-open-feed',
            name: "Open Feed from URL",
            callback: async () => {
                const input = new TextInputPrompt(this.app, "URL", "URL", "", "", t("open"));
                await input.openAndGetValue(async (text) => {
                    const items = await getFeedItems({name: "", folder: "", url: text.getValue()});
                    if (!items || items.items.length === 0) {
                        input.setValidationError(text, t("invalid_feed"));
                        return;
                    }

                    input.close();
                    new ArticleSuggestModal(this, items.items).open();
                });
            }
        });

        this.registerView(VIEW_ID, (leaf: WorkspaceLeaf) => new ViewLoader(leaf, this));

        this.addSettingTab(new RSSReaderSettingsTab(this.app, this));

        let interval: number;
        if (this.settings.updateTime !== 0) {
            interval = window.setInterval(async () => {
                await this.updateFeeds();
            }, this.settings.updateTime * 60 * 1000);
            this.registerInterval(interval);
        }

        if (this.settings.autoSync) {
            this.registerInterval(window.setInterval(async () => {
                await this.loadSettings();
            }, 1000 * 60));
        }

        //reset update timer on settings change.
        settingsStore.subscribe((settings: RssReaderSettings) => {
            if (interval !== undefined)
                clearInterval(interval);
            if (settings.updateTime != 0) {
                interval = window.setInterval(async () => {
                    await this.updateFeeds();
                }, settings.updateTime * 60 * 1000);
                this.registerInterval(interval);
            }

            this.settings = settings;
            this.saveSettings();
        });

        this.app.workspace.onLayoutReady(async () => {
            await this.migrateData();
            await this.initLeaf();
            await this.updateFeeds();


            feedsStore.subscribe((feeds: RssFeedContent[]) => {
                //keep sorted store sorted when the items change.
                const sorted = groupBy(feeds, "folder");
                sortedFeedsStore.update(() => sorted);

                let items: RssFeedItem[] = [];
                for (const feed in Object.keys(feeds)) {
                    //@ts-ignore
                    const feedItems = feeds[feed].items;
                    items = items.concat(feedItems);
                }

                //collect wallabag.xml tags for auto completion
                const tags: string[] = [];
                for (const item of items) {
                    if (item !== undefined)
                        tags.push(...item.tags);
                }

                //@ts-ignore
                const fileTags = this.app.metadataCache.getTags();
                for (const tag of Object.keys(fileTags)) {
                    tags.push(tag.replace('#', ''));
                }
                tagsStore.update(() => new Set<string>(tags.filter(tag => tag.length > 0)));

                //collect wallabag.xml folders for auto-completion
                const folders: string[] = [];
                for (const item of items) {
                    if (item !== undefined)
                        folders.push(item.folder);
                }
                folderStore.update(() => new Set<string>(folders.filter(folder => folder !== undefined && folder.length > 0)));

                this.filterItems(items);
            });
        });
    }
Example #29
Source File: main.ts    From obsidian-dictionary with GNU Affero General Public License v3.0 4 votes vote down vote up
async onload(): Promise<void> {
        console.log('loading dictionary');

        await Promise.all([this.loadSettings(), this.loadCache()]);

        addIcons();

        this.addSettingTab(new SettingsTab(this.app, this));

        this.manager = new APIManager(this);

        this.registerView(VIEW_TYPE, (leaf) => {
            return new DictionaryView(leaf, this);
        });

        this.addCommand({
            id: 'dictionary-open-view',
            name: t('Open Dictionary View'),
            callback: async () => {
                if (this.app.workspace.getLeavesOfType(VIEW_TYPE).length == 0) {
                    await this.app.workspace.getRightLeaf(false).setViewState({
                        type: VIEW_TYPE,
                    });
                }
                this.app.workspace.revealLeaf(this.app.workspace.getLeavesOfType(VIEW_TYPE).first());
                dispatchEvent(new Event("dictionary-focus-on-search"));
            },
        });

        this.addCommand({
            id: 'dictionary-open-language-switcher',
            name: t('Open Language Switcher'),
            callback: () => {
                new LanguageChooser(this.app, this).open();
            },
        });

        this.registerDomEvent(document.body, "pointerup", () => {
            if (!this.settings.shouldShowSynonymPopover) {
                return;
            }
            this.handlePointerUp();
        });
        this.registerDomEvent(window, "keydown", () => {
            // Destroy the popover if it's open
            if (this.synonymPopover) {
                this.synonymPopover.destroy();
                this.synonymPopover = null;
            }
        });

        this.registerDomEvent(document.body, "contextmenu", (event) => {
            //@ts-ignore
            if (this.settings.shouldShowCustomContextMenu && event.path.find((el: HTMLElement) => {
                try {
                    return el.hasClass("markdown-preview-view");
                } catch (error) {
                    return false;
                }
            })) {
                const selection = window.getSelection().toString();
                if (selection && this.app.workspace.activeLeaf?.getViewState()?.state.mode === "preview") {
                    event.preventDefault();

                    const fileMenu = new Menu(this.app);

                    fileMenu.addItem((item) => {
                        item.setTitle(t('Copy'))
                            .setIcon('copy')
                            .onClick((_) => {
                                copy(selection);
                            });
                    });

                    if (selection.trim().split(" ").length === 1) {
                        fileMenu.addItem((item) => {
                            item.setTitle(t('Look up'))
                                .setIcon('quote-glyph')
                                .onClick(async (_) => {
                                    let leaf: WorkspaceLeaf = this.app.workspace.getLeavesOfType(VIEW_TYPE).first();
                                    if (!leaf) {
                                        leaf = this.app.workspace.getRightLeaf(false);
                                        await leaf.setViewState({
                                            type: VIEW_TYPE,
                                        });
                                    }
                                    // eslint-disable-next-line @typescript-eslint/ban-ts-comment
                                    //@ts-ignore
                                    leaf.view.query(selection.trim());
                                    this.app.workspace.revealLeaf(leaf);
                                });
                        });
                    }

                    fileMenu.showAtPosition({ x: event.clientX, y: event.clientY });
                }
            }
        });

        this.localDictionary = new LocalDictionaryBuilder(this);
        
        this.registerEvent(this.app.workspace.on('editor-menu', this.handleContextMenuHelper));

        this.registerEvent(this.app.workspace.on('file-open', (file) => {
            if (file && this.settings.getLangFromFile) {
                let lang = this.app.metadataCache.getFileCache(file).frontmatter?.lang ?? null;
                if (!lang) {
                    lang = this.app.metadataCache.getFileCache(file).frontmatter?.language ?? null;
                }
                if (lang && Object.values(RFC).contains(lang)) {
                    this.settings.defaultLanguage = Object.keys(RFC)[Object.values(RFC).indexOf(lang)] as keyof APISettings;
                } else {
                    this.settings.defaultLanguage = this.settings.normalLang;
                }
                this.saveSettings();
            }
        }));
    }