1
1
import { PDFPlusLibSubmodule } from 'lib/submodule' ;
2
- import { PropRequired } from 'utils' ;
2
+ import { getNodeAndOffsetOfTextPos , PropRequired } from 'utils' ;
3
3
import { TextLayerBuilder , Rect , TextContentItem } from 'typings' ;
4
4
5
5
@@ -12,8 +12,8 @@ export class HighlightGeometryLib extends PDFPlusLibSubmodule {
12
12
* 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).
13
13
* Each rectangle is associated with an array of indices of the text content items contained in the rectangle.
14
14
*/
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 ;
17
17
18
18
const results : MergedRect [ ] = [ ] ;
19
19
@@ -34,7 +34,7 @@ export class HighlightGeometryLib extends PDFPlusLibSubmodule {
34
34
if ( ! item . str ) continue ;
35
35
36
36
// 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 ) ;
38
38
if ( ! rect ) continue ;
39
39
40
40
if ( ! mergedRect ) {
@@ -59,13 +59,13 @@ export class HighlightGeometryLib extends PDFPlusLibSubmodule {
59
59
return results ;
60
60
}
61
61
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 {
63
63
// If the item has the `chars` property filled, use it to get the bounding rectangle of each character in the item.
64
64
if ( item . chars && item . chars . length >= item . str . length ) {
65
65
return this . computeHighlightRectForItemFromChars ( item as PropRequired < TextContentItem , 'chars' > , index , beginIndex , beginOffset , endIndex , endOffset ) ;
66
66
}
67
67
// 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 ) ;
69
69
}
70
70
71
71
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 {
92
92
] ;
93
93
}
94
94
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 {
103
96
// the bounding box of the whole text content item
104
97
const x1 = item . transform [ 4 ] ;
105
98
const y1 = item . transform [ 5 ] ;
106
99
const x2 = item . transform [ 4 ] + item . width ;
107
100
const y2 = item . transform [ 5 ] + item . height ;
108
101
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 ( ) ;
114
103
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
+ }
118
114
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 ) ;
122
124
}
123
125
124
- const rect = boundingEl . getBoundingClientRect ( ) ;
126
+ const rect = range . getBoundingClientRect ( ) ;
125
127
const parentRect = textDiv . getBoundingClientRect ( ) ;
126
128
127
- textDivCopied . remove ( ) ;
128
-
129
129
return [
130
130
x1 + ( rect . left - parentRect . left ) / parentRect . width * item . width ,
131
131
y1 + ( rect . bottom - parentRect . bottom ) / parentRect . height * item . height ,
0 commit comments