Skip to content

Commit

Permalink
release: 0.40.8
Browse files Browse the repository at this point in the history
  • Loading branch information
RyotaUshio committed Jun 15, 2024
1 parent d9f9d20 commit 7286944
Show file tree
Hide file tree
Showing 15 changed files with 273 additions and 131 deletions.
2 changes: 1 addition & 1 deletion manifest-beta.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"id": "pdf-plus",
"name": "PDF++",
"version": "0.40.7",
"version": "0.40.8",
"minAppVersion": "1.5.8",
"description": "The most Obsidian-native PDF annotation tool ever.",
"author": "Ryota Ushio",
Expand Down
2 changes: 1 addition & 1 deletion manifest.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"id": "pdf-plus",
"name": "PDF++",
"version": "0.40.7",
"version": "0.40.8",
"minAppVersion": "1.5.8",
"description": "The most Obsidian-native PDF annotation tool ever.",
"author": "Ryota Ushio",
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "obsidian-pdf-plus",
"version": "0.40.7",
"version": "0.40.8",
"description": "The most Obsidian-native PDF annotation tool ever.",
"scripts": {
"dev": "node esbuild.config.mjs",
Expand Down
128 changes: 81 additions & 47 deletions src/bib.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,42 +40,33 @@ export class BibliographyManager extends PDFPlusComponent {

isEnabled() {
const viewer = this.child.pdfViewer;
return isNonEmbedLike(viewer)
|| (this.settings.enableBibInCanvas && isCanvas(viewer))
|| (this.settings.enableBibInHoverPopover && isHoverPopover(viewer))
|| (this.settings.enableBibInEmbed && isEmbed(viewer));
return this.settings.actionOnCitationHover !== 'none'
&& (
isNonEmbedLike(viewer)
|| (this.settings.enableBibInCanvas && isCanvas(viewer))
|| (this.settings.enableBibInHoverPopover && isHoverPopover(viewer))
|| (this.settings.enableBibInEmbed && isEmbed(viewer))
);
}

private async init() {
if (this.isEnabled()) {
await this.initBibText();
await this.extractBibText();
await this.parseBibText();
}
this.initialized = true;
}

private async initBibText() {
private async extractBibText() {
return new Promise<void>((resolve) => {
this.lib.onDocumentReady(this.child.pdfViewer, async (doc) => {
const dests = await doc.getDestinations();
const promises: Promise<void>[] = [];
for (const destId in dests) {
if (destId.startsWith('cite.')) {
const destArray = dests[destId] as PDFJsDestArray;
promises.push(
BibliographyManager.getBibliographyTextFromDest(destArray, doc)
.then((bibInfo) => {
if (bibInfo) {
const bibText = bibInfo.text;
this.destIdToBibText.set(destId, bibText);
this.events.trigger('extracted', destId, bibText);
}
})
);
}
}
await Promise.all(promises);
resolve();
this.lib.onDocumentReady(this.child.pdfViewer, (doc) => {
new BibliographyTextExtractor(doc)
.onExtracted((destId, bibText) => {
this.destIdToBibText.set(destId, bibText);
this.events.trigger('extracted', destId, bibText);
})
.extract()
.then(resolve);
});
});
}
Expand Down Expand Up @@ -209,34 +200,83 @@ export class BibliographyManager extends PDFPlusComponent {
return null;
}

static async getBibliographyTextFromDest(dest: string | PDFJsDestArray, doc: PDFDocumentProxy) {
let explicitDest: PDFJsDestArray | null = null;
if (typeof dest === 'string') {
explicitDest = (await doc.getDestination(dest)) as PDFJsDestArray | null;
} else {
explicitDest = dest;

on(name: 'extracted', callback: (destId: string, bibText: string) => any, ctx?: any): ReturnType<Events['on']>;
on(name: 'parsed', callback: (destId: string, parsedBib: string) => any, ctx?: any): ReturnType<Events['on']>;
on(...args: Parameters<Events['on']>) {
return this.events.on(...args);
}
}


class BibliographyTextExtractor {
doc: PDFDocumentProxy;
pageRefToTextContentItemsPromise: Record<string, Promise<TextContentItem[]> | undefined>;
onExtractedCallback: (destId: string, bibText: string) => any;

constructor(doc: PDFDocumentProxy) {
this.doc = doc;
this.pageRefToTextContentItemsPromise = {};
}

onExtracted(callback: BibliographyTextExtractor['onExtractedCallback']) {
this.onExtractedCallback = callback;
return this;
}

async extract() {
const dests = await this.doc.getDestinations();
const promises: Promise<void>[] = [];
for (const destId in dests) {
if (destId.startsWith('cite.')) {
const destArray = dests[destId] as PDFJsDestArray;
promises.push(
this.extractBibTextForDest(destArray)
.then((bibInfo) => {
if (bibInfo) {
const bibText = bibInfo.text;
this.onExtractedCallback(destId, bibText);
}
})
);
}
}
if (!explicitDest) return null;
await Promise.all(promises);
}

const pageNumber = await doc.getPageIndex(explicitDest[0]) + 1;
const page = await doc.getPage(pageNumber);
const items = (await page.getTextContent()).items as TextContentItem[];
/** Get `TextContentItem`s contained in the specified page. This method avoids fetching the same info multiple times. */
async getTextContentItemsFromPageRef(pageRef: PDFJsDestArray[0]) {
const refStr = JSON.stringify(pageRef);

return this.pageRefToTextContentItemsPromise[refStr] ?? (
this.pageRefToTextContentItemsPromise[refStr] = (async () => {
const pageNumber = await this.doc.getPageIndex(pageRef) + 1;
const page = await this.doc.getPage(pageNumber);
const items = (await page.getTextContent()).items as TextContentItem[];
return items;
})()
);
}

async extractBibTextForDest(destArray: PDFJsDestArray) {
const pageRef = destArray[0];
const items = await this.getTextContentItemsFromPageRef(pageRef);

// Whole lotta hand-crafted rules LOL

let beginIndex = -1;
if (explicitDest[1].name === 'XYZ') {
const left = explicitDest[2];
const top = explicitDest[3];
if (destArray[1].name === 'XYZ') {
const left = destArray[2];
const top = destArray[3];
if (left === null || top === null) return null;
beginIndex = items.findIndex((item: TextContentItem) => {
if (!item.str) return false;
const itemLeft = item.transform[4];
const itemTop = item.transform[5] + (item.height || item.transform[0]) * 0.8;
return left <= itemLeft && itemTop <= top;
});
} else if (explicitDest[1].name === 'FitBH') {
const top = explicitDest[2];
} else if (destArray[1].name === 'FitBH') {
const top = destArray[2];
if (top === null) return null;
beginIndex = items.findIndex((item: TextContentItem) => {
if (!item.str) return false;
Expand Down Expand Up @@ -280,12 +320,6 @@ export class BibliographyManager extends PDFPlusComponent {

return { text: toSingleLine(text), items: bibTextItems };
}

on(name: 'extracted', callback: (destId: string, bibText: string) => any, ctx?: any): ReturnType<Events['on']>;
on(name: 'parsed', callback: (destId: string, parsedBib: string) => any, ctx?: any): ReturnType<Events['on']>;
on(...args: Parameters<Events['on']>) {
return this.events.on(...args);
}
}


Expand Down
44 changes: 28 additions & 16 deletions src/lib/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -344,20 +344,27 @@ export class PDFPlusCommands extends PDFPlusLibSubmodule {
}

showOutline(checking: boolean) {
const sidebar = this.lib.getObsidianViewer(true)?.pdfSidebar;
if (sidebar) {
if (!sidebar.haveOutline) return false;
if (sidebar.isOpen && sidebar.active === 2) {
if (this.settings.closeSidebarWithShowCommandIfExist) {
if (!checking) sidebar.close();
return true;
const pdfViewer = this.lib.getObsidianViewer(true);
if (!pdfViewer) return false;

const el = pdfViewer.dom?.containerEl;

if (!pdfViewer.isEmbed || (el && el.contains(el.doc.activeElement))) {
const sidebar = pdfViewer?.pdfSidebar;
if (sidebar) {
if (!sidebar.haveOutline) return false;
if (sidebar.isOpen && sidebar.active === 2) {
if (this.settings.closeSidebarWithShowCommandIfExist) {
if (!checking) sidebar.close();
return true;
}
return false;
}
return false;
}
if (!checking) {
sidebar.switchView(SidebarView.OUTLINE, true);
if (!checking) {
sidebar.switchView(SidebarView.OUTLINE, true);
}
return true;
}
return true;
}

if (this.settings.executeBuiltinCommandForOutline) {
Expand Down Expand Up @@ -408,11 +415,16 @@ export class PDFPlusCommands extends PDFPlusLibSubmodule {

zoom(checking: boolean, zoomIn: boolean) {
const pdfViewer = this.lib.getObsidianViewer(true);
if (pdfViewer) {
if (!checking) {
zoomIn ? pdfViewer.zoomIn() : pdfViewer.zoomOut();
if (!pdfViewer) return false;

const el = pdfViewer.dom?.containerEl;
if (!pdfViewer.isEmbed || (el && el.contains(el.doc.activeElement))) {
if (pdfViewer) {
if (!checking) {
zoomIn ? pdfViewer.zoomIn() : pdfViewer.zoomOut();
}
return true;
}
return true;
}

if (this.settings.executeFontSizeAdjusterCommand) {
Expand Down
20 changes: 14 additions & 6 deletions src/lib/copy-link.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Editor, EditorRange, MarkdownFileInfo, MarkdownView, Notice, TFile } fr

import { PDFPlusLibSubmodule } from './submodule';
import { PDFPlusTemplateProcessor } from 'template';
import { encodeLinktext, getOffsetInTextLayerNode, getTextLayerNode, paramsToSubpath, parsePDFSubpath } from 'utils';
import { encodeLinktext, getOffsetInTextLayerNode, getTextLayerNode, paramsToSubpath, parsePDFSubpath, subpathToParams } from 'utils';
import { Canvas, PDFOutlineTreeNode, PDFViewerChild, Rect } from 'typings';
import { ColorPalette } from 'color-palette';

Expand Down Expand Up @@ -93,14 +93,14 @@ export class copyLinkLib extends PDFPlusLibSubmodule {
};
}

getLinkTemplateVariables(child: PDFViewerChild, displayTextFormat: string | undefined, file: TFile, subpath: string, page: number, text: string, sourcePath?: string) {
getLinkTemplateVariables(child: PDFViewerChild, displayTextFormat: string | undefined, file: TFile, subpath: string, page: number, text: string, comment: string, sourcePath?: string) {
sourcePath = sourcePath ?? '';
const link = this.app.fileManager.generateMarkdownLink(file, sourcePath, subpath).slice(1);
let linktext = this.app.metadataCache.fileToLinktext(file, sourcePath) + subpath;
if (this.app.vault.getConfig('useMarkdownLinks')) {
linktext = encodeLinktext(linktext);
}
const display = this.getDisplayText(child, displayTextFormat, file, page, text);
const display = this.getDisplayText(child, displayTextFormat, file, page, text, comment);
// https://github.com/obsidianmd/obsidian-api/issues/154
// const linkWithDisplay = app.fileManager.generateMarkdownLink(file, sourcePath, subpath, display).slice(1);
const linkWithDisplay = this.lib.generateMarkdownLink(file, sourcePath, subpath, display || undefined).slice(1);
Expand All @@ -120,7 +120,7 @@ export class copyLinkLib extends PDFPlusLibSubmodule {
};
}

getDisplayText(child: PDFViewerChild, displayTextFormat: string | undefined, file: TFile, page: number, text: string) {
getDisplayText(child: PDFViewerChild, displayTextFormat: string | undefined, file: TFile, page: number, text: string, comment?: string) {
if (!displayTextFormat) {
// read display text format from color palette
const palette = this.lib.getColorPaletteFromChild(child);
Expand All @@ -137,7 +137,8 @@ export class copyLinkLib extends PDFPlusLibSubmodule {
page,
pageCount: child.pdfViewer.pagesCount,
pageLabel: child.getPage(page).pageLabel ?? ('' + page),
text
text,
comment: comment ?? '',
}).evalTemplate(displayTextFormat)
.trim();
} catch (err) {
Expand All @@ -149,15 +150,22 @@ export class copyLinkLib extends PDFPlusLibSubmodule {
getTextToCopy(child: PDFViewerChild, template: string, displayTextFormat: string | undefined, file: TFile, page: number, subpath: string, text: string, colorName: string, sourcePath?: string) {
const pageView = child.getPage(page);

// need refactor
const annotationId = subpathToParams(subpath).get('annotation');
// @ts-ignore
let comment: string = (typeof annotationId === 'string' && pageView?.annotationLayer?.annotationLayer?.getAnnotation(annotationId)?.data?.contentsObj?.str) || '';
comment = this.lib.toSingleLine(comment);

const processor = new PDFPlusTemplateProcessor(this.plugin, {
file,
page,
pageLabel: pageView.pageLabel ?? ('' + page),
pageCount: child.pdfViewer.pagesCount,
text,
comment,
colorName,
calloutType: this.settings.calloutType,
...this.lib.copyLink.getLinkTemplateVariables(child, displayTextFormat, file, subpath, page, text, sourcePath)
...this.lib.copyLink.getLinkTemplateVariables(child, displayTextFormat, file, subpath, page, text, comment, sourcePath)
});

const evaluated = processor.evalTemplate(template);
Expand Down
3 changes: 3 additions & 0 deletions src/lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { AnnotationElement, CanvasFileNode, CanvasNode, CanvasView, DestArray, E
import { PDFCroppedEmbed } from 'pdf-cropped-embed';
import { PDFBacklinkIndex } from './pdf-backlink-index';
import { Speech } from './speech';
import * as utils from 'utils';


export class PDFPlusLib {
Expand All @@ -38,6 +39,8 @@ export class PDFPlusLib {
composer: PDFComposer;
speech: Speech;

utils = utils;

constructor(plugin: PDFPlus) {
this.app = plugin.app;
this.plugin = plugin;
Expand Down
12 changes: 4 additions & 8 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,11 @@ import { ColorPalette } from 'color-palette';
import { DomManager } from 'dom-manager';
import { PDFCroppedEmbed } from 'pdf-cropped-embed';
import { DEFAULT_SETTINGS, PDFPlusSettings, PDFPlusSettingTab } from 'settings';
import { subpathToParams, OverloadParameters, focusObsidian, isTargetHTMLElement, getInstallerVersion, isVersionOlderThan } from 'utils';
import { subpathToParams, OverloadParameters, focusObsidian, isTargetHTMLElement } from 'utils';
import { DestArray, ObsidianViewer, PDFEmbed, PDFView, PDFViewerChild, PDFViewerComponent, Rect } from 'typings';
import { ExternalPDFModal } from 'modals';
import { ExternalPDFModal, InstallerVersionModal } from 'modals';
import { PDFExternalLinkPostProcessor, PDFInternalLinkPostProcessor, PDFOutlineItemPostProcessor, PDFThumbnailItemPostProcessor } from 'post-process';
import { BibliographyManager } from 'bib';
import { InstallerVersionModal } from 'modals/installer-version-modal';


export default class PDFPlus extends Plugin {
Expand Down Expand Up @@ -130,16 +129,13 @@ export default class PDFPlus extends Plugin {
}
}

private checkVersion() {
checkVersion() {
const untestedVersion = '1.7.0';
if (requireApiVersion(untestedVersion)) {
console.warn(`${this.manifest.name}: This plugin has not been tested on Obsidian ${untestedVersion} or above. Please report any issue you encounter on GitHub (https://github.com/RyotaUshio/obsidian-pdf-plus/issues/new/choose).`);
}

const installerVersion = getInstallerVersion();
if (installerVersion && isVersionOlderThan(installerVersion, '1.5.8')) {
new InstallerVersionModal(this).open();
}
InstallerVersionModal.openIfNecessary(this);
}

private addIcons() {
Expand Down
1 change: 1 addition & 0 deletions src/modals/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ export * from './pdf-composer-modals';
export * from './outline-modals';
export * from './page-label-modals';
export * from './external-pdf-modals';
export * from './installer-version-modal';
Loading

0 comments on commit 7286944

Please sign in to comment.