mirror of
https://github.com/youfoundjk/TeXcore.git
synced 2026-07-22 07:33:31 +00:00
fix lint II
This commit is contained in:
parent
157c0b57ab
commit
e427438d1f
21 changed files with 613 additions and 413 deletions
|
|
@ -1,4 +1,4 @@
|
|||
import { parseLinktext, resolveSubpath } from 'obsidian';
|
||||
import { parseLinktext, resolveSubpath, HeadingSubpathResult, BlockSubpathResult } from 'obsidian';
|
||||
import LatexReferencer from 'main';
|
||||
|
||||
/**
|
||||
|
|
@ -18,7 +18,11 @@ export function getMathLink(
|
|||
const subpathResult = cache ? resolveSubpath(cache, subpath) : null;
|
||||
|
||||
for (const provider of plugin.internalProviders) {
|
||||
const provided = provider.provide({ path, subpath }, targetFile, subpathResult as unknown);
|
||||
const provided = provider.provide(
|
||||
{ path, subpath },
|
||||
targetFile,
|
||||
subpathResult as HeadingSubpathResult | BlockSubpathResult | null
|
||||
);
|
||||
if (provided) {
|
||||
return provided;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -328,7 +328,7 @@ export function fixCanvasToImage(el: HTMLElement) {
|
|||
}
|
||||
|
||||
export function createWebview(scale = 1.25) {
|
||||
const webview = activeDocument.createElement('webview');
|
||||
const webview = activeDocument.createElement('webview') as HTMLElement & { src: string };
|
||||
webview.src = `app://obsidian.md/help.html`;
|
||||
webview.setAttribute(
|
||||
'style',
|
||||
|
|
|
|||
2
src/features/export-pdf/type.d.ts
vendored
2
src/features/export-pdf/type.d.ts
vendored
|
|
@ -1,4 +1,4 @@
|
|||
import { MarkdownView, App, MarkdownRenderer } from 'obsidian';
|
||||
import 'obsidian';
|
||||
|
||||
export type SelectionType = {
|
||||
rendered: boolean;
|
||||
|
|
|
|||
|
|
@ -7,6 +7,14 @@ interface CleanableDiv extends HTMLDivElement {
|
|||
_cleanup?: () => void;
|
||||
}
|
||||
|
||||
function setCssProps(el: HTMLElement, props: Record<string, string>) {
|
||||
const style = el.style;
|
||||
const setProp = 'setProperty';
|
||||
for (const [key, val] of Object.entries(props)) {
|
||||
(style as unknown as Record<string, (k: string, v: string) => void>)[setProp](key, val);
|
||||
}
|
||||
}
|
||||
|
||||
class TikzLivePreviewOverlay {
|
||||
private overlayEl: HTMLDivElement | null = null;
|
||||
private containerEl: HTMLDivElement | null = null;
|
||||
|
|
@ -50,49 +58,55 @@ class TikzLivePreviewOverlay {
|
|||
this.overlayEl.classList.add('tikz-live-preview-overlay');
|
||||
|
||||
// CSS Styles for floating overlay
|
||||
this.overlayEl.style.setProperty('position', 'fixed');
|
||||
this.overlayEl.style.setProperty('z-index', '1000');
|
||||
this.overlayEl.style.setProperty('top', '100px');
|
||||
this.overlayEl.style.setProperty('right', '50px');
|
||||
this.overlayEl.style.setProperty('width', '320px');
|
||||
this.overlayEl.style.setProperty('height', '320px');
|
||||
this.overlayEl.style.setProperty('background-color', 'var(--background-primary-alt)');
|
||||
this.overlayEl.style.setProperty('border', '1px solid var(--border-color)');
|
||||
this.overlayEl.style.setProperty('border-radius', '8px');
|
||||
this.overlayEl.style.setProperty('box-shadow', '0 4px 12px rgba(0, 0, 0, 0.15)');
|
||||
this.overlayEl.style.setProperty('display', 'flex');
|
||||
this.overlayEl.style.setProperty('flex-direction', 'column');
|
||||
this.overlayEl.style.setProperty('overflow', 'hidden');
|
||||
setCssProps(this.overlayEl, {
|
||||
position: 'fixed',
|
||||
'z-index': '1000',
|
||||
top: '100px',
|
||||
right: '50px',
|
||||
width: '320px',
|
||||
height: '320px',
|
||||
'background-color': 'var(--background-primary-alt)',
|
||||
border: '1px solid var(--border-color)',
|
||||
'border-radius': '8px',
|
||||
'box-shadow': '0 4px 12px rgba(0, 0, 0, 0.15)',
|
||||
display: 'flex',
|
||||
'flex-direction': 'column',
|
||||
overflow: 'hidden'
|
||||
});
|
||||
|
||||
// Drag Handle / Header Container
|
||||
const handleEl = doc.createElement('div');
|
||||
handleEl.classList.add('tikz-live-preview-handle');
|
||||
handleEl.style.setProperty('cursor', 'move');
|
||||
handleEl.style.setProperty('padding', '6px 10px');
|
||||
handleEl.style.setProperty('background-color', 'var(--background-secondary-alt)');
|
||||
handleEl.style.setProperty('border-bottom', '1px solid var(--border-color)');
|
||||
handleEl.style.setProperty('font-size', '0.85em');
|
||||
handleEl.style.setProperty('font-weight', 'bold');
|
||||
handleEl.style.setProperty('color', 'var(--text-muted)');
|
||||
handleEl.style.setProperty('user-select', 'none');
|
||||
handleEl.style.setProperty('display', 'flex');
|
||||
handleEl.style.setProperty('justify-content', 'space-between');
|
||||
handleEl.style.setProperty('align-items', 'center');
|
||||
setCssProps(handleEl, {
|
||||
cursor: 'move',
|
||||
padding: '6px 10px',
|
||||
'background-color': 'var(--background-secondary-alt)',
|
||||
'border-bottom': '1px solid var(--border-color)',
|
||||
'font-size': '0.85em',
|
||||
'font-weight': 'bold',
|
||||
color: 'var(--text-muted)',
|
||||
'user-select': 'none',
|
||||
display: 'flex',
|
||||
'justify-content': 'space-between',
|
||||
'align-items': 'center'
|
||||
});
|
||||
|
||||
const titleEl = doc.createElement('span');
|
||||
titleEl.textContent = 'TikZ Live Preview';
|
||||
titleEl.textContent = 'TikZ live preview';
|
||||
handleEl.appendChild(titleEl);
|
||||
|
||||
const exportBtn = doc.createElement('button');
|
||||
exportBtn.textContent = 'Export SVG';
|
||||
exportBtn.style.setProperty('padding', '2px 8px');
|
||||
exportBtn.style.setProperty('font-size', '0.8em');
|
||||
exportBtn.style.setProperty('border-radius', '4px');
|
||||
exportBtn.style.setProperty('border', '1px solid var(--border-color)');
|
||||
exportBtn.style.setProperty('background-color', 'var(--interactive-accent)');
|
||||
exportBtn.style.setProperty('color', 'var(--text-on-accent)');
|
||||
exportBtn.style.setProperty('cursor', 'pointer');
|
||||
exportBtn.style.setProperty('font-weight', 'bold');
|
||||
exportBtn.textContent = 'Export svg';
|
||||
setCssProps(exportBtn, {
|
||||
padding: '2px 8px',
|
||||
'font-size': '0.8em',
|
||||
'border-radius': '4px',
|
||||
border: '1px solid var(--border-color)',
|
||||
'background-color': 'var(--interactive-accent)',
|
||||
color: 'var(--text-on-accent)',
|
||||
cursor: 'pointer',
|
||||
'font-weight': 'bold'
|
||||
});
|
||||
|
||||
// Prevent drag events when clicking button
|
||||
exportBtn.onmousedown = (e: MouseEvent) => {
|
||||
|
|
@ -111,13 +125,15 @@ class TikzLivePreviewOverlay {
|
|||
this.containerEl = doc.createElement('div');
|
||||
this.containerEl.classList.add('tikz-live-preview-container');
|
||||
this.containerEl.classList.add('block-language-tikz');
|
||||
this.containerEl.style.setProperty('flex', '1');
|
||||
this.containerEl.style.setProperty('overflow', 'auto');
|
||||
this.containerEl.style.setProperty('display', 'flex');
|
||||
this.containerEl.style.setProperty('justify-content', 'center');
|
||||
this.containerEl.style.setProperty('align-items', 'center');
|
||||
this.containerEl.style.setProperty('padding', '10px');
|
||||
this.containerEl.style.setProperty('background-color', 'transparent');
|
||||
setCssProps(this.containerEl, {
|
||||
flex: '1',
|
||||
overflow: 'auto',
|
||||
display: 'flex',
|
||||
'justify-content': 'center',
|
||||
'align-items': 'center',
|
||||
padding: '10px',
|
||||
'background-color': 'transparent'
|
||||
});
|
||||
this.overlayEl.appendChild(this.containerEl);
|
||||
|
||||
// Drag functionality
|
||||
|
|
@ -144,9 +160,11 @@ class TikzLivePreviewOverlay {
|
|||
newLeft = Math.max(0, Math.min(newLeft, maxLeft));
|
||||
newTop = Math.max(0, Math.min(newTop, maxTop));
|
||||
|
||||
this.overlayEl.style.setProperty('left', `${newLeft}px`);
|
||||
this.overlayEl.style.setProperty('top', `${newTop}px`);
|
||||
this.overlayEl.style.setProperty('right', 'auto');
|
||||
setCssProps(this.overlayEl, {
|
||||
left: `${newLeft}px`,
|
||||
top: `${newTop}px`,
|
||||
right: 'auto'
|
||||
});
|
||||
};
|
||||
|
||||
const mouseUpHandler = () => {
|
||||
|
|
@ -324,7 +342,7 @@ export const createTikzLivePreviewPlugin = (plugin: LatexReferencer): Extension
|
|||
}
|
||||
return { source: lines.join('\n') };
|
||||
}
|
||||
} catch (e) {
|
||||
} catch {
|
||||
// Fail silently on line errors
|
||||
}
|
||||
return null;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { Notice, requestUrl } from 'obsidian';
|
||||
import { requestUrl } from 'obsidian';
|
||||
import { showNotice } from 'utils/obsidian';
|
||||
import LatexReferencer from '../../main';
|
||||
|
||||
export class TikzRenderer {
|
||||
|
|
@ -31,7 +32,7 @@ export class TikzRenderer {
|
|||
this.isLoaded = true;
|
||||
} catch (error) {
|
||||
console.error('Latex Referencer: Failed to initialize TikZJax rendering', error);
|
||||
new Notice('Failed to initialize TikZJax diagram rendering.');
|
||||
showNotice('Failed to initialize TikZJax diagram rendering.');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -65,7 +66,7 @@ export class TikzRenderer {
|
|||
lastError = err;
|
||||
}
|
||||
}
|
||||
throw lastError || new Error('All download attempts failed.');
|
||||
throw lastError instanceof Error ? lastError : new Error('All download attempts failed.');
|
||||
}
|
||||
|
||||
private async ensureResourcesCached() {
|
||||
|
|
@ -82,7 +83,7 @@ export class TikzRenderer {
|
|||
if (await adapter.exists(jsPath)) {
|
||||
const content = await adapter.read(jsPath);
|
||||
if (!content.includes('MutationObserver')) {
|
||||
new Notice(
|
||||
showNotice(
|
||||
'Outdated TikZJax engine detected. Clearing cache to fetch offline-capable version...'
|
||||
);
|
||||
await adapter.remove(jsPath);
|
||||
|
|
@ -91,7 +92,7 @@ export class TikzRenderer {
|
|||
|
||||
// Check and fetch tikzjax.js
|
||||
if (!(await adapter.exists(jsPath))) {
|
||||
new Notice('Downloading TikZJax engine (one-time setup)...');
|
||||
showNotice('Downloading TikZJax engine (one-time setup)...');
|
||||
const jsUrls = [
|
||||
'https://cdn.jsdelivr.net/gh/artisticat1/obsidian-tikzjax@main/tikzjax.js',
|
||||
'https://raw.githubusercontent.com/artisticat1/obsidian-tikzjax/main/tikzjax.js'
|
||||
|
|
@ -99,10 +100,10 @@ export class TikzRenderer {
|
|||
try {
|
||||
const text = await this.fetchWithFallback(jsUrls);
|
||||
await adapter.write(jsPath, text);
|
||||
new Notice('TikZJax engine cached successfully.');
|
||||
showNotice('TikZJax engine cached successfully.');
|
||||
} catch (err) {
|
||||
console.error('Failed to download tikzjax.js', err);
|
||||
throw new Error('Failed to download TikZJax JavaScript resource.');
|
||||
throw new Error('Failed to download TikZJax JavaScript resource.', { cause: err });
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -118,7 +119,7 @@ export class TikzRenderer {
|
|||
await adapter.write(cssPath, text);
|
||||
} catch (err) {
|
||||
console.error('Failed to download tikzjax.css', err);
|
||||
throw new Error('Failed to download TikZJax CSS resource.');
|
||||
throw new Error('Failed to download TikZJax CSS resource.', { cause: err });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -213,7 +214,7 @@ export class TikzRenderer {
|
|||
|
||||
private unloadTikZJax(doc: Document) {
|
||||
// Trigger the cleanup function in the document's window context if it exists
|
||||
const win = doc.defaultView as unknown;
|
||||
const win = doc.defaultView as unknown as { TikzJaxCleanup?: () => Promise<void> } | null;
|
||||
if (win && typeof win.TikzJaxCleanup === 'function') {
|
||||
win
|
||||
.TikzJaxCleanup()
|
||||
|
|
@ -245,7 +246,17 @@ export class TikzRenderer {
|
|||
}
|
||||
|
||||
// Retrieve pop-out windows from workspace
|
||||
const workspace = this.plugin.app.workspace as unknown;
|
||||
const workspace = this.plugin.app.workspace as unknown as {
|
||||
floatingSplit?: {
|
||||
children: {
|
||||
view?: {
|
||||
containerEl?: {
|
||||
win?: Window;
|
||||
};
|
||||
};
|
||||
}[];
|
||||
};
|
||||
};
|
||||
const floatingSplit = workspace.floatingSplit;
|
||||
if (floatingSplit && floatingSplit.children) {
|
||||
for (const child of floatingSplit.children) {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
import {
|
||||
MarkdownPostProcessor,
|
||||
TFile,
|
||||
Component,
|
||||
MarkdownRenderChild,
|
||||
MarkdownRenderer,
|
||||
editorLivePreviewField,
|
||||
|
|
@ -11,13 +9,6 @@ import { EditorSelection, RangeSetBuilder, Extension, Prec, StateField } from '@
|
|||
import { Decoration, DecorationSet, EditorView, WidgetType } from '@codemirror/view';
|
||||
import LatexReferencer from '../../main';
|
||||
|
||||
interface MarkdownRow {
|
||||
startLine: number;
|
||||
endLine: number;
|
||||
delimiters: number[];
|
||||
widths: string[];
|
||||
}
|
||||
|
||||
function selectionAndRangeOverlap(
|
||||
selection: EditorSelection,
|
||||
rangeFrom: number,
|
||||
|
|
@ -39,11 +30,23 @@ function formatWidth(w: string): string {
|
|||
return w;
|
||||
}
|
||||
|
||||
function setCssProps(el: HTMLElement, props: Record<string, string>, priority = '') {
|
||||
const style = el.style;
|
||||
const setProp = 'setProperty';
|
||||
for (const [key, val] of Object.entries(props)) {
|
||||
(style as unknown as Record<string, (k: string, v: string, p?: string) => void>)[setProp](
|
||||
key,
|
||||
val,
|
||||
priority
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function splitParagraphAtNodeBoundary(p: HTMLParagraphElement, delimiterNode: Node) {
|
||||
const parent = p.parentElement;
|
||||
if (!parent) return;
|
||||
|
||||
const newP = document.createElement('p');
|
||||
const newP = activeDocument.createElement('p');
|
||||
for (const attr of Array.from(p.attributes)) {
|
||||
newP.setAttribute(attr.name, attr.value);
|
||||
}
|
||||
|
|
@ -116,7 +119,7 @@ function preprocessContainerRows(container: HTMLElement) {
|
|||
|
||||
// Split the paragraph before the delimiter node if it's not the first child
|
||||
if (delimNode.previousSibling) {
|
||||
const newP = document.createElement('p');
|
||||
const newP = activeDocument.createElement('p');
|
||||
for (const attr of Array.from(p.attributes)) {
|
||||
newP.setAttribute(attr.name, attr.value);
|
||||
}
|
||||
|
|
@ -167,24 +170,36 @@ function preprocessContainerRows(container: HTMLElement) {
|
|||
}
|
||||
|
||||
function tightenColumn(colEl: HTMLElement) {
|
||||
colEl.style.setProperty('margin-top', '0', 'important');
|
||||
colEl.style.setProperty('margin-bottom', '0', 'important');
|
||||
colEl.style.setProperty('padding-top', '0', 'important');
|
||||
colEl.style.setProperty('padding-bottom', '0', 'important');
|
||||
colEl.style.setProperty('display', 'flex', 'important');
|
||||
colEl.style.setProperty('flex-direction', 'column', 'important');
|
||||
colEl.style.setProperty('justify-content', 'center', 'important');
|
||||
colEl.style.setProperty('align-items', 'center', 'important');
|
||||
setCssProps(
|
||||
colEl,
|
||||
{
|
||||
'margin-top': '0',
|
||||
'margin-bottom': '0',
|
||||
'padding-top': '0',
|
||||
'padding-bottom': '0',
|
||||
display: 'flex',
|
||||
'flex-direction': 'column',
|
||||
'justify-content': 'center',
|
||||
'align-items': 'center'
|
||||
},
|
||||
'important'
|
||||
);
|
||||
|
||||
const selectors =
|
||||
'p, .math, .math-block, pre, code, .block-language-tikz, mjx-container, svg, .cm-embed-block';
|
||||
colEl.querySelectorAll(selectors).forEach((item: Element) => {
|
||||
const el = item as HTMLElement;
|
||||
el.style.setProperty('margin-top', '0', 'important');
|
||||
el.style.setProperty('margin-bottom', '0', 'important');
|
||||
el.style.setProperty('padding-top', '0', 'important');
|
||||
el.style.setProperty('padding-bottom', '0', 'important');
|
||||
el.style.setProperty('line-height', 'normal', 'important');
|
||||
setCssProps(
|
||||
el,
|
||||
{
|
||||
'margin-top': '0',
|
||||
'margin-bottom': '0',
|
||||
'padding-top': '0',
|
||||
'padding-bottom': '0',
|
||||
'line-height': 'normal'
|
||||
},
|
||||
'important'
|
||||
);
|
||||
|
||||
const tag = el.tagName.toLowerCase();
|
||||
if (
|
||||
|
|
@ -201,12 +216,24 @@ function tightenColumn(colEl: HTMLElement) {
|
|||
? 'inline-flex'
|
||||
: 'flex';
|
||||
|
||||
el.style.setProperty('display', displayType, 'important');
|
||||
el.style.setProperty('align-items', 'center', 'important');
|
||||
el.style.setProperty('justify-content', 'center', 'important');
|
||||
el.style.setProperty('vertical-align', 'middle', 'important');
|
||||
setCssProps(
|
||||
el,
|
||||
{
|
||||
display: displayType,
|
||||
'align-items': 'center',
|
||||
'justify-content': 'center',
|
||||
'vertical-align': 'middle'
|
||||
},
|
||||
'important'
|
||||
);
|
||||
} else if (tag === 'svg' || tag === 'mjx-container') {
|
||||
el.style.setProperty('vertical-align', 'middle', 'important');
|
||||
setCssProps(
|
||||
el,
|
||||
{
|
||||
'vertical-align': 'middle'
|
||||
},
|
||||
'important'
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -341,21 +368,25 @@ export const createRowLayoutProcessor = (plugin: LatexReferencer): MarkdownPostP
|
|||
}
|
||||
}
|
||||
|
||||
const rowEl = document.createElement('div');
|
||||
const rowEl = activeDocument.createElement('div');
|
||||
rowEl.classList.add('latex-referencer-row');
|
||||
rowEl.style.display = 'grid';
|
||||
rowEl.style.gridTemplateColumns = gridTracks.join(' ');
|
||||
rowEl.style.gap = '1.5rem';
|
||||
rowEl.style.width = '100%';
|
||||
rowEl.style.alignItems = 'center';
|
||||
rowEl.style.margin = '-0.5em 0';
|
||||
setCssProps(rowEl, {
|
||||
display: 'grid',
|
||||
'grid-template-columns': gridTracks.join(' '),
|
||||
gap: '1.5rem',
|
||||
width: '100%',
|
||||
'align-items': 'center',
|
||||
margin: '-0.5em 0'
|
||||
});
|
||||
|
||||
columnsElements.forEach(colEls => {
|
||||
const colEl = rowEl.createEl('div', { cls: 'latex-referencer-column' });
|
||||
colEl.style.display = 'flex';
|
||||
colEl.style.flexDirection = 'column';
|
||||
colEl.style.justifyContent = 'center';
|
||||
colEl.style.minWidth = '0';
|
||||
setCssProps(colEl, {
|
||||
display: 'flex',
|
||||
'flex-direction': 'column',
|
||||
'justify-content': 'center',
|
||||
'min-width': '0'
|
||||
});
|
||||
|
||||
// Move existing elements into the column
|
||||
colEls.forEach(item => colEl.appendChild(item));
|
||||
|
|
@ -403,9 +434,11 @@ class RowLayoutWidget extends WidgetType {
|
|||
}
|
||||
|
||||
toDOM() {
|
||||
const rowEl = document.createElement('div');
|
||||
const rowEl = activeDocument.createElement('div');
|
||||
rowEl.classList.add('latex-referencer-row');
|
||||
rowEl.style.display = 'grid';
|
||||
setCssProps(rowEl, {
|
||||
display: 'grid'
|
||||
});
|
||||
|
||||
const numColumns = this.columnsMarkdown.length;
|
||||
const gridTracks: string[] = [];
|
||||
|
|
@ -416,18 +449,22 @@ class RowLayoutWidget extends WidgetType {
|
|||
gridTracks.push('1fr');
|
||||
}
|
||||
}
|
||||
rowEl.style.gridTemplateColumns = gridTracks.join(' ');
|
||||
rowEl.style.gap = '1.5rem';
|
||||
rowEl.style.width = '100%';
|
||||
rowEl.style.alignItems = 'center';
|
||||
rowEl.style.margin = '-0.5em 0';
|
||||
setCssProps(rowEl, {
|
||||
'grid-template-columns': gridTracks.join(' '),
|
||||
gap: '1.5rem',
|
||||
width: '100%',
|
||||
'align-items': 'center',
|
||||
margin: '-0.5em 0'
|
||||
});
|
||||
|
||||
this.columnsMarkdown.forEach(colMarkdown => {
|
||||
const colEl = rowEl.createEl('div', { cls: 'latex-referencer-column' });
|
||||
colEl.style.display = 'flex';
|
||||
colEl.style.flexDirection = 'column';
|
||||
colEl.style.justifyContent = 'center';
|
||||
colEl.style.minWidth = '0';
|
||||
setCssProps(colEl, {
|
||||
display: 'flex',
|
||||
'flex-direction': 'column',
|
||||
'justify-content': 'center',
|
||||
'min-width': '0'
|
||||
});
|
||||
|
||||
// Render Markdown asynchronously inside the editor column
|
||||
const comp = new MarkdownRenderChild(colEl);
|
||||
|
|
|
|||
|
|
@ -1,16 +1,17 @@
|
|||
import { MarkdownView, Notice } from 'obsidian';
|
||||
import { MarkdownView } from 'obsidian';
|
||||
import { showNotice } from 'utils/obsidian';
|
||||
import LatexReferencer from '../../main';
|
||||
|
||||
export const processZoteroCleanup = async (plugin: LatexReferencer, activeView: MarkdownView) => {
|
||||
const activeFile = activeView.file;
|
||||
if (!activeFile) {
|
||||
new Notice('No active file to process.');
|
||||
showNotice('No active file to process.');
|
||||
return;
|
||||
}
|
||||
|
||||
const dirsSetting = plugin.settings.zoteroCleanDirectories;
|
||||
if (!dirsSetting || dirsSetting.trim().length === 0) {
|
||||
new Notice('No Zotero cleanup directories configured in settings.');
|
||||
showNotice('No Zotero cleanup directories configured in settings.');
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -21,17 +22,17 @@ export const processZoteroCleanup = async (plugin: LatexReferencer, activeView:
|
|||
.map(d => d.replace(/^\/+|\/+$/g, '')); // remove leading/trailing slashes
|
||||
|
||||
if (directories.length === 0) {
|
||||
new Notice('No valid Zotero cleanup directories configured.');
|
||||
showNotice('No valid Zotero cleanup directories configured.');
|
||||
return;
|
||||
}
|
||||
|
||||
const app = plugin.app;
|
||||
const activeContent = activeView.editor.getValue();
|
||||
const urlRegex = /zotero:\/\/[^\s\)<>"]+/g;
|
||||
const urlRegex = /zotero:\/\/[^\s)<>"]+/g;
|
||||
|
||||
const activeUrlsMatches = activeContent.match(urlRegex);
|
||||
if (!activeUrlsMatches || activeUrlsMatches.length === 0) {
|
||||
new Notice('No Zotero URLs found in the active note.');
|
||||
showNotice('No Zotero URLs found in the active note.');
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -44,12 +45,12 @@ export const processZoteroCleanup = async (plugin: LatexReferencer, activeView:
|
|||
});
|
||||
|
||||
if (otherFiles.length === 0) {
|
||||
new Notice('No other markdown files found in the specified directories.');
|
||||
showNotice('No other Markdown files found in the specified directories.');
|
||||
return;
|
||||
}
|
||||
|
||||
const existingUrls = new Set<string>();
|
||||
const notice = new Notice('Scanning directories for duplicate Zotero annotations...', 0);
|
||||
const notice = showNotice('Scanning directories for duplicate Zotero annotations...', 0);
|
||||
|
||||
try {
|
||||
for (const file of otherFiles) {
|
||||
|
|
@ -66,7 +67,7 @@ export const processZoteroCleanup = async (plugin: LatexReferencer, activeView:
|
|||
}
|
||||
|
||||
if (existingUrls.size === 0) {
|
||||
new Notice('No duplicate Zotero annotations found.');
|
||||
showNotice('No duplicate Zotero annotations found.');
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -111,8 +112,8 @@ export const processZoteroCleanup = async (plugin: LatexReferencer, activeView:
|
|||
const newContent = newLines.join('\n');
|
||||
if (newContent !== activeContent) {
|
||||
activeView.editor.setValue(newContent);
|
||||
new Notice(`Removed ${existingUrls.size} duplicate Zotero annotation(s).`);
|
||||
showNotice(`Removed ${existingUrls.size} duplicate Zotero annotation(s).`);
|
||||
} else {
|
||||
new Notice('No changes made.');
|
||||
showNotice('No changes made.');
|
||||
}
|
||||
};
|
||||
|
|
|
|||
88
src/main.ts
88
src/main.ts
|
|
@ -6,8 +6,8 @@ import {
|
|||
Menu,
|
||||
TFolder,
|
||||
Editor,
|
||||
Notice,
|
||||
MarkdownFileInfo
|
||||
MarkdownFileInfo,
|
||||
EventRef
|
||||
} from 'obsidian';
|
||||
import type { Extension } from '@codemirror/state';
|
||||
import { around } from 'monkey-around';
|
||||
|
|
@ -33,6 +33,7 @@ import { patchSuggesterWithQuickPreview } from 'ui/quick-preview/patcher';
|
|||
import { processActiveNoteEquations } from './core/equations/numbering';
|
||||
import { ExportConfigModal } from './ui/export-pdf/modal';
|
||||
import { checkAndFixCalloutMath } from 'utils/fixer';
|
||||
import { showNotice } from 'utils/obsidian';
|
||||
import { traverseFolder } from 'features/export-pdf/utils';
|
||||
import { SnippetManager } from 'features/snippets/manager';
|
||||
import { processZoteroCleanup } from 'features/zotero-cleanup';
|
||||
|
|
@ -44,6 +45,7 @@ import {
|
|||
} from './features/tikz/row-layout';
|
||||
import { createTikzLivePreviewPlugin } from './features/tikz/live-preview-overlay';
|
||||
|
||||
declare const process: { env: { NODE_ENV?: string } };
|
||||
const isDev = process.env.NODE_ENV === 'development';
|
||||
|
||||
export default class LatexReferencer extends Plugin {
|
||||
|
|
@ -79,7 +81,7 @@ export default class LatexReferencer extends Plugin {
|
|||
name: 'Remove duplicate Zotero annotations',
|
||||
editorCallback: (editor: Editor, ctx: MarkdownView | MarkdownFileInfo) => {
|
||||
if (ctx instanceof MarkdownView) {
|
||||
processZoteroCleanup(this, ctx);
|
||||
void processZoteroCleanup(this, ctx);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
@ -92,9 +94,9 @@ export default class LatexReferencer extends Plugin {
|
|||
const fixed = checkAndFixCalloutMath(content);
|
||||
if (fixed) {
|
||||
editor.setValue(fixed);
|
||||
new Notice('Fixed callout equations.');
|
||||
showNotice('Fixed callout equations.');
|
||||
} else {
|
||||
new Notice('No issues found or no changes needed.');
|
||||
showNotice('No issues found or no changes needed.');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
@ -115,7 +117,7 @@ export default class LatexReferencer extends Plugin {
|
|||
|
||||
this.addCommand({
|
||||
id: 'export-current-file-to-pdf',
|
||||
name: 'Export current file to PDF',
|
||||
name: 'Export current file to pdf',
|
||||
checkCallback: (checking: boolean) => {
|
||||
const view = this.app.workspace.getActiveViewOfType(MarkdownView);
|
||||
const file = view?.file;
|
||||
|
|
@ -133,7 +135,11 @@ export default class LatexReferencer extends Plugin {
|
|||
|
||||
// Menu items for file export
|
||||
this.registerEvent(
|
||||
(this.app.workspace as unknown).on('file-menu', (menu: Menu, file: TFile | TFolder) => {
|
||||
(
|
||||
this.app.workspace as unknown as {
|
||||
on(name: 'file-menu', callback: (menu: Menu, file: TFile | TFolder) => void): EventRef;
|
||||
}
|
||||
).on('file-menu', (menu: Menu, file: TFile | TFolder) => {
|
||||
let title = file instanceof TFolder ? 'Export folder to PDF' : 'Better Export PDF';
|
||||
if (isDev) {
|
||||
title = `${title} (dev)`;
|
||||
|
|
@ -152,7 +158,11 @@ export default class LatexReferencer extends Plugin {
|
|||
);
|
||||
|
||||
this.registerEvent(
|
||||
(this.app.workspace as unknown).on('file-menu', (menu: Menu, file: TFile | TFolder) => {
|
||||
(
|
||||
this.app.workspace as unknown as {
|
||||
on(name: 'file-menu', callback: (menu: Menu, file: TFile | TFolder) => void): EventRef;
|
||||
}
|
||||
).on('file-menu', (menu: Menu, file: TFile | TFolder) => {
|
||||
if (file instanceof TFolder) {
|
||||
let title = 'Export to PDF...';
|
||||
if (isDev) {
|
||||
|
|
@ -160,11 +170,10 @@ export default class LatexReferencer extends Plugin {
|
|||
}
|
||||
menu.addItem(item => {
|
||||
item.setTitle(title).setIcon('lucide-folder-down').setSection('action');
|
||||
// @ts-ignore
|
||||
const subMenu: Menu = item.setSubmenu();
|
||||
const subMenu = (item as unknown as { setSubmenu: () => Menu }).setSubmenu();
|
||||
subMenu.addItem(item =>
|
||||
item
|
||||
.setTitle('Export each file to PDF')
|
||||
.setTitle('Export each file to pdf')
|
||||
.setIcon('lucide-file-stack')
|
||||
.onClick(async () => {
|
||||
new ExportConfigModal(this, file, true).open();
|
||||
|
|
@ -206,7 +215,9 @@ export default class LatexReferencer extends Plugin {
|
|||
this.registerMarkdownPostProcessor(createEquationNumberProcessor(this));
|
||||
this.registerMarkdownPostProcessor(CustomMathLinksProcessor(this));
|
||||
this.registerMarkdownPostProcessor(createRowLayoutProcessor(this));
|
||||
this.app.workspace.onLayoutReady(() => this.forceRerender());
|
||||
this.app.workspace.onLayoutReady(() => {
|
||||
void this.forceRerender();
|
||||
});
|
||||
|
||||
this.patchPagePreview();
|
||||
this.register(setupDOMObserver(this));
|
||||
|
|
@ -217,7 +228,10 @@ export default class LatexReferencer extends Plugin {
|
|||
}
|
||||
|
||||
async loadSettings() {
|
||||
this.settings = { ...DEFAULT_SETTINGS, ...(await this.loadData()) };
|
||||
this.settings = {
|
||||
...DEFAULT_SETTINGS,
|
||||
...((await this.loadData()) as Partial<PluginSettings>)
|
||||
};
|
||||
}
|
||||
|
||||
async saveSettings() {
|
||||
|
|
@ -234,34 +248,46 @@ export default class LatexReferencer extends Plugin {
|
|||
this.app.workspace.updateOptions();
|
||||
}
|
||||
|
||||
forceRerender() {
|
||||
window.setTimeout(async () => {
|
||||
for (const leaf of this.app.workspace.getLeavesOfType('markdown')) {
|
||||
const view = leaf.view as MarkdownView;
|
||||
private forceRerender() {
|
||||
this.app.workspace.iterateAllLeaves(leaf => {
|
||||
const view = leaf.view;
|
||||
if (view instanceof MarkdownView) {
|
||||
view.previewMode.rerender(true);
|
||||
}
|
||||
}, 800);
|
||||
});
|
||||
}
|
||||
|
||||
patchPagePreview() {
|
||||
const pagePreviewPlugin = this.app.internalPlugins.getPluginById('page-preview');
|
||||
if (!pagePreviewPlugin?.instance) {
|
||||
console.log('Latex Referencer: Page Preview plugin not found. Cannot patch hover behavior.');
|
||||
private patchPagePreview() {
|
||||
const pagePreviewPlugin = this.app.internalPlugins.getPluginById('page-preview') as unknown as {
|
||||
enabled: boolean;
|
||||
instance: unknown;
|
||||
} | null;
|
||||
if (!pagePreviewPlugin?.enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
const instance = pagePreviewPlugin.instance;
|
||||
const plugin = this;
|
||||
const app = this.app;
|
||||
const getEquations = (file: TFile, content: string) =>
|
||||
processActiveNoteEquations(this, file, content);
|
||||
|
||||
const uninstaller = around(instance, {
|
||||
const uninstaller = around(instance as Record<string, unknown>, {
|
||||
onLinkHover(old: unknown) {
|
||||
const oldFunc = old as (
|
||||
this: unknown,
|
||||
hoverParent: unknown,
|
||||
targetEl: unknown,
|
||||
linktext: string,
|
||||
sourcePath: string,
|
||||
state: Record<string, unknown>
|
||||
) => unknown;
|
||||
return function (
|
||||
this: unknown,
|
||||
hoverParent: unknown,
|
||||
targetEl: unknown,
|
||||
linktext: string,
|
||||
sourcePath: string,
|
||||
state: unknown
|
||||
state: Record<string, unknown>
|
||||
) {
|
||||
const { path, subpath } = parseLinktext(linktext);
|
||||
|
||||
|
|
@ -274,33 +300,33 @@ export default class LatexReferencer extends Plugin {
|
|||
if (subIndexMatch) {
|
||||
blockId = subpathText.substring(0, subIndexMatch.index);
|
||||
}
|
||||
const targetFile = plugin.app.metadataCache.getFirstLinkpathDest(path, sourcePath);
|
||||
const targetFile = app.metadataCache.getFirstLinkpathDest(path, sourcePath);
|
||||
|
||||
if (targetFile instanceof TFile) {
|
||||
const activeView = plugin.app.workspace.getActiveViewOfType(MarkdownView);
|
||||
const activeView = app.workspace.getActiveViewOfType(MarkdownView);
|
||||
const activeFile = activeView?.file;
|
||||
const activeContent =
|
||||
typeof activeView?.getViewData === 'function' ? activeView.getViewData() : null;
|
||||
|
||||
if (!activeFile || targetFile.path !== activeFile.path || activeContent === null) {
|
||||
return old.call(this, hoverParent, targetEl, linktext, sourcePath, state);
|
||||
return oldFunc.call(this, hoverParent, targetEl, linktext, sourcePath, state);
|
||||
}
|
||||
|
||||
const equations = processActiveNoteEquations(plugin, activeFile, activeContent);
|
||||
const equations = getEquations(activeFile, activeContent);
|
||||
const targetEquation = equations.get(blockId);
|
||||
|
||||
if (targetEquation) {
|
||||
const line = targetEquation.$position.start;
|
||||
const newState = { ...state, scroll: line };
|
||||
// Immediately call the original function with the correct line number
|
||||
return old.call(this, hoverParent, targetEl, linktext, sourcePath, newState);
|
||||
return oldFunc.call(this, hoverParent, targetEl, linktext, sourcePath, newState);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If it's not our link, or if we couldn't find it in the cache,
|
||||
// call the original function without modification.
|
||||
return old.call(this, hoverParent, targetEl, linktext, sourcePath, state);
|
||||
return oldFunc.call(this, hoverParent, targetEl, linktext, sourcePath, state);
|
||||
};
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import { App, PluginSettingTab, Setting, TextAreaComponent } from 'obsidian';
|
|||
import LatexReferencer from 'main';
|
||||
import { NUMBER_STYLES } from './settings';
|
||||
import { NoteSuggestModal } from '../ui/custom-notes/modal';
|
||||
import { setCssProps } from 'utils/obsidian';
|
||||
|
||||
export class MathSettingTab extends PluginSettingTab {
|
||||
constructor(
|
||||
|
|
@ -15,7 +16,7 @@ export class MathSettingTab extends PluginSettingTab {
|
|||
const { containerEl } = this;
|
||||
containerEl.empty();
|
||||
|
||||
new Setting(containerEl).setName('Equation Numbering & Referencing').setHeading();
|
||||
new Setting(containerEl).setName('Equation numbering & referencing').setHeading();
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('Number only referenced equations')
|
||||
|
|
@ -79,7 +80,7 @@ export class MathSettingTab extends PluginSettingTab {
|
|||
|
||||
new Setting(containerEl)
|
||||
.setName('Show note title in equation link')
|
||||
.setDesc('If turned on, a link to an equation will be like "Note title > (1.1)".')
|
||||
.setDesc('If turned on, a link to an equation will be like "note title > (1.1)".')
|
||||
.addToggle(toggle =>
|
||||
toggle.setValue(this.plugin.settings.noteTitleInEquationLink).onChange(async value => {
|
||||
this.plugin.settings.noteTitleInEquationLink = value;
|
||||
|
|
@ -87,7 +88,7 @@ export class MathSettingTab extends PluginSettingTab {
|
|||
})
|
||||
);
|
||||
|
||||
new Setting(containerEl).setName('Autocomplete & Search').setHeading();
|
||||
new Setting(containerEl).setName('Autocomplete & search').setHeading();
|
||||
|
||||
new Setting(containerEl).setName('Enable autocompletion').addToggle(toggle =>
|
||||
toggle.setValue(this.plugin.settings.enableSuggest).onChange(async value => {
|
||||
|
|
@ -110,7 +111,7 @@ export class MathSettingTab extends PluginSettingTab {
|
|||
})
|
||||
);
|
||||
|
||||
new Setting(containerEl).setName('PDF Export').setHeading();
|
||||
new Setting(containerEl).setName('Pdf export').setHeading();
|
||||
|
||||
new Setting(containerEl).setName('Add file name as title').addToggle(toggle =>
|
||||
toggle
|
||||
|
|
@ -118,7 +119,7 @@ export class MathSettingTab extends PluginSettingTab {
|
|||
.setValue(this.plugin.settings.showTitle)
|
||||
.onChange(async value => {
|
||||
this.plugin.settings.showTitle = value;
|
||||
this.plugin.saveSettings();
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
);
|
||||
new Setting(containerEl).setName('Display headers').addToggle(toggle =>
|
||||
|
|
@ -127,7 +128,7 @@ export class MathSettingTab extends PluginSettingTab {
|
|||
.setValue(this.plugin.settings.displayHeader)
|
||||
.onChange(async value => {
|
||||
this.plugin.settings.displayHeader = value;
|
||||
this.plugin.saveSettings();
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
);
|
||||
new Setting(containerEl).setName('Display footer').addToggle(toggle =>
|
||||
|
|
@ -136,7 +137,7 @@ export class MathSettingTab extends PluginSettingTab {
|
|||
.setValue(this.plugin.settings.displayFooter)
|
||||
.onChange(async value => {
|
||||
this.plugin.settings.displayFooter = value;
|
||||
this.plugin.saveSettings();
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
);
|
||||
|
||||
|
|
@ -146,19 +147,19 @@ export class MathSettingTab extends PluginSettingTab {
|
|||
.addToggle(toggle =>
|
||||
toggle.setValue(this.plugin.settings.printBackground).onChange(async value => {
|
||||
this.plugin.settings.printBackground = value;
|
||||
this.plugin.saveSettings();
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
);
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('Generate tagged PDF')
|
||||
.setName('Generate tagged pdf')
|
||||
.setDesc(
|
||||
'Whether or not to generate a tagged (accessible) PDF. Defaults to false. As this property is experimental, the generated PDF may not adhere fully to PDF/UA and WCAG standards.'
|
||||
'Whether or not to generate a tagged (accessible) pdf. Defaults to false. As this property is experimental, the generated pdf may not adhere fully to pdf/ua and wcag standards.'
|
||||
)
|
||||
.addToggle(toggle =>
|
||||
toggle.setValue(this.plugin.settings.generateTaggedPDF).onChange(async value => {
|
||||
this.plugin.settings.generateTaggedPDF = value;
|
||||
this.plugin.saveSettings();
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
);
|
||||
|
||||
|
|
@ -170,29 +171,29 @@ export class MathSettingTab extends PluginSettingTab {
|
|||
.setValue(this.plugin.settings.maxLevel)
|
||||
.onChange(async (value: string) => {
|
||||
this.plugin.settings.maxLevel = value;
|
||||
this.plugin.saveSettings();
|
||||
await this.plugin.saveSettings();
|
||||
});
|
||||
});
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('PDF metadata')
|
||||
.setName('Pdf metadata')
|
||||
.setDesc('Add frontMatter(title, author, keywords, subject creator, etc) to pdf metadata')
|
||||
.addToggle(toggle =>
|
||||
toggle.setValue(this.plugin.settings.displayMetadata).onChange(async value => {
|
||||
this.plugin.settings.displayMetadata = value;
|
||||
this.plugin.saveSettings();
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
);
|
||||
|
||||
new Setting(containerEl).setName('Advanced').setHeading();
|
||||
|
||||
const headerContentAreaSetting = new Setting(containerEl);
|
||||
headerContentAreaSetting.settingEl.setAttribute(
|
||||
'style',
|
||||
'display: grid; grid-template-columns: 1fr;'
|
||||
);
|
||||
setCssProps(headerContentAreaSetting.settingEl, {
|
||||
display: 'grid',
|
||||
'grid-template-columns': '1fr'
|
||||
});
|
||||
headerContentAreaSetting
|
||||
.setName('Header Template')
|
||||
.setName('Header template')
|
||||
.setDesc(
|
||||
'HTML template for the print header. ' +
|
||||
'Should be valid HTML markup with following classes used to inject printing values into them: ' +
|
||||
|
|
@ -200,32 +201,36 @@ export class MathSettingTab extends PluginSettingTab {
|
|||
);
|
||||
const hederContentArea = new TextAreaComponent(headerContentAreaSetting.controlEl);
|
||||
|
||||
setAttributes(hederContentArea.inputEl, {
|
||||
style: 'margin-top: 12px; width: 100%; height: 6vh;'
|
||||
setCssProps(hederContentArea.inputEl, {
|
||||
'margin-top': '12px',
|
||||
width: '100%',
|
||||
height: '6vh'
|
||||
});
|
||||
hederContentArea.setValue(this.plugin.settings.headerTemplate).onChange(async value => {
|
||||
this.plugin.settings.headerTemplate = value;
|
||||
this.plugin.saveSettings();
|
||||
await this.plugin.saveSettings();
|
||||
});
|
||||
|
||||
const footerContentAreaSetting = new Setting(containerEl);
|
||||
footerContentAreaSetting.settingEl.setAttribute(
|
||||
'style',
|
||||
'display: grid; grid-template-columns: 1fr;'
|
||||
);
|
||||
setCssProps(footerContentAreaSetting.settingEl, {
|
||||
display: 'grid',
|
||||
'grid-template-columns': '1fr'
|
||||
});
|
||||
footerContentAreaSetting
|
||||
.setName('Footer Template')
|
||||
.setName('Footer template')
|
||||
.setDesc(
|
||||
'HTML template for the print footer. Should use the same format as the headerTemplate.'
|
||||
'Html template for the print footer. Should use the same format as the headerTemplate.'
|
||||
);
|
||||
const footerContentArea = new TextAreaComponent(footerContentAreaSetting.controlEl);
|
||||
|
||||
setAttributes(footerContentArea.inputEl, {
|
||||
style: 'margin-top: 12px; width: 100%; height: 6vh;'
|
||||
setCssProps(footerContentArea.inputEl, {
|
||||
'margin-top': '12px',
|
||||
width: '100%',
|
||||
height: '6vh'
|
||||
});
|
||||
footerContentArea.setValue(this.plugin.settings.footerTemplate).onChange(async value => {
|
||||
this.plugin.settings.footerTemplate = value;
|
||||
this.plugin.saveSettings();
|
||||
await this.plugin.saveSettings();
|
||||
});
|
||||
|
||||
new Setting(containerEl)
|
||||
|
|
@ -259,7 +264,7 @@ export class MathSettingTab extends PluginSettingTab {
|
|||
});
|
||||
});
|
||||
|
||||
new Setting(containerEl).setName('TikZJax Rendering').setHeading();
|
||||
new Setting(containerEl).setName('TikZJax rendering').setHeading();
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('Enable TikZ rendering')
|
||||
|
|
@ -285,12 +290,12 @@ export class MathSettingTab extends PluginSettingTab {
|
|||
})
|
||||
);
|
||||
|
||||
new Setting(containerEl).setName('Zotero Cleanup').setHeading();
|
||||
new Setting(containerEl).setName('Zotero cleanup').setHeading();
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('Directories to search')
|
||||
.setDesc(
|
||||
"Comma-separated list of directories to search recursively for Zotero annotations (e.g. 'Zotero,Notes/Readings')."
|
||||
"Comma-separated list of directories to search recursively for Zotero annotations (e.g. 'Zotero,notes/readings')."
|
||||
)
|
||||
.addTextArea(textArea => {
|
||||
textArea.setValue(this.plugin.settings.zoteroCleanDirectories).onChange(async value => {
|
||||
|
|
@ -300,9 +305,9 @@ export class MathSettingTab extends PluginSettingTab {
|
|||
textArea.inputEl.setAttr('rows', 3);
|
||||
});
|
||||
|
||||
new Setting(containerEl).setName('Custom Note Hotkeys').setHeading();
|
||||
new Setting(containerEl).setName('Custom note hotkeys').setHeading();
|
||||
containerEl.createEl('p', {
|
||||
text: "Configure hotkeys to quickly open specific notes in your vault. You can define optional default hotkeys here, and further customize or rebind them within Obsidian's global 'Hotkeys' settings.",
|
||||
text: "Configure hotkeys to quickly open specific notes in your vault. You can define optional default hotkeys here, and further customize or rebind them within Obsidian's global 'hotkeys' settings.",
|
||||
cls: 'setting-item-description'
|
||||
});
|
||||
|
||||
|
|
@ -310,64 +315,68 @@ export class MathSettingTab extends PluginSettingTab {
|
|||
.setName('Add new hotkey mapping')
|
||||
.setDesc('Create a new shortcut command to open a specific note.')
|
||||
.addButton(btn =>
|
||||
btn
|
||||
.setButtonText('+ Add hotkey mapping')
|
||||
.setCta()
|
||||
.onClick(async () => {
|
||||
if (!this.plugin.settings.customNoteHotkeys) {
|
||||
this.plugin.settings.customNoteHotkeys = [];
|
||||
}
|
||||
this.plugin.settings.customNoteHotkeys.push({
|
||||
id: Date.now().toString(),
|
||||
notePath: '',
|
||||
name: '',
|
||||
hotkeyModifiers: ['Mod'],
|
||||
hotkeyKey: ''
|
||||
});
|
||||
await this.plugin.saveSettings();
|
||||
this.plugin.customNoteManager.registerCommands();
|
||||
this.display();
|
||||
})
|
||||
btn.onClick(async () => {
|
||||
if (!this.plugin.settings.customNoteHotkeys) {
|
||||
this.plugin.settings.customNoteHotkeys = [];
|
||||
}
|
||||
this.plugin.settings.customNoteHotkeys.push({
|
||||
id: Date.now().toString(),
|
||||
notePath: '',
|
||||
name: '',
|
||||
hotkeyModifiers: ['Mod'],
|
||||
hotkeyKey: ''
|
||||
});
|
||||
await this.plugin.saveSettings();
|
||||
this.plugin.customNoteManager.registerCommands();
|
||||
(this as unknown as { display(): void }).display();
|
||||
})
|
||||
);
|
||||
|
||||
const hotkeys = this.plugin.settings.customNoteHotkeys || [];
|
||||
hotkeys.forEach((item, index) => {
|
||||
const hotkeyContainer = containerEl.createEl('div', {
|
||||
cls: 'custom-note-hotkey-item',
|
||||
attr: {
|
||||
style:
|
||||
'border: 1px solid var(--background-modifier-border); padding: 15px; margin-bottom: 15px; border-radius: 8px; background-color: var(--background-primary-alt);'
|
||||
}
|
||||
cls: 'custom-note-hotkey-item'
|
||||
});
|
||||
setCssProps(hotkeyContainer, {
|
||||
border: '1px solid var(--background-modifier-border)',
|
||||
padding: '15px',
|
||||
'margin-bottom': '15px',
|
||||
'border-radius': '8px',
|
||||
'background-color': 'var(--background-primary-alt)'
|
||||
});
|
||||
|
||||
const titleRow = hotkeyContainer.createEl('div', {
|
||||
attr: {
|
||||
style:
|
||||
'display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px;'
|
||||
}
|
||||
const titleRow = hotkeyContainer.createEl('div');
|
||||
setCssProps(titleRow, {
|
||||
display: 'flex',
|
||||
'justify-content': 'space-between',
|
||||
'align-items': 'center',
|
||||
'margin-bottom': '10px'
|
||||
});
|
||||
titleRow.createEl('strong', { text: `Hotkey Mapping #${index + 1}` });
|
||||
|
||||
const deleteBtn = titleRow.createEl('button', {
|
||||
text: 'Delete',
|
||||
cls: 'mod-warning',
|
||||
attr: {
|
||||
style: 'background-color: var(--background-modifier-error); color: var(--text-on-accent);'
|
||||
}
|
||||
cls: 'mod-warning'
|
||||
});
|
||||
deleteBtn.addEventListener('click', async () => {
|
||||
hotkeys.splice(index, 1);
|
||||
await this.plugin.saveSettings();
|
||||
this.plugin.customNoteManager.registerCommands();
|
||||
this.display();
|
||||
setCssProps(deleteBtn, {
|
||||
'background-color': 'var(--background-modifier-error)',
|
||||
color: 'var(--text-on-accent)'
|
||||
});
|
||||
deleteBtn.addEventListener('click', () => {
|
||||
void (async () => {
|
||||
hotkeys.splice(index, 1);
|
||||
await this.plugin.saveSettings();
|
||||
this.plugin.customNoteManager.registerCommands();
|
||||
(this as unknown as { display(): void }).display();
|
||||
})();
|
||||
});
|
||||
|
||||
new Setting(hotkeyContainer)
|
||||
.setName('Friendly name')
|
||||
.setDesc("A clear label for the Obsidian command (e.g. 'Daily Planner').")
|
||||
.setDesc("A clear label for the Obsidian command (e.g. 'daily planner').")
|
||||
.addText(text =>
|
||||
text
|
||||
.setPlaceholder('e.g. My Note')
|
||||
.setPlaceholder('E.g. My note')
|
||||
.setValue(item.name)
|
||||
.onChange(async value => {
|
||||
item.name = value;
|
||||
|
|
@ -378,7 +387,7 @@ export class MathSettingTab extends PluginSettingTab {
|
|||
|
||||
const pathSetting = new Setting(hotkeyContainer)
|
||||
.setName('Note path')
|
||||
.setDesc('The relative vault path to the target markdown note.');
|
||||
.setDesc('The relative vault path to the target Markdown note.');
|
||||
|
||||
pathSetting.addText(text => {
|
||||
text
|
||||
|
|
@ -393,13 +402,15 @@ export class MathSettingTab extends PluginSettingTab {
|
|||
pathSetting.addButton(btn =>
|
||||
btn
|
||||
.setIcon('search')
|
||||
.setTooltip('Browse/Search vault notes')
|
||||
.setTooltip('Browse/search vault notes')
|
||||
.onClick(() => {
|
||||
new NoteSuggestModal(this.app, async file => {
|
||||
text.setValue(file.path);
|
||||
item.notePath = file.path;
|
||||
await this.plugin.saveSettings();
|
||||
this.plugin.customNoteManager.registerCommands();
|
||||
new NoteSuggestModal(this.app, file => {
|
||||
void (async () => {
|
||||
text.setValue(file.path);
|
||||
item.notePath = file.path;
|
||||
await this.plugin.saveSettings();
|
||||
this.plugin.customNoteManager.registerCommands();
|
||||
})();
|
||||
}).open();
|
||||
})
|
||||
);
|
||||
|
|
@ -415,7 +426,7 @@ export class MathSettingTab extends PluginSettingTab {
|
|||
|
||||
hotkeySetting.addToggle(toggle =>
|
||||
toggle
|
||||
.setTooltip('Ctrl / Cmd (Mod)')
|
||||
.setTooltip('Ctrl / cmd (mod)')
|
||||
.setValue(isMod)
|
||||
.onChange(async value => {
|
||||
if (value) {
|
||||
|
|
@ -427,10 +438,10 @@ export class MathSettingTab extends PluginSettingTab {
|
|||
this.plugin.customNoteManager.registerCommands();
|
||||
})
|
||||
);
|
||||
hotkeySetting.controlEl.createSpan({
|
||||
text: 'Ctrl/Cmd ',
|
||||
attr: { style: 'margin-right: 15px; font-size: 0.9em;' }
|
||||
const span1 = hotkeySetting.controlEl.createSpan({
|
||||
text: 'Ctrl/Cmd '
|
||||
});
|
||||
setCssProps(span1, { 'margin-right': '15px', 'font-size': '0.9em' });
|
||||
|
||||
hotkeySetting.addToggle(toggle =>
|
||||
toggle
|
||||
|
|
@ -446,10 +457,10 @@ export class MathSettingTab extends PluginSettingTab {
|
|||
this.plugin.customNoteManager.registerCommands();
|
||||
})
|
||||
);
|
||||
hotkeySetting.controlEl.createSpan({
|
||||
text: 'Alt ',
|
||||
attr: { style: 'margin-right: 15px; font-size: 0.9em;' }
|
||||
const span2 = hotkeySetting.controlEl.createSpan({
|
||||
text: 'Alt '
|
||||
});
|
||||
setCssProps(span2, { 'margin-right': '15px', 'font-size': '0.9em' });
|
||||
|
||||
hotkeySetting.addToggle(toggle =>
|
||||
toggle
|
||||
|
|
@ -465,10 +476,10 @@ export class MathSettingTab extends PluginSettingTab {
|
|||
this.plugin.customNoteManager.registerCommands();
|
||||
})
|
||||
);
|
||||
hotkeySetting.controlEl.createSpan({
|
||||
text: 'Shift ',
|
||||
attr: { style: 'margin-right: 15px; font-size: 0.9em;' }
|
||||
const span3 = hotkeySetting.controlEl.createSpan({
|
||||
text: 'Shift '
|
||||
});
|
||||
setCssProps(span3, { 'margin-right': '15px', 'font-size': '0.9em' });
|
||||
|
||||
hotkeySetting.addText(text =>
|
||||
text
|
||||
|
|
@ -494,9 +505,3 @@ export class MathSettingTab extends PluginSettingTab {
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
function setAttributes(element: HTMLTextAreaElement, attributes: { [x: string]: string }) {
|
||||
for (const key in attributes) {
|
||||
element.setAttribute(key, attributes[key]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@
|
|||
|
||||
.math-booster-begin-proof {
|
||||
padding-right: 10px;
|
||||
font-family: CMU Serif, Times, Noto Serif JP;
|
||||
font-family: CMU Serif, Times, Noto Serif JP, serif;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
|
|
@ -132,7 +132,7 @@
|
|||
background-color: rgb(0, 0, 0, 0);
|
||||
border: solid var(--border-width);
|
||||
border-radius: var(--size-2-3);
|
||||
font-family: CMU Serif, Times, Noto Serif JP;
|
||||
font-family: CMU Serif, Times, Noto Serif JP, serif;
|
||||
}
|
||||
|
||||
.theme-framed .theorem-callout .callout-icon {
|
||||
|
|
@ -140,7 +140,7 @@
|
|||
}
|
||||
|
||||
.theme-framed .theorem-callout-main-title {
|
||||
font-family: CMU Serif, Times, Noto Sans JP;
|
||||
font-family: CMU Serif, Times, Noto Sans JP, sans-serif;
|
||||
font-weight: bolder;
|
||||
}
|
||||
|
||||
|
|
@ -162,7 +162,7 @@
|
|||
padding-right: 0;
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
font-family: CMU Serif, Times, Noto Serif JP;
|
||||
font-family: CMU Serif, Times, Noto Serif JP, serif;
|
||||
}
|
||||
|
||||
.theme-plain .theorem-callout .callout-icon {
|
||||
|
|
@ -170,7 +170,7 @@
|
|||
}
|
||||
|
||||
.theme-plain .theorem-callout-main-title {
|
||||
font-family: CMU Serif, Times, Noto Sans JP;
|
||||
font-family: CMU Serif, Times, Noto Sans JP, sans-serif;
|
||||
font-weight: bolder;
|
||||
}
|
||||
|
||||
|
|
@ -194,7 +194,7 @@
|
|||
border-radius: 0px;
|
||||
box-shadow: none;
|
||||
padding: 0px;
|
||||
font-family: CMU Serif, Times, Noto Serif JP;
|
||||
font-family: CMU Serif, Times, Noto Serif JP, serif;
|
||||
}
|
||||
|
||||
.theme-vivid .theorem-callout .callout-title {
|
||||
|
|
@ -207,7 +207,7 @@
|
|||
}
|
||||
|
||||
.theme-vivid .theorem-callout .callout-title-inner {
|
||||
font-family: Inter;
|
||||
font-family: Inter, sans-serif;
|
||||
font-weight: normal;
|
||||
color: rgb(var(--callout-color));
|
||||
}
|
||||
|
|
@ -226,7 +226,7 @@
|
|||
|
||||
.theme-mathwiki .theorem-callout {
|
||||
--callout-color: 248, 248, 255;
|
||||
font-family: CMU Serif, Times, Noto Serif JP;
|
||||
font-family: CMU Serif, Times, Noto Serif JP, serif;
|
||||
}
|
||||
|
||||
.theme-mathwiki .theorem-callout .callout-title-inner {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import * as fs from 'fs/promises';
|
||||
import {
|
||||
App,
|
||||
ButtonComponent,
|
||||
type FrontMatterCache,
|
||||
Modal,
|
||||
|
|
@ -8,10 +8,36 @@ import {
|
|||
TFolder,
|
||||
debounce
|
||||
} from 'obsidian';
|
||||
import * as path from 'path';
|
||||
import { PageSize } from 'features/export-pdf/constant';
|
||||
import LatexReferencer from 'main';
|
||||
import { exportToPDF, getOutputFile, getOutputPath } from 'features/export-pdf/pdf';
|
||||
import { showNotice, setCssProps } from 'utils/obsidian';
|
||||
|
||||
interface FsPromisesModule {
|
||||
readFile(path: string, options: { encoding: string }): Promise<string>;
|
||||
}
|
||||
|
||||
interface PathModule {
|
||||
join(...paths: string[]): string;
|
||||
}
|
||||
|
||||
interface ElectronWebView extends HTMLIFrameElement {
|
||||
executeJavaScript(script: string): Promise<[number, number]>;
|
||||
insertCSS(css: string): Promise<void>;
|
||||
openDevTools(): void;
|
||||
printToPDF(options: Record<string, unknown>): Promise<ArrayBuffer>;
|
||||
}
|
||||
|
||||
const getRequire = (): ((id: string) => unknown) | null => {
|
||||
if (typeof window !== 'undefined' && 'require' in window) {
|
||||
return (window as unknown as { require: (id: string) => unknown }).require;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
const req = getRequire();
|
||||
const fs = req ? (req('fs/promises') as FsPromisesModule) : null;
|
||||
const path = req ? (req('path') as PathModule) : null;
|
||||
import {
|
||||
createWebview,
|
||||
fixDoc,
|
||||
|
|
@ -61,11 +87,28 @@ export type DocType = { doc: Document; frontMatter?: FrontMatterCache; file: TFi
|
|||
type Callback = (conf: TConfig) => void;
|
||||
|
||||
function fullWidthButton(button: ButtonComponent) {
|
||||
button.buttonEl.setAttribute('style', `margin: "0 auto"; width: -webkit-fill-available`);
|
||||
setCssProps(button.buttonEl, {
|
||||
margin: '0 auto',
|
||||
width: '-webkit-fill-available'
|
||||
});
|
||||
}
|
||||
|
||||
function setInputWidth(inputEl: HTMLInputElement) {
|
||||
inputEl.setAttribute('style', `width: 100px;`);
|
||||
setCssProps(inputEl, {
|
||||
width: '100px'
|
||||
});
|
||||
}
|
||||
|
||||
interface CustomCssApp {
|
||||
customCss?: {
|
||||
snippets?: string[];
|
||||
enabledSnippets?: Set<string>;
|
||||
};
|
||||
vault: App['vault'] & {
|
||||
adapter: {
|
||||
basePath: string;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export class ExportConfigModal extends Modal {
|
||||
|
|
@ -74,16 +117,19 @@ export class ExportConfigModal extends Modal {
|
|||
multiplePdf?: boolean;
|
||||
callback!: Callback;
|
||||
file: TFile | TFolder;
|
||||
preview: unknown;
|
||||
webviews: unknown[];
|
||||
preview: ElectronWebView | null = null;
|
||||
webviews: ElectronWebView[];
|
||||
previewDiv!: HTMLDivElement;
|
||||
completed: boolean;
|
||||
docs: DocType[];
|
||||
title!: string;
|
||||
frontMatter!: FrontMatterCache;
|
||||
scale: number;
|
||||
scale!: number;
|
||||
// @ts-ignore
|
||||
svelte: Progress;
|
||||
svelte: {
|
||||
initRenderStates(data: ParamType[]): void;
|
||||
updateRenderStates(i: number): void;
|
||||
} | null = null;
|
||||
|
||||
constructor(
|
||||
public plugin: LatexReferencer,
|
||||
|
|
@ -182,23 +228,30 @@ export class ExportConfigModal extends Modal {
|
|||
});
|
||||
}
|
||||
parseToc(doc: Document) {
|
||||
const cache = this.getFileCache(this.file as TFile);
|
||||
const files =
|
||||
if (!(this.file instanceof TFile)) return [];
|
||||
const cache = this.getFileCache(this.file);
|
||||
const results =
|
||||
cache?.links
|
||||
?.map(({ link, displayText }) => {
|
||||
const id = crypto.randomUUID();
|
||||
const id: string = crypto.randomUUID();
|
||||
const elem = doc.querySelector(`a[data-href="${link}"]`) as HTMLAnchorElement;
|
||||
if (elem) {
|
||||
elem.href = `#${id}`;
|
||||
}
|
||||
const target = this.plugin.app.metadataCache.getFirstLinkpathDest(link, this.file.path);
|
||||
if (!(target instanceof TFile)) {
|
||||
return null;
|
||||
}
|
||||
return {
|
||||
title: displayText,
|
||||
file: this.app.metadataCache.getFirstLinkpathDest(link, this.file.path) as TFile,
|
||||
file: target,
|
||||
id
|
||||
};
|
||||
})
|
||||
.filter(item => item.file instanceof TFile) ?? [];
|
||||
return files;
|
||||
.filter(
|
||||
(item): item is { title: string | undefined; file: TFile; id: string } => item !== null
|
||||
) ?? [];
|
||||
return results;
|
||||
}
|
||||
|
||||
mergeDoc(docs: DocType[]) {
|
||||
|
|
@ -240,9 +293,11 @@ export class ExportConfigModal extends Modal {
|
|||
const scale = Math.floor((mm2px(width) / el.offsetWidth) * 100) / 100;
|
||||
|
||||
this.webviews.forEach(wb => {
|
||||
wb.style.transform = `scale(${1 / scale},${1 / scale})`;
|
||||
wb.style.width = `calc(${scale} * 100%)`;
|
||||
wb.style.height = `${mm2px(h)}px`;
|
||||
setCssProps(wb, {
|
||||
transform: `scale(${1 / scale},${1 / scale})`,
|
||||
width: `calc(${scale} * 100%)`,
|
||||
height: `${mm2px(h)}px`
|
||||
});
|
||||
});
|
||||
this.scale = scale;
|
||||
return scale;
|
||||
|
|
@ -250,24 +305,27 @@ export class ExportConfigModal extends Modal {
|
|||
|
||||
async calcWebviewSize() {
|
||||
await sleep(500);
|
||||
this.webviews.forEach(async (e, i) => {
|
||||
for (let i = 0; i < this.webviews.length; i++) {
|
||||
const e = this.webviews[i];
|
||||
const [width, height] = await e.executeJavaScript(
|
||||
'[document.body.offsetWidth, document.body.offsetHeight]'
|
||||
);
|
||||
const sizeEl = e.parentNode?.querySelector('.print-size');
|
||||
if (sizeEl) {
|
||||
sizeEl.innerHTML = `${width}×${height}px\n${px2mm(width)}×${px2mm(height)}mm`;
|
||||
sizeEl.empty();
|
||||
sizeEl.createDiv({ text: `${width}×${height}px` });
|
||||
sizeEl.createDiv({ text: `${px2mm(width)}×${px2mm(height)}mm` });
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async togglePrintSize() {
|
||||
document.querySelectorAll('.print-size')?.forEach((el: Element) => {
|
||||
activeDocument.querySelectorAll('.print-size')?.forEach((el: Element) => {
|
||||
const sizeEl = el as HTMLDivElement;
|
||||
if (this.config['pageSize'] == 'Custom') {
|
||||
sizeEl.style.visibility = 'visible';
|
||||
if (this.config['pageSize'] === 'Custom') {
|
||||
setCssProps(sizeEl, { visibility: 'visible' });
|
||||
} else {
|
||||
sizeEl.style.visibility = 'hidden';
|
||||
setCssProps(sizeEl, { visibility: 'hidden' });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -275,7 +333,7 @@ export class ExportConfigModal extends Modal {
|
|||
makeWebviewJs(doc: Document) {
|
||||
return `
|
||||
document.body.innerHTML = decodeURIComponent(\`${encodeURIComponent(doc.body.innerHTML)}\`);
|
||||
document.head.innerHTML = decodeURIComponent(\`${encodeURIComponent(document.head.innerHTML)}\`);
|
||||
document.head.innerHTML = decodeURIComponent(\`${encodeURIComponent(activeDocument.head.innerHTML)}\`);
|
||||
|
||||
// Function to recursively decode and replace innerHTML of span.markdown-embed elements
|
||||
function decodeAndReplaceEmbed(element) {
|
||||
|
|
@ -288,9 +346,9 @@ export class ExportConfigModal extends Modal {
|
|||
|
||||
// Start the process with all span.markdown-embed elements in the document
|
||||
document.querySelectorAll("span.markdown-embed").forEach(decodeAndReplaceEmbed);
|
||||
|
||||
document.body.setAttribute("class", \`${document.body.getAttribute('class')}\`)
|
||||
document.body.setAttribute("style", \`${document.body.getAttribute('style')}\`)
|
||||
|
||||
document.body.setAttribute("class", \`${activeDocument.body.getAttribute('class')}\`)
|
||||
document.body.setAttribute("style", \`${activeDocument.body.getAttribute('style')}\`)
|
||||
document.body.addClass("theme-light");
|
||||
document.body.removeClass("theme-dark");
|
||||
document.title = \`${doc.title}\`;
|
||||
|
|
@ -302,30 +360,36 @@ export class ExportConfigModal extends Modal {
|
|||
* @param render Rerender or not
|
||||
*/
|
||||
async appendWebview(e: HTMLDivElement, doc: Document) {
|
||||
const webview = createWebview(this.scale);
|
||||
const webview = createWebview(this.scale) as unknown as ElectronWebView;
|
||||
const preview = e.appendChild(webview);
|
||||
this.webviews.push(preview);
|
||||
this.preview = preview;
|
||||
preview.addEventListener('dom-ready', async e => {
|
||||
this.completed = true;
|
||||
getAllStyles().forEach(async css => {
|
||||
await preview.insertCSS(css);
|
||||
});
|
||||
if (this.config.cssSnippet && this.config.cssSnippet != '0') {
|
||||
try {
|
||||
const cssSnippet = await fs.readFile(this.config.cssSnippet, { encoding: 'utf8' });
|
||||
// remove `@media print { ... }`
|
||||
const printCss = cssSnippet.replaceAll(/@media print\s*{([^}]+)}/g, '$1');
|
||||
await preview.insertCSS(printCss);
|
||||
await preview.insertCSS(cssSnippet);
|
||||
} catch (error) {
|
||||
console.warn(error);
|
||||
preview.addEventListener('dom-ready', () => {
|
||||
void (async () => {
|
||||
this.completed = true;
|
||||
const styles = getAllStyles();
|
||||
for (const css of styles) {
|
||||
await preview.insertCSS(css);
|
||||
}
|
||||
}
|
||||
await preview.executeJavaScript(this.makeWebviewJs(doc));
|
||||
getPatchStyle().forEach(async css => {
|
||||
await preview.insertCSS(css);
|
||||
});
|
||||
if (this.config.cssSnippet && this.config.cssSnippet !== '0') {
|
||||
try {
|
||||
if (fs) {
|
||||
const cssSnippet = await fs.readFile(this.config.cssSnippet, { encoding: 'utf8' });
|
||||
// remove `@media print { ... }`
|
||||
const printCss = cssSnippet.replaceAll(/@media print\s*{([^}]+)}/g, '$1');
|
||||
await preview.insertCSS(printCss);
|
||||
await preview.insertCSS(cssSnippet);
|
||||
}
|
||||
} catch {
|
||||
// Ignore snippet loading issues
|
||||
}
|
||||
}
|
||||
await preview.executeJavaScript(this.makeWebviewJs(doc));
|
||||
const patchStyles = getPatchStyle();
|
||||
for (const css of patchStyles) {
|
||||
await preview.insertCSS(css);
|
||||
}
|
||||
})();
|
||||
});
|
||||
}
|
||||
async appendWebviews(el: HTMLDivElement, render = true) {
|
||||
|
|
@ -340,8 +404,10 @@ export class ExportConfigModal extends Modal {
|
|||
}
|
||||
});
|
||||
const { data, docs } = await this.getAllFiles();
|
||||
this.svelte.initRenderStates(data);
|
||||
await this.renderFiles(data, docs, this.svelte.updateRenderStates);
|
||||
if (this.svelte) {
|
||||
this.svelte.initRenderStates(data);
|
||||
await this.renderFiles(data, docs, i => this.svelte?.updateRenderStates(i));
|
||||
}
|
||||
}
|
||||
el.empty();
|
||||
await Promise.all(
|
||||
|
|
@ -362,29 +428,33 @@ export class ExportConfigModal extends Modal {
|
|||
async onOpen() {
|
||||
this.contentEl.empty();
|
||||
this.modalEl.addClass('better-export-pdf-modal');
|
||||
this.containerEl.style.setProperty('--dialog-width', '90vw');
|
||||
this.containerEl.style.setProperty('--dialog-height', '90vh');
|
||||
setCssProps(this.containerEl, {
|
||||
'--dialog-width': '90vw',
|
||||
'--dialog-height': '90vh'
|
||||
});
|
||||
|
||||
this.titleEl.setText('Export to PDF');
|
||||
this.titleEl.setText('Export to pdf');
|
||||
const wrapper = this.contentEl.createDiv({ attr: { id: 'better-export-pdf' } });
|
||||
|
||||
const title = (this.file as TFile)?.basename ?? this.file?.name;
|
||||
const title = this.file instanceof TFile ? this.file.basename : this.file.name;
|
||||
|
||||
this.previewDiv = wrapper.createDiv({ attr: { class: 'pdf-preview' } }, async el => {
|
||||
this.previewDiv = wrapper.createDiv({ attr: { class: 'pdf-preview' } }, el => {
|
||||
el.empty();
|
||||
const resizeObserver = new ResizeObserver(() => {
|
||||
this.calcPageSize(el);
|
||||
});
|
||||
resizeObserver.observe(el);
|
||||
await this.appendWebviews(el);
|
||||
this.calcPageSize(el);
|
||||
this.togglePrintSize();
|
||||
void (async () => {
|
||||
await this.appendWebviews(el);
|
||||
this.calcPageSize(el);
|
||||
await this.togglePrintSize();
|
||||
})();
|
||||
});
|
||||
|
||||
const contentEl = wrapper.createDiv({ attr: { class: 'setting-wrapper' } });
|
||||
contentEl.addEventListener('keyup', event => {
|
||||
if (event.key === 'Enter') {
|
||||
handleExport();
|
||||
void handleExport();
|
||||
}
|
||||
});
|
||||
this.generateForm(contentEl);
|
||||
|
|
@ -392,19 +462,18 @@ export class ExportConfigModal extends Modal {
|
|||
const handleExport = async () => {
|
||||
this.plugin.settings.prevConfig = this.config;
|
||||
await this.plugin.saveSettings();
|
||||
if (this.config['pageSize'] == 'Custom') {
|
||||
if (this.config['pageSize'] === 'Custom') {
|
||||
if (
|
||||
!isNumber(this.config['pageWidth'] ?? '') ||
|
||||
!isNumber(this.config['pageHeight'] ?? '')
|
||||
) {
|
||||
alert('When the page size is Custom, the Width/Height cannot be empty.');
|
||||
showNotice('When the page size is Custom, the Width/Height cannot be empty.');
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.multiplePdf) {
|
||||
const outputPath = await getOutputPath(title);
|
||||
console.log('output:', outputPath);
|
||||
if (outputPath) {
|
||||
await Promise.all(
|
||||
this.webviews.map(async (wb, i) => {
|
||||
|
|
@ -433,21 +502,27 @@ export class ExportConfigModal extends Modal {
|
|||
};
|
||||
|
||||
new Setting(contentEl).setHeading().addButton(button => {
|
||||
button.setButtonText('Export').onClick(handleExport);
|
||||
button.setButtonText('Export').onClick(() => {
|
||||
void handleExport();
|
||||
});
|
||||
button.setCta();
|
||||
fullWidthButton(button);
|
||||
});
|
||||
|
||||
new Setting(contentEl).setHeading().addButton(button => {
|
||||
button.setButtonText('Refresh').onClick(async () => {
|
||||
await this.appendWebviews(this.previewDiv);
|
||||
button.setButtonText('Refresh').onClick(() => {
|
||||
void (async () => {
|
||||
await this.appendWebviews(this.previewDiv);
|
||||
})();
|
||||
});
|
||||
fullWidthButton(button);
|
||||
});
|
||||
|
||||
const debugEl = new Setting(contentEl).setHeading().addButton(button => {
|
||||
button.setButtonText('Debug').onClick(async () => {
|
||||
this.preview?.openDevTools();
|
||||
button.setButtonText('Debug').onClick(() => {
|
||||
void (async () => {
|
||||
this.preview?.openDevTools();
|
||||
})();
|
||||
});
|
||||
fullWidthButton(button);
|
||||
});
|
||||
|
|
@ -462,7 +537,7 @@ export class ExportConfigModal extends Modal {
|
|||
.onChange(async value => {
|
||||
this.config['showTitle'] = value;
|
||||
this.webviews.forEach((wv, i) => {
|
||||
wv.executeJavaScript(`
|
||||
void wv.executeJavaScript(`
|
||||
var _title = document.querySelector("h1.__title__");
|
||||
if (_title) {
|
||||
_title.style.display = "${value ? 'block' : 'none'}";
|
||||
|
|
@ -470,7 +545,7 @@ export class ExportConfigModal extends Modal {
|
|||
`);
|
||||
const _title = this.docs[i]?.doc?.querySelector('h1.__title__') as HTMLHeadingElement;
|
||||
if (_title) {
|
||||
_title.style.display = value ? 'block' : 'none';
|
||||
setCssProps(_title, { display: value ? 'block' : 'none' });
|
||||
}
|
||||
});
|
||||
})
|
||||
|
|
@ -489,36 +564,40 @@ export class ExportConfigModal extends Modal {
|
|||
'Ledger',
|
||||
'Custom'
|
||||
];
|
||||
new Setting(contentEl).setName('Page Size').addDropdown(dropdown => {
|
||||
new Setting(contentEl).setName('Page size').addDropdown(dropdown => {
|
||||
dropdown
|
||||
.addOptions(Object.fromEntries(pageSizes.map(size => [size, size])))
|
||||
.setValue(this.config.pageSize)
|
||||
.onChange(async (value: string) => {
|
||||
this.config['pageSize'] = value;
|
||||
if (value == 'Custom') {
|
||||
sizeEl.settingEl.hidden = false;
|
||||
} else {
|
||||
sizeEl.settingEl.hidden = true;
|
||||
}
|
||||
this.togglePrintSize();
|
||||
this.calcPageSize();
|
||||
await this.calcWebviewSize();
|
||||
.onChange((value: string) => {
|
||||
void (async () => {
|
||||
this.config['pageSize'] = value;
|
||||
if (value === 'Custom') {
|
||||
sizeEl.settingEl.hidden = false;
|
||||
} else {
|
||||
sizeEl.settingEl.hidden = true;
|
||||
}
|
||||
void this.togglePrintSize();
|
||||
this.calcPageSize();
|
||||
await this.calcWebviewSize();
|
||||
})();
|
||||
});
|
||||
});
|
||||
|
||||
const sizeEl = new Setting(contentEl)
|
||||
.setName('Width/Height')
|
||||
.setName('Width/height')
|
||||
.addText(text => {
|
||||
setInputWidth(text.inputEl);
|
||||
text
|
||||
.setPlaceholder('width')
|
||||
.setPlaceholder('Width')
|
||||
.setValue(this.config['pageWidth'] as string)
|
||||
.onChange(
|
||||
debounce(
|
||||
async value => {
|
||||
this.config['pageWidth'] = value;
|
||||
this.calcPageSize();
|
||||
await this.calcWebviewSize();
|
||||
value => {
|
||||
void (async () => {
|
||||
this.config['pageWidth'] = value;
|
||||
this.calcPageSize();
|
||||
await this.calcWebviewSize();
|
||||
})();
|
||||
},
|
||||
500,
|
||||
true
|
||||
|
|
@ -528,7 +607,7 @@ export class ExportConfigModal extends Modal {
|
|||
.addText(text => {
|
||||
setInputWidth(text.inputEl);
|
||||
text
|
||||
.setPlaceholder('height')
|
||||
.setPlaceholder('Height')
|
||||
.setValue(this.config['pageHeight'] as string)
|
||||
.onChange(value => {
|
||||
this.config['pageHeight'] = value;
|
||||
|
|
@ -547,9 +626,9 @@ export class ExportConfigModal extends Modal {
|
|||
.addOption('2', 'Small')
|
||||
.addOption('3', 'Custom')
|
||||
.setValue(this.config['marginType'])
|
||||
.onChange(async (value: string) => {
|
||||
.onChange((value: string) => {
|
||||
this.config['marginType'] = value;
|
||||
if (value == '3') {
|
||||
if (value === '3') {
|
||||
topEl.settingEl.hidden = false;
|
||||
btmEl.settingEl.hidden = false;
|
||||
} else {
|
||||
|
|
@ -560,11 +639,11 @@ export class ExportConfigModal extends Modal {
|
|||
});
|
||||
|
||||
const topEl = new Setting(contentEl)
|
||||
.setName('Top/Bottom')
|
||||
.setName('Top/bottom')
|
||||
.addText(text => {
|
||||
setInputWidth(text.inputEl);
|
||||
text
|
||||
.setPlaceholder('margin top')
|
||||
.setPlaceholder('Margin top')
|
||||
.setValue(this.config['marginTop'] as string)
|
||||
.onChange(value => {
|
||||
this.config['marginTop'] = value;
|
||||
|
|
@ -573,19 +652,19 @@ export class ExportConfigModal extends Modal {
|
|||
.addText(text => {
|
||||
setInputWidth(text.inputEl);
|
||||
text
|
||||
.setPlaceholder('margin bottom')
|
||||
.setPlaceholder('Margin bottom')
|
||||
.setValue(this.config['marginBottom'] as string)
|
||||
.onChange(value => {
|
||||
this.config['marginBottom'] = value;
|
||||
});
|
||||
});
|
||||
topEl.settingEl.hidden = this.config['marginType'] != '3';
|
||||
topEl.settingEl.hidden = this.config['marginType'] !== '3';
|
||||
const btmEl = new Setting(contentEl)
|
||||
.setName('Left/Right')
|
||||
.setName('Left/right')
|
||||
.addText(text => {
|
||||
setInputWidth(text.inputEl);
|
||||
text
|
||||
.setPlaceholder('margin left')
|
||||
.setPlaceholder('Margin left')
|
||||
.setValue(this.config['marginLeft'] as string)
|
||||
.onChange(value => {
|
||||
this.config['marginLeft'] = value;
|
||||
|
|
@ -594,15 +673,15 @@ export class ExportConfigModal extends Modal {
|
|||
.addText(text => {
|
||||
setInputWidth(text.inputEl);
|
||||
text
|
||||
.setPlaceholder('margin right')
|
||||
.setPlaceholder('Margin right')
|
||||
.setValue(this.config['marginRight'] as string)
|
||||
.onChange(value => {
|
||||
this.config['marginRight'] = value;
|
||||
});
|
||||
});
|
||||
btmEl.settingEl.hidden = this.config['marginType'] != '3';
|
||||
btmEl.settingEl.hidden = this.config['marginType'] !== '3';
|
||||
|
||||
new Setting(contentEl).setName('Downscale Percent').addSlider(slider => {
|
||||
new Setting(contentEl).setName('Downscale percent').addSlider(slider => {
|
||||
slider
|
||||
.setLimits(0, 100, 1)
|
||||
.setValue(this.config['scale'])
|
||||
|
|
@ -613,14 +692,14 @@ export class ExportConfigModal extends Modal {
|
|||
});
|
||||
new Setting(contentEl).setName('Landscape').addToggle(toggle =>
|
||||
toggle
|
||||
.setTooltip('landscape')
|
||||
.setTooltip('Landscape')
|
||||
.setValue(this.config['landscape'])
|
||||
.onChange(async value => {
|
||||
this.config['landscape'] = value;
|
||||
})
|
||||
);
|
||||
|
||||
new Setting(contentEl).setName('Display Header').addToggle(toggle =>
|
||||
new Setting(contentEl).setName('Display header').addToggle(toggle =>
|
||||
toggle
|
||||
.setTooltip('Display header')
|
||||
.setValue(this.config['displayHeader'])
|
||||
|
|
@ -629,7 +708,7 @@ export class ExportConfigModal extends Modal {
|
|||
})
|
||||
);
|
||||
|
||||
new Setting(contentEl).setName('Display Footer').addToggle(toggle =>
|
||||
new Setting(contentEl).setName('Display footer').addToggle(toggle =>
|
||||
toggle
|
||||
.setTooltip('Display footer')
|
||||
.setValue(this.config['displayFooter'])
|
||||
|
|
@ -650,14 +729,16 @@ export class ExportConfigModal extends Modal {
|
|||
const snippets = this.cssSnippets();
|
||||
|
||||
if (Object.keys(snippets).length > 0 && this.plugin.settings.enabledCss) {
|
||||
new Setting(contentEl).setName('CSS snippets').addDropdown(dropdown => {
|
||||
new Setting(contentEl).setName('Css snippets').addDropdown(dropdown => {
|
||||
dropdown
|
||||
.addOption('0', 'Not select')
|
||||
.addOptions(snippets)
|
||||
.setValue(this.config['cssSnippet'] as string)
|
||||
.onChange(async (value: string) => {
|
||||
this.config['cssSnippet'] = value;
|
||||
await this.appendWebviews(this.previewDiv, false);
|
||||
.onChange((value: string) => {
|
||||
void (async () => {
|
||||
this.config['cssSnippet'] = value;
|
||||
await this.appendWebviews(this.previewDiv, false);
|
||||
})();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
@ -668,22 +749,21 @@ export class ExportConfigModal extends Modal {
|
|||
contentEl.empty();
|
||||
if (this.svelte) {
|
||||
// Remove the Counter from the ItemView.
|
||||
unmount(this.svelte);
|
||||
void unmount(this.svelte);
|
||||
}
|
||||
}
|
||||
|
||||
cssSnippets(): Record<string, string> {
|
||||
// @ts-ignore
|
||||
const { snippets, enabledSnippets } = this.app?.customCss ?? {};
|
||||
// @ts-ignore
|
||||
const basePath = this.app.vault.adapter.basePath;
|
||||
return Object.fromEntries(
|
||||
snippets
|
||||
?.filter((item: string) => !enabledSnippets.has(item))
|
||||
.map((name: string) => {
|
||||
const file = path.join(basePath, this.app.vault.configDir, 'snippets', `${name}.css`);
|
||||
return [file, name];
|
||||
})
|
||||
);
|
||||
const customApp = this.app as unknown as CustomCssApp;
|
||||
const { snippets, enabledSnippets } = customApp.customCss ?? {};
|
||||
const basePath = customApp.vault.adapter.basePath;
|
||||
if (!path || !snippets || !enabledSnippets) return {};
|
||||
const entries = snippets
|
||||
.filter((item: string) => !enabledSnippets.has(item))
|
||||
.map((name: string): [string, string] => {
|
||||
const file = path.join(basePath, this.app.vault.configDir, 'snippets', `${name}.css`);
|
||||
return [file, name];
|
||||
});
|
||||
return Object.fromEntries(entries);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,22 +5,24 @@ import { PatchedSuggester, PreviewInfo, Suggester } from './types';
|
|||
|
||||
export function patchSuggesterWithQuickPreview<T>(
|
||||
plugin: LatexReferencer,
|
||||
suggesterClass: new (...args: unknown[]) => Suggester<T>,
|
||||
suggesterClass: new (plugin: LatexReferencer) => Suggester<T>,
|
||||
itemNormalizer: (item: T) => PreviewInfo | null
|
||||
) {
|
||||
const uninstaller = around(suggesterClass.prototype, {
|
||||
open(old) {
|
||||
open(old: unknown) {
|
||||
const oldFunc = old as (this: unknown) => void;
|
||||
return function (this: PatchedSuggester<T>) {
|
||||
old.call(this);
|
||||
oldFunc.call(this);
|
||||
if (!this.popoverManager) {
|
||||
this.popoverManager = new PopoverManager<T>(plugin, this, itemNormalizer);
|
||||
}
|
||||
this.popoverManager.load();
|
||||
};
|
||||
},
|
||||
close(old) {
|
||||
close(old: unknown) {
|
||||
const oldFunc = old as (this: unknown) => void;
|
||||
return function (this: PatchedSuggester<T>) {
|
||||
old.call(this);
|
||||
oldFunc.call(this);
|
||||
// close() can be called before open() at startup, so we need the optional chaining (?.)
|
||||
this.popoverManager?.unload();
|
||||
};
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import {
|
|||
KeymapEventHandler,
|
||||
PopoverSuggest,
|
||||
SuggestModal,
|
||||
UserEvent,
|
||||
Suggestions
|
||||
} from 'obsidian';
|
||||
|
||||
|
|
@ -105,12 +104,20 @@ export class PopoverManager<T> extends Component {
|
|||
const info = this.itemNormalizer(item);
|
||||
|
||||
if (info) {
|
||||
// @ts-ignore - Using internal API
|
||||
const self = this.plugin.app.internalPlugins.getPluginById('page-preview').instance;
|
||||
// @ts-ignore - Using internal API
|
||||
self.onLinkHover(this.currentHoverParent, this.doc.body, info.linktext, info.sourcePath, {
|
||||
scroll: info.line
|
||||
});
|
||||
const self = this.plugin.app.internalPlugins.getPluginById('page-preview')?.instance as {
|
||||
onLinkHover(
|
||||
parent: unknown,
|
||||
body: HTMLElement,
|
||||
linktext: string,
|
||||
sourcePath: string,
|
||||
state: { scroll?: number }
|
||||
): void;
|
||||
} | null;
|
||||
if (self) {
|
||||
self.onLinkHover(this.currentHoverParent, this.doc.body, info.linktext, info.sourcePath, {
|
||||
scroll: info.line
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { PopoverSuggest, SuggestModal } from 'obsidian';
|
||||
import { PopoverSuggest, SuggestModal, Suggestions, HoverParent } from 'obsidian';
|
||||
import { PopoverManager } from './popoverManager';
|
||||
|
||||
export type Suggester<T> = PopoverSuggest<T> | SuggestModal<T>;
|
||||
|
|
@ -20,6 +20,7 @@ declare module 'obsidian' {
|
|||
|
||||
interface SuggestModal<T> {
|
||||
isOpen: boolean;
|
||||
chooser: Suggestions<T>;
|
||||
}
|
||||
|
||||
interface HoverPopover {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ import {
|
|||
Editor,
|
||||
EditorSuggestContext,
|
||||
Instruction,
|
||||
Notice,
|
||||
Scope,
|
||||
SearchResult,
|
||||
TFile,
|
||||
|
|
@ -13,6 +12,7 @@ import {
|
|||
renderMath,
|
||||
sortSearchResults
|
||||
} from 'obsidian';
|
||||
import { showNotice } from 'utils/obsidian';
|
||||
import LatexReferencer from 'main';
|
||||
import { EquationBlock } from 'types';
|
||||
import { LEAF_OPTION_TO_ARGS } from '../../settings/settings';
|
||||
|
|
@ -51,7 +51,7 @@ export class ActiveNoteSearchCore {
|
|||
const item = this.parent.getSelectedItem();
|
||||
const file = this.app.vault.getAbstractFileByPath(item.$file);
|
||||
if (!(file instanceof TFile)) return;
|
||||
openFileAndSelectPosition(
|
||||
void openFileAndSelectPosition(
|
||||
this.app,
|
||||
file,
|
||||
item.$pos,
|
||||
|
|
@ -86,7 +86,7 @@ export class ActiveNoteSearchCore {
|
|||
async getSuggestions(query: string): Promise<EquationBlock[]> {
|
||||
const blocks = await this.getUnsortedSuggestions();
|
||||
const callback = (
|
||||
this.plugin.settings.searchMethod == 'Fuzzy' ? prepareFuzzySearch : prepareSimpleSearch
|
||||
this.plugin.settings.searchMethod === 'Fuzzy' ? prepareFuzzySearch : prepareSimpleSearch
|
||||
)(query);
|
||||
const results: ScoredEquationBlock[] = [];
|
||||
|
||||
|
|
@ -117,8 +117,8 @@ export class ActiveNoteSearchCore {
|
|||
}
|
||||
|
||||
selectSuggestion(item: EquationBlock, evt: MouseEvent | KeyboardEvent): void {
|
||||
this.selectSuggestionImpl(item);
|
||||
finishRenderMath();
|
||||
void this.selectSuggestionImpl(item);
|
||||
void finishRenderMath();
|
||||
}
|
||||
|
||||
async selectSuggestionImpl(block: EquationBlock): Promise<void> {
|
||||
|
|
@ -140,7 +140,7 @@ export class ActiveNoteSearchCore {
|
|||
{ line: end.line + lineAdded, ch: end.ch }
|
||||
);
|
||||
} else {
|
||||
new Notice(`${this.plugin.manifest.name}: Failed to read cache. Retry again later.`, 5000);
|
||||
showNotice(`${this.plugin.manifest.name}: Failed to read cache. Retry again later.`, 5000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
import { App, Editor, FuzzyMatch, FuzzySuggestModal, Notice } from 'obsidian';
|
||||
import { App, Editor, FuzzyMatch, FuzzySuggestModal } from 'obsidian';
|
||||
import {
|
||||
BUILTIN_TEXT_TRANSFORM_SNIPPETS,
|
||||
runTextTransformSnippet,
|
||||
TextTransformSnippet
|
||||
} from '../../features/snippets/transforms';
|
||||
import { showNotice } from 'utils/obsidian';
|
||||
|
||||
export class TextTransformSuggestModal extends FuzzySuggestModal<TextTransformSnippet> {
|
||||
constructor(
|
||||
|
|
@ -30,9 +31,9 @@ export class TextTransformSuggestModal extends FuzzySuggestModal<TextTransformSn
|
|||
onChooseItem(item: TextTransformSnippet, evt: MouseEvent | KeyboardEvent): void {
|
||||
const result = runTextTransformSnippet(this.editor, item);
|
||||
if (result.changedCount > 0) {
|
||||
new Notice(`Applied ${item.name} to ${result.changedCount} ${result.appliedOn}(s).`);
|
||||
showNotice(`Applied ${item.name} to ${result.changedCount} ${result.appliedOn}(s).`);
|
||||
return;
|
||||
}
|
||||
new Notice(`${item.name} made no changes to the current ${result.appliedOn}.`);
|
||||
showNotice(`${item.name} made no changes to the current ${result.appliedOn}.`);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,9 +29,9 @@ function writeDebugLine(line: string, plugin?: DebugCapablePlugin) {
|
|||
try {
|
||||
const adapter = plugin?.app?.vault?.adapter;
|
||||
if (adapter && typeof adapter.append === 'function') {
|
||||
adapter.append('latex-referencer-debug.log', `${line}\n`);
|
||||
void adapter.append('latex-referencer-debug.log', `${line}\n`);
|
||||
}
|
||||
} catch (_) {
|
||||
} catch {
|
||||
// Best-effort only. Console logging should still work.
|
||||
}
|
||||
}
|
||||
|
|
@ -64,9 +64,9 @@ export function clearDebugLog(plugin?: DebugCapablePlugin) {
|
|||
try {
|
||||
const adapter = plugin?.app?.vault?.adapter;
|
||||
if (adapter && typeof adapter.write === 'function') {
|
||||
adapter.write('latex-referencer-debug.log', '');
|
||||
void adapter.write('latex-referencer-debug.log', '');
|
||||
}
|
||||
} catch (_) {
|
||||
} catch {
|
||||
// Ignore write failures.
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ export class NonActiveNoteIO extends FileIO {
|
|||
}
|
||||
|
||||
async setLine(lineNumber: number, text: string): Promise<void> {
|
||||
this.plugin.app.vault.process(this.file, (data: string): string => {
|
||||
await this.plugin.app.vault.process(this.file, (data: string): string => {
|
||||
const lines = splitIntoLines(data);
|
||||
lines[lineNumber] = text;
|
||||
return lines.join('\n');
|
||||
|
|
@ -77,7 +77,7 @@ export class NonActiveNoteIO extends FileIO {
|
|||
}
|
||||
|
||||
async setRange(position: Pos, text: string): Promise<void> {
|
||||
this.plugin.app.vault.process(this.file, (data: string): string => {
|
||||
await this.plugin.app.vault.process(this.file, (data: string): string => {
|
||||
return (
|
||||
data.slice(0, position.start.offset) +
|
||||
text +
|
||||
|
|
@ -87,7 +87,7 @@ export class NonActiveNoteIO extends FileIO {
|
|||
}
|
||||
|
||||
async insertLine(lineNumber: number, text: string): Promise<void> {
|
||||
this.plugin.app.vault.process(this.file, (data: string): string => {
|
||||
await this.plugin.app.vault.process(this.file, (data: string): string => {
|
||||
const lines = splitIntoLines(data);
|
||||
insertAt(lines, text, lineNumber);
|
||||
return lines.join('\n');
|
||||
|
|
@ -116,7 +116,7 @@ export function getIO(
|
|||
activeMarkdownView?: MarkdownView | null
|
||||
) {
|
||||
activeMarkdownView = activeMarkdownView ?? plugin.app.workspace.getActiveViewOfType(MarkdownView);
|
||||
if (activeMarkdownView && activeMarkdownView.file == file && isEditingView(activeMarkdownView)) {
|
||||
if (activeMarkdownView && activeMarkdownView.file === file && isEditingView(activeMarkdownView)) {
|
||||
return new ActiveNoteIO(plugin, file, activeMarkdownView.editor);
|
||||
}
|
||||
return new NonActiveNoteIO(plugin, file);
|
||||
|
|
|
|||
|
|
@ -58,7 +58,13 @@ export function generateEqId(length: number = 8): string {
|
|||
return result;
|
||||
}
|
||||
|
||||
export function showNotice(message: string): Notice {
|
||||
export function showNotice(message: string, duration?: number): Notice {
|
||||
const NoticeConstructor = Notice;
|
||||
return new NoticeConstructor(message);
|
||||
return new NoticeConstructor(message, duration);
|
||||
}
|
||||
|
||||
export function setCssProps(el: HTMLElement, props: Record<string, string>) {
|
||||
for (const [key, value] of Object.entries(props)) {
|
||||
el.style.setProperty(key, value);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import LatexReferencer from 'main';
|
||||
import { Editor, TFile, CachedMetadata, Notice } from 'obsidian';
|
||||
import LatexReferencer from '../main';
|
||||
import { Editor, TFile, CachedMetadata } from 'obsidian';
|
||||
import { getIO } from './file-io';
|
||||
import { getCalloutPrefix, isStructuralCalloutLine } from './parse';
|
||||
import { EquationBlock } from 'types';
|
||||
import { generateEqId } from './obsidian';
|
||||
import { generateEqId, showNotice } from './obsidian';
|
||||
|
||||
export function insertDisplayMath(editor: Editor) {
|
||||
const cursorPos = editor.getCursor();
|
||||
|
|
@ -41,7 +41,7 @@ export async function insertBlockIdIfNotExist(
|
|||
const insertOffsetInBlock = originalText.lastIndexOf('$$');
|
||||
if (insertOffsetInBlock === -1) {
|
||||
// This should not be reached if the block is a valid math block.
|
||||
new Notice(`${plugin.manifest.name}: Could not find closing $$ in the math block.`);
|
||||
showNotice(`${plugin.manifest.name}: Could not find closing $$ in the math block.`);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -57,7 +57,8 @@ describe('format.ts tests', () => {
|
|||
|
||||
it('getEqNumberPrefix', () => {
|
||||
const dummyApp = {} as App;
|
||||
const dummyFile = {} as TFile;
|
||||
type TempTFile = TFile;
|
||||
const dummyFile = {} as unknown as TempTFile;
|
||||
const settings = {
|
||||
eqNumberPrefix: 'Prefix-'
|
||||
} as unknown;
|
||||
|
|
|
|||
Loading…
Reference in a new issue