Skip to content

Commit d24c9d9

Browse files
committed
release: 0.40.14
1 parent 22d47ce commit d24c9d9

17 files changed

+216
-100
lines changed

manifest-beta.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"id": "pdf-plus",
33
"name": "PDF++",
4-
"version": "0.40.13",
4+
"version": "0.40.14",
55
"minAppVersion": "1.5.8",
66
"description": "The most Obsidian-native PDF annotation tool ever.",
77
"author": "Ryota Ushio",

manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"id": "pdf-plus",
33
"name": "PDF++",
4-
"version": "0.40.13",
4+
"version": "0.40.14",
55
"minAppVersion": "1.5.8",
66
"description": "The most Obsidian-native PDF annotation tool ever.",
77
"author": "Ryota Ushio",

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "obsidian-pdf-plus",
3-
"version": "0.40.13",
3+
"version": "0.40.14",
44
"description": "The most Obsidian-native PDF annotation tool ever.",
55
"scripts": {
66
"dev": "node esbuild.config.mjs",

src/backlink-visualizer.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import PDFPlus from 'main';
44
import { PDFPlusComponent } from 'lib/component';
55
import { PDFBacklinkCache, PDFBacklinkIndex, PDFPageBacklinkIndex } from 'lib/pdf-backlink-index';
66
import { PDFPageView, PDFViewerChild, Rect } from 'typings';
7-
import { MultiValuedMap, isCanvas, isEmbed, isHoverPopover, isMouseEventExternal, isNonEmbedLike } from 'utils';
7+
import { MultiValuedMap, getTextLayerInfo, isCanvas, isEmbed, isHoverPopover, isMouseEventExternal, isNonEmbedLike } from 'utils';
88
import { onBacklinkVisualizerContextMenu } from 'context-menu';
99
import { BidirectionalMultiValuedMap } from 'utils';
1010
import { MergedRect } from 'lib/highlights/geometry';
@@ -294,9 +294,10 @@ export class RectangleCache extends PDFPlusComponent {
294294

295295
const textLayer = pageView.textLayer;
296296
if (!textLayer) return null;
297-
if (!textLayer.textDivs.length) return null;
297+
const textLayerInfo = getTextLayerInfo(textLayer);
298+
if (!textLayerInfo.textDivs.length) return null;
298299

299-
const rects = this.lib.highlight.geometry.computeMergedHighlightRects(textLayer, beginIndex, beginOffset, endIndex, endOffset);
300+
const rects = this.lib.highlight.geometry.computeMergedHighlightRects(textLayerInfo, beginIndex, beginOffset, endIndex, endOffset);
300301
return rects;
301302
}
302303
}
@@ -407,7 +408,8 @@ export class PDFViewerBacklinkVisualizer extends PDFBacklinkVisualizer implement
407408

408409
const textLayer = pageView.textLayer;
409410
if (!textLayer) return;
410-
if (!textLayer.textDivs.length) return;
411+
const { textDivs } = getTextLayerInfo(textLayer);
412+
if (!textDivs.length) return;
411413

412414
const rects = this.rectangleCache.getRectsForSelection(pageNumber, id);
413415
if (!rects) return;
@@ -417,7 +419,7 @@ export class PDFViewerBacklinkVisualizer extends PDFBacklinkVisualizer implement
417419
rectEl.addClasses(['pdf-plus-backlink', 'pdf-plus-backlink-selection']);
418420

419421
// font-size is used to set the padding of this highlight in em unit
420-
const textDiv = textLayer.textDivs[indices[0]];
422+
const textDiv = textDivs[indices[0]];
421423
rectEl.setCssStyles({
422424
fontSize: textDiv.style.fontSize
423425
});

src/lib/copy-link.ts

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { Editor, EditorRange, MarkdownFileInfo, MarkdownView, Notice, TFile } fr
22

33
import { PDFPlusLibSubmodule } from './submodule';
44
import { PDFPlusTemplateProcessor } from 'template';
5-
import { encodeLinktext, getOffsetInTextLayerNode, getTextLayerNode, paramsToSubpath, parsePDFSubpath, subpathToParams } from 'utils';
5+
import { encodeLinktext, getOffsetInTextLayerNode, getTextLayerInfo, getTextLayerNode, paramsToSubpath, parsePDFSubpath, subpathToParams } from 'utils';
66
import { Canvas, PDFOutlineTreeNode, PDFViewerChild, Rect } from 'typings';
77
import { ColorPalette } from 'color-palette';
88

@@ -76,9 +76,12 @@ export class copyLinkLib extends PDFPlusLibSubmodule {
7676
page = child.pdfViewer.pdfViewer?.currentPageNumber ?? page;
7777
}
7878

79+
const selectionStr = child.getTextSelectionRangeStr(pageEl);
80+
if (!selectionStr) return null;
81+
7982
const subpath = paramsToSubpath({
8083
page,
81-
selection: child.getTextSelectionRangeStr(pageEl),
84+
selection: selectionStr,
8285
...subpathParams
8386
});
8487

@@ -283,12 +286,16 @@ export class copyLinkLib extends PDFPlusLibSubmodule {
283286
// TODO: Needs refactor
284287
const result = parsePDFSubpath(subpath);
285288
if (result && 'beginIndex' in result) {
286-
const item = child.getPage(page).textLayer?.textContentItems[result.beginIndex];
287-
if (item) {
288-
const left = item.transform[4];
289-
const top = item.transform[5] + item.height;
290-
if (typeof left === 'number' && typeof top === 'number') {
291-
this.plugin.lastCopiedDestInfo = { file, destArray: [page - 1, 'XYZ', left, top, null] };
289+
const textLayer = child.getPage(page).textLayer;
290+
if (textLayer) {
291+
const { textContentItems } = getTextLayerInfo(textLayer);
292+
const item = textContentItems[result.beginIndex];
293+
if (item) {
294+
const left = item.transform[4];
295+
const top = item.transform[5] + item.height;
296+
if (typeof left === 'number' && typeof top === 'number') {
297+
this.plugin.lastCopiedDestInfo = { file, destArray: [page - 1, 'XYZ', left, top, null] };
298+
}
292299
}
293300
}
294301
}

src/lib/highlights/geometry.ts

Lines changed: 28 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { PDFPlusLibSubmodule } from 'lib/submodule';
2-
import { PropRequired } from 'utils';
2+
import { getNodeAndOffsetOfTextPos, PropRequired } from 'utils';
33
import { TextLayerBuilder, Rect, TextContentItem } from 'typings';
44

55

@@ -12,8 +12,8 @@ export class HighlightGeometryLib extends PDFPlusLibSubmodule {
1212
* Each rectangle is obtained by merging the rectangles of the text content items contained in the selection, when possible (typically when the text selection is within a single line).
1313
* Each rectangle is associated with an array of indices of the text content items contained in the rectangle.
1414
*/
15-
computeMergedHighlightRects(textLayer: TextLayerBuilder, beginIndex: number, beginOffset: number, endIndex: number, endOffset: number): MergedRect[] {
16-
const { textContentItems, textDivs, div } = textLayer;
15+
computeMergedHighlightRects(textLayer: { textDivs: HTMLElement[], textContentItems: TextContentItem[] }, beginIndex: number, beginOffset: number, endIndex: number, endOffset: number): MergedRect[] {
16+
const { textContentItems, textDivs } = textLayer;
1717

1818
const results: MergedRect[] = [];
1919

@@ -34,7 +34,7 @@ export class HighlightGeometryLib extends PDFPlusLibSubmodule {
3434
if (!item.str) continue;
3535

3636
// the minimum rectangle that contains all the chars of this text content item
37-
const rect = this.computeHighlightRectForItem(div, item, textDiv, index, beginIndex, beginOffset, endIndex, endOffset);
37+
const rect = this.computeHighlightRectForItem(item, textDiv, index, beginIndex, beginOffset, endIndex, endOffset);
3838
if (!rect) continue;
3939

4040
if (!mergedRect) {
@@ -59,13 +59,13 @@ export class HighlightGeometryLib extends PDFPlusLibSubmodule {
5959
return results;
6060
}
6161

62-
computeHighlightRectForItem(textLayerDiv: HTMLElement, item: TextContentItem, textDiv: HTMLElement, index: number, beginIndex: number, beginOffset: number, endIndex: number, endOffset: number): Rect | null {
62+
computeHighlightRectForItem(item: TextContentItem, textDiv: HTMLElement, index: number, beginIndex: number, beginOffset: number, endIndex: number, endOffset: number): Rect | null {
6363
// If the item has the `chars` property filled, use it to get the bounding rectangle of each character in the item.
6464
if (item.chars && item.chars.length >= item.str.length) {
6565
return this.computeHighlightRectForItemFromChars(item as PropRequired<TextContentItem, 'chars'>, index, beginIndex, beginOffset, endIndex, endOffset);
6666
}
6767
// Otherwise, use the text layer divs to get the bounding rectangle of the text selection.
68-
return this.computeHighlightRectForItemFromTextLayer(textLayerDiv, item, textDiv, index, beginIndex, beginOffset, endIndex, endOffset);
68+
return this.computeHighlightRectForItemFromTextLayer(item, textDiv, index, beginIndex, beginOffset, endIndex, endOffset);
6969
}
7070

7171
computeHighlightRectForItemFromChars(item: PropRequired<TextContentItem, 'chars'>, index: number, beginIndex: number, beginOffset: number, endIndex: number, endOffset: number): Rect | null {
@@ -92,40 +92,40 @@ export class HighlightGeometryLib extends PDFPlusLibSubmodule {
9292
];
9393
}
9494

95-
// Inspired by PDFViewerChild.prototype.hightlightText from Obsidian's app.js
96-
computeHighlightRectForItemFromTextLayer(textLayerDiv: HTMLElement, item: TextContentItem, textDiv: HTMLElement, index: number, beginIndex: number, beginOffset: number, endIndex: number, endOffset: number): Rect | null {
97-
const offsetFrom = index === beginIndex ? beginOffset : 0;
98-
// `endOffset` is computed from the `endOffset` property (https://developer.mozilla.org/en-US/docs/Web/API/Range/endOffset)
99-
// of the `Range` contained in the selection, which is the number of characters from the start of the `Range` to its end.
100-
// Therefore, `endOffset` is 1 greater than the index of the last character in the selection.
101-
const offsetTo = index === endIndex ? endOffset : undefined;
102-
95+
computeHighlightRectForItemFromTextLayer(item: TextContentItem, textDiv: HTMLElement, index: number, beginIndex: number, beginOffset: number, endIndex: number, endOffset: number): Rect | null {
10396
// the bounding box of the whole text content item
10497
const x1 = item.transform[4];
10598
const y1 = item.transform[5];
10699
const x2 = item.transform[4] + item.width;
107100
const y2 = item.transform[5] + item.height;
108101

109-
const textDivCopied = textDiv.cloneNode() as HTMLElement;
110-
textLayerDiv.appendChild(textDivCopied);
111-
112-
const textBefore = item.str.substring(0, offsetFrom);
113-
textDivCopied.appendText(textBefore);
102+
const range = textDiv.doc.createRange();
114103

115-
const text = item.str.substring(offsetFrom, offsetTo);
116-
const boundingEl = textDivCopied.createSpan();
117-
boundingEl.appendText(text);
104+
if (index === beginIndex) {
105+
const posFrom = getNodeAndOffsetOfTextPos(textDiv, beginOffset);
106+
if (posFrom) {
107+
range.setStart(posFrom.node, posFrom.offset);
108+
} else {
109+
range.setStartBefore(textDiv);
110+
}
111+
} else {
112+
range.setStartBefore(textDiv);
113+
}
118114

119-
if (offsetTo !== undefined) {
120-
const textAfter = item.str.substring(offsetTo);
121-
textDivCopied.appendText(textAfter);
115+
if (index === endIndex) {
116+
const posTo = getNodeAndOffsetOfTextPos(textDiv, endOffset);
117+
if (posTo) {
118+
range.setEnd(posTo.node, posTo.offset);
119+
} else {
120+
range.setEndAfter(textDiv);
121+
}
122+
} else {
123+
range.setEndAfter(textDiv);
122124
}
123125

124-
const rect = boundingEl.getBoundingClientRect();
126+
const rect = range.getBoundingClientRect();
125127
const parentRect = textDiv.getBoundingClientRect();
126128

127-
textDivCopied.remove();
128-
129129
return [
130130
x1 + (rect.left - parentRect.left) / parentRect.width * item.width,
131131
y1 + (rect.bottom - parentRect.bottom) / parentRect.height * item.height,

src/lib/highlights/write-file/index.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { Notice, TFile } from 'obsidian';
33
import PDFPlus from 'main';
44
import { PdfLibIO } from './pdf-lib';
55
import { PDFPlusLibSubmodule } from 'lib/submodule';
6-
import { parsePDFSubpath } from 'utils';
6+
import { getTextLayerInfo, parsePDFSubpath } from 'utils';
77
import { DestArray, PDFViewerChild, Rect } from 'typings';
88

99

@@ -63,7 +63,8 @@ export class AnnotationWriteFileLib extends PDFPlusLibSubmodule {
6363
if (1 <= pageNumber && pageNumber <= child.pdfViewer.pagesCount) {
6464
const pageView = child.getPage(pageNumber);
6565
if (pageView?.textLayer && pageView.div.dataset.loaded) {
66-
const results = this.lib.highlight.geometry.computeMergedHighlightRects(pageView.textLayer, beginIndex, beginOffset, endIndex, endOffset);
66+
const textLayerInfo = getTextLayerInfo(pageView.textLayer);
67+
const results = this.lib.highlight.geometry.computeMergedHighlightRects(textLayerInfo, beginIndex, beginOffset, endIndex, endOffset);
6768
const rects = results.map(({ rect }) => rect);
6869
let annotationID;
6970
try {

src/lib/index.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -658,7 +658,10 @@ export class PDFPlusLib {
658658
}
659659

660660
getTextContentItems() {
661-
return this.getPage(true)?.textLayer?.textContentItems;
661+
const textLayer = this.getPage(true)?.textLayer;
662+
if (textLayer) {
663+
return utils.getTextLayerInfo(textLayer).textContentItems;
664+
}
662665
}
663666

664667
getPDFDocument(activeOnly: boolean = false) {

0 commit comments

Comments
 (0)