From 9b0761813ee42f039f22953046064f97eb852774 Mon Sep 17 00:00:00 2001 From: RyotaUshio Date: Wed, 25 Sep 2024 15:24:24 +0900 Subject: [PATCH] release: 0.40.11 --- manifest-beta.json | 2 +- manifest.json | 2 +- package-lock.json | 4 +-- package.json | 2 +- src/lib/commands.ts | 12 ++++++--- src/lib/copy-link.ts | 32 ++++++++++++++++++++---- src/lib/highlights/extract.ts | 10 +++++--- src/main.ts | 47 +++++++++++++++++++++-------------- src/settings.ts | 29 ++++++++++++--------- 9 files changed, 92 insertions(+), 48 deletions(-) diff --git a/manifest-beta.json b/manifest-beta.json index dd378ffc..06236304 100644 --- a/manifest-beta.json +++ b/manifest-beta.json @@ -1,7 +1,7 @@ { "id": "pdf-plus", "name": "PDF++", - "version": "0.40.10", + "version": "0.40.11", "minAppVersion": "1.5.8", "description": "The most Obsidian-native PDF annotation tool ever.", "author": "Ryota Ushio", diff --git a/manifest.json b/manifest.json index dd378ffc..06236304 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "id": "pdf-plus", "name": "PDF++", - "version": "0.40.10", + "version": "0.40.11", "minAppVersion": "1.5.8", "description": "The most Obsidian-native PDF annotation tool ever.", "author": "Ryota Ushio", diff --git a/package-lock.json b/package-lock.json index 9a441a04..b975d9bf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "obsidian-pdf-plus", - "version": "0.40.10", + "version": "0.40.11", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "obsidian-pdf-plus", - "version": "0.40.10", + "version": "0.40.11", "license": "MIT", "devDependencies": { "@cantoo/pdf-lib": "^1.21.1", diff --git a/package.json b/package.json index 1bdacccc..a521bffd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "obsidian-pdf-plus", - "version": "0.40.10", + "version": "0.40.11", "description": "The most Obsidian-native PDF annotation tool ever.", "scripts": { "dev": "node esbuild.config.mjs", diff --git a/src/lib/commands.ts b/src/lib/commands.ts index 77f5f318..7ae7ed8d 100644 --- a/src/lib/commands.ts +++ b/src/lib/commands.ts @@ -348,7 +348,7 @@ export class PDFPlusCommands extends PDFPlusLibSubmodule { if (!pdfViewer) return false; const el = pdfViewer.dom?.containerEl; - + if (!pdfViewer.isEmbed || (el && el.contains(el.doc.activeElement))) { const sidebar = pdfViewer?.pdfSidebar; if (sidebar) { @@ -882,7 +882,7 @@ export class PDFPlusCommands extends PDFPlusLibSubmodule { const highlights = await this.lib.highlight.extract.getAnnotatedTextsInDocument(doc); highlights.forEach((resultsInPage, pageNumber) => { - resultsInPage.forEach(({ text, rgb }, id) => { + resultsInPage.forEach(({ text, rgb, comment }, id) => { if (data) { data = data.trimEnd() + '\n\n'; } @@ -891,7 +891,11 @@ export class PDFPlusCommands extends PDFPlusLibSubmodule { data += this.lib.copyLink.getTextToCopy( child, template, undefined, file, pageNumber, - `#page=${pageNumber}&annotation=${id}`, text, color + `#page=${pageNumber}&annotation=${id}`, + text, color, undefined, + // We have to get the comment content before calling getTextToCopy and pass it as the last argument. + // See the docstring of getTextToCopy for more details. + comment ); }) }); @@ -986,7 +990,7 @@ export class PDFPlusCommands extends PDFPlusLibSubmodule { const selection = doc.getSelection(); if (!selection || !selection.focusNode || selection.isCollapsed) return false; - + if (!checking) showContextMenuAtSelection(this.plugin, child, selection); return true; diff --git a/src/lib/copy-link.ts b/src/lib/copy-link.ts index 54c8e372..127cb221 100644 --- a/src/lib/copy-link.ts +++ b/src/lib/copy-link.ts @@ -147,14 +147,36 @@ 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) { + /** + * @param child + * @param template + * @param displayTextFormat + * @param file + * @param page + * @param subpath + * @param text + * @param colorName + * @param sourcePath + * @param comment This will be used as the `comment` template variable. + * Assuming the subpath points to an annotation (e.g. `#page=1&annotation=123R`), + * if this parameter is not provided, the comment will be extracted from the annotation layer. + * This means that if the page is not loaded yet (lazy loading), the comment will not be extracted. + * (This is necessary for making this function synchronous.) + * Therefore, you must extract the comment by yourself beforehand and provide it as the `comment` parameter + * if the page may not be loaded yet. + * (See also: https://github.com/RyotaUshio/obsidian-pdf-plus/issues/260) + * @returns + */ + getTextToCopy(child: PDFViewerChild, template: string, displayTextFormat: string | undefined, file: TFile, page: number, subpath: string, text: string, colorName: string, sourcePath?: string, comment?: 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); + if (typeof comment !== 'string') { + const annotationId = subpathToParams(subpath).get('annotation'); + // @ts-ignore + comment = (typeof annotationId === 'string' && pageView?.annotationLayer?.annotationLayer?.getAnnotation(annotationId)?.data?.contentsObj?.str); + comment = this.lib.toSingleLine(comment || ''); + } const processor = new PDFPlusTemplateProcessor(this.plugin, { file, diff --git a/src/lib/highlights/extract.ts b/src/lib/highlights/extract.ts index ee0d3e8f..92fbfd32 100644 --- a/src/lib/highlights/extract.ts +++ b/src/lib/highlights/extract.ts @@ -5,7 +5,7 @@ import { PDFPlusLibSubmodule } from 'lib/submodule'; import { Rect, TextContentItem } from 'typings'; -type AnnotatedTextsInPage = Map; +type AnnotatedTextsInPage = Map; type AnnotatedTextsInDocument = Map; type PDFTextRange = { text: string, from: { index: number, offset: number }, to: { index: number, offset: number } }; @@ -30,7 +30,7 @@ export class HighlightExtractor extends PDFPlusLibSubmodule { page.getAnnotations() ]); - const results: { id: string, textRanges: PDFTextRange[], rgb: RGB | null, left: number, top: number }[] = []; + const results: { id: string, textRanges: PDFTextRange[], rgb: RGB | null, comment?: string, left: number, top: number }[] = []; for (const annot of annots) { const isTextMarkupAnnot = ['Highlight', 'Underline', 'Squiggly', 'StrikeOut'].includes(annot.subtype); @@ -54,9 +54,11 @@ export class HighlightExtractor extends PDFPlusLibSubmodule { const rgb = annot.color ? { r: annot.color[0], g: annot.color[1], b: annot.color[2] } as RGB : null; + const comment = annot.contentsObj?.str; + const firstRect = annot.quadPoints[0]; - results.push({ id: annot.id, textRanges, rgb, left: firstRect[0].x, top: firstRect[0].y }); + results.push({ id: annot.id, textRanges, rgb, comment, left: firstRect[0].x, top: firstRect[0].y }); } return new Map( @@ -74,7 +76,7 @@ export class HighlightExtractor extends PDFPlusLibSubmodule { .map((range) => range.text) .join('\n'); text = this.lib.toSingleLine(text); - return [result.id, { text, rgb: result.rgb }]; + return [result.id, { text, rgb: result.rgb, comment: result.comment }]; }) ); } diff --git a/src/main.ts b/src/main.ts index 00c1eb07..6fbf6ec3 100644 --- a/src/main.ts +++ b/src/main.ts @@ -88,6 +88,7 @@ export default class PDFPlus extends Plugin { await this.loadSettings(); await this.saveSettings(); + this.domManager = this.addChild(new DomManager(this)); this.domManager.registerCalloutRenderer(); @@ -103,8 +104,6 @@ export default class PDFPlus extends Plugin { this.registerGlobalVariables(); - this.registerGlobalDomEvents(); - this.registerEvents(); this.startTrackingActiveMarkdownFile(); @@ -112,6 +111,8 @@ export default class PDFPlus extends Plugin { this.registerObsidianProtocolHandler('pdf-plus', this.obsidianProtocolHandler.bind(this)); this.addSettingTab(this.settingTab = new PDFPlusSettingTab(this)); + + this.registerStyleSettings(); } async onunload() { @@ -139,7 +140,7 @@ export default class PDFPlus extends Plugin { } checkVersion() { - const untestedVersion = '1.7.0'; + const untestedVersion = '1.8.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).`); } @@ -287,6 +288,16 @@ export default class PDFPlus extends Plugin { this.app.saveLocalStorage(this.manifest.id + '-' + key, value); } + /** + * Tell the Style Settings plugin to parse styles.css on load and unload + * so that the Style Settings pane can be updated. + */ + private registerStyleSettings() { + // See https://github.com/mgmeyers/obsidian-style-settings?tab=readme-ov-file#plugin-support + this.app.workspace.trigger('parse-style-settings'); + this.register(() => this.app.workspace.trigger('parse-style-settings')); + } + private registerRibbonIcons() { this.autoCopyMode = new AutoCopyMode(this); this.autoCopyMode.toggle(this.settings.autoCopy); @@ -474,6 +485,21 @@ export default class PDFPlus extends Plugin { } }); + // Make PDF embeds with a subpath unscrollable + if (this.settings.embedUnscrollable) { + for (const eventType of [ + 'wheel', // mousewheel + 'touchmove' // finger swipe + ] as const) { + this.registerDomEvent(embed.containerEl, eventType, (evt) => { + if (isTargetHTMLElement(evt, evt.target) + && evt.target.closest('.pdf-embed[src*="#"] .pdf-viewer-container')) { + evt.preventDefault(); + } + }, { passive: false }); + } + } + if (embed instanceof PDFCroppedEmbed) { this.registerDomEvent(embed.containerEl, 'click', (evt) => { if (isTargetHTMLElement(evt, evt.target) && evt.target.closest('.cm-editor')) { @@ -508,21 +534,6 @@ export default class PDFPlus extends Plugin { this.registerGlobalVariable('pdflib', pdflib, false); } - registerGlobalDomEvent(type: K, callback: (this: HTMLElement, ev: DocumentEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void { - this.lib.registerGlobalDomEvent(this, type, callback, options); - } - - private registerGlobalDomEvents() { - // Make PDF embeds with a subpath unscrollable - this.registerGlobalDomEvent('wheel', (evt) => { - if (this.settings.embedUnscrollable - && isTargetHTMLElement(evt, evt.target) - && evt.target.closest('.pdf-embed[src*="#"] .pdf-viewer-container')) { - evt.preventDefault(); - } - }, { passive: false }); - } - private registerEvents() { // keep this.pdfViewerChildren up-to-date this.registerEvent(this.app.workspace.on('layout-change', () => { diff --git a/src/settings.ts b/src/settings.ts index 5b50d033..7b98b297 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -1450,11 +1450,15 @@ export class PDFPlusSettingTab extends PluginSettingTab { this.component.load(); + // Show which section is currently being displayed by highlighting the corresponding icon in the header. activeWindow.setTimeout(() => this.updateHeaderElClass()); - this.component.registerDomEvent( - this.contentEl, 'wheel', - debounce(() => this.updateHeaderElClass(), 100) - ); + for (const eventType of ['wheel', 'touchmove'] as const) { + this.component.registerDomEvent( + this.contentEl, eventType, + debounce(() => this.updateHeaderElClass(), 100), + { passive: true } + ); + } this.contentEl.createDiv('top-note', async (el) => { @@ -2396,7 +2400,7 @@ export class PDFPlusSettingTab extends PluginSettingTab { }) .then((setting) => { if (this.plugin.requireModKeyForLinkHover(PDFInternalLinkPostProcessor.HOVER_LINK_SOURCE_ID)) setting.setDesc(`You may want to turn this off to avoid conflicts with hover+${modKey}.`); - setting.descEl.appendText('Reopen the tabs or reload the app after changing this option.'); + setting.descEl.appendText('Reopen tabs or reload the app after changing this option.'); }); this.addToggleSetting('enableHoverPDFInternalLink', () => this.events.trigger('update')) .setName(`Show a popover preview of PDF internal links by hover(+${modKey})`); @@ -2526,18 +2530,18 @@ export class PDFPlusSettingTab extends PluginSettingTab { }) .then((setting) => { if (this.plugin.requireModKeyForLinkHover(PDFOutlineItemPostProcessor.HOVER_LINK_SOURCE_ID)) setting.setDesc(`You may want to turn this off to avoid conflicts with hover+${modKey}.`); - setting.descEl.appendText('Reopen the tabs or reload the app after changing this option.'); + setting.descEl.appendText('Reopen tabs or reload the app after changing this option.'); }); this.addToggleSetting('popoverPreviewOnOutlineHover', () => this.events.trigger('update')) .setName(`Show popover preview by hover(+${modKey})`) - .setDesc('Reopen the tabs or reload the app after changing this option.'); + .setDesc('Reopen tabs or reload the app after changing this option.'); this.showConditionally( this.addRequireModKeyOnHoverSetting(PDFOutlineItemPostProcessor.HOVER_LINK_SOURCE_ID), () => this.plugin.settings.popoverPreviewOnOutlineHover ); this.addToggleSetting('recordHistoryOnOutlineClick') .setName('Record to history when clicking an outline item') - .setDesc('Reopen the tabs or reload the app after changing this option.'); + .setDesc('Reopen tabs or reload the app after changing this option.'); this.addToggleSetting('outlineContextMenu') .setName('Replace the built-in context menu in the outline with a custom one') .setDesc('This enables you to insert a section link with a custom format by right-clicking an item in the outline. Moreover, you will be able to add, rename, or delete outline items if PDF modification is enabled.') @@ -2604,18 +2608,18 @@ export class PDFPlusSettingTab extends PluginSettingTab { }) .then((setting) => { if (this.plugin.requireModKeyForLinkHover(PDFThumbnailItemPostProcessor.HOVER_LINK_SOURCE_ID)) setting.setDesc(`You may want to turn this off to avoid conflicts with hover+${modKey}`); - setting.descEl.appendText('Reopen the tabs or reload the app after changing this option.'); + setting.descEl.appendText('Reopen tabs or reload the app after changing this option.'); }); this.addToggleSetting('popoverPreviewOnThumbnailHover', () => this.events.trigger('update')) .setName(`Show popover preview by hover(+${modKey})`) - .setDesc('Reopen the tabs or reload the app after changing this option.'); + .setDesc('Reopen tabs or reload the app after changing this option.'); this.showConditionally( this.addRequireModKeyOnHoverSetting(PDFThumbnailItemPostProcessor.HOVER_LINK_SOURCE_ID), () => this.plugin.settings.popoverPreviewOnThumbnailHover ) this.addToggleSetting('recordHistoryOnThumbnailClick') .setName('Record to history when clicking a thumbnail') - .setDesc('Reopen the tabs or reload the app after changing this option.'); + .setDesc('Reopen tabs or reload the app after changing this option.'); this.addToggleSetting('thumbnailContextMenu') .setName('Replace the built-in context menu in thumbnails with a custom one') .setDesc('This enables you to copy a page link with a custom display text format specified in the PDF toolbar by right-clicking a thumbnail. Moreover, you will be able to insert, delete, extract pages if PDF modification is enabled.'); @@ -2815,7 +2819,8 @@ export class PDFPlusSettingTab extends PluginSettingTab { this.addToggleSetting('persistentAnnotationHighlightsInEmbed') .setName('Don\'t clear highlights in an annotation embeds'); this.addToggleSetting('embedUnscrollable') - .setName('Make PDF embeds with a page specified unscrollable'); + .setName('Make PDF embeds with a page specified unscrollable') + .setDesc('After changing this option, you need to reopen tabs or reload the app.'); this.addHeading('Backlinks pane for PDF files', 'backlink-view', 'links-coming-in')