@@ -4,7 +4,6 @@ import { randomString } from "../../../../app/util";
4
4
import EntityLink from "../../../../components/EntityLink" ;
5
5
import Entity from "../../../../model/Entity" ;
6
6
import LinkedEntities from "../../../../model/LinkedEntities" ;
7
- import Image3D from "../../../../components/Image3D" ;
8
7
9
8
export default function addLinksToText (
10
9
text : string ,
@@ -13,15 +12,53 @@ export default function addLinksToText(
13
12
currentEntity : Entity | undefined ,
14
13
entityType : "ontologies" | "classes" | "properties" | "individuals"
15
14
) {
16
- let linksToSplice : Array < { start : number ; end : number ; link : JSX . Element } > =
17
- [ ] ;
18
15
16
+ let linksToSplice : Array < { start : number ; end : number ; link : JSX . Element } > = [ ] ;
17
+ let urlMatches : Array < { start : number ; end : number } > = [ ] ; // To store the ranges of URLs
18
+
19
+ // First, find all URLs and record their ranges
20
+ const urlRe = / [ A - z ] + : \/ \/ [ ^ \s ] + / g;
21
+ for ( let match = urlRe . exec ( text ) ; match ; match = urlRe . exec ( text ) ) {
22
+ const url = match [ 0 ] ;
23
+ linksToSplice . push ( {
24
+ start : match . index ,
25
+ end : match . index + url . length ,
26
+ link : (
27
+ < span key = { url + randomString ( ) } >
28
+ < Link
29
+ to = { url }
30
+ className = "link-default pr-1"
31
+ target = "_blank"
32
+ rel = "noopener noreferrer"
33
+ >
34
+ { url }
35
+ </ Link >
36
+ </ span >
37
+ ) ,
38
+ } ) ;
39
+ urlMatches . push ( { start : match . index , end : match . index + url . length } ) ;
40
+ }
41
+
42
+ // Then, process entity IDs
19
43
for ( let entityId of Object . keys ( linkedEntities . linkedEntities ) ) {
20
44
for (
21
45
let n = text . indexOf ( entityId , 0 ) ;
22
46
n !== - 1 ;
23
47
n = text . indexOf ( entityId , n )
24
48
) {
49
+ // We need to handle this case when entity ID is part of a URL and it then gets linked to an entity but
50
+ // resulting url is broken. So, we need to keep the URL as is if the entity ID is part of a URL.
51
+ // Check if the entity ID is within any URL range
52
+ let isWithinURL = urlMatches . some (
53
+ ( urlRange ) =>
54
+ n >= urlRange . start && n + entityId . length <= urlRange . end
55
+ ) ;
56
+ if ( isWithinURL ) {
57
+ // Skip this entity ID because it's part of a URL
58
+ n += entityId . length ;
59
+ continue ;
60
+ }
61
+
25
62
linksToSplice . push ( {
26
63
start : n ,
27
64
end : n + entityId . length ,
@@ -41,65 +78,45 @@ export default function addLinksToText(
41
78
}
42
79
}
43
80
44
- const urlRe = / [ A - z ] + : \/ \/ [ ^ \s ] + / g;
45
- for ( let match = urlRe . exec ( text ) ; match ; match = urlRe . exec ( text ) ) {
46
- const url = match [ 0 ] ;
47
- // console.log("found match " + url);
48
- linksToSplice . push ( {
49
- start : match . index ,
50
- end : match . index + url . length ,
51
- link : (
52
- < span >
53
- < Link
54
- key = { url + randomString ( ) }
55
- to = { url }
56
- className = "link-default pr-1"
57
- target = "_blank"
58
- rel = "noopener noreferrer"
59
- >
60
- { url }
61
- </ Link >
62
- </ span >
63
- ) ,
64
- } ) ;
65
- }
66
-
67
- removeOverlapping: for ( let n = 0 ; n < linksToSplice . length ; ) {
68
- for ( let n2 = 0 ; n2 < linksToSplice . length ; ++ n2 ) {
69
- let spliceA = linksToSplice [ n ] ;
70
- let spliceB = linksToSplice [ n2 ] ;
81
+ // Remove overlapping links by sorting and keeping the first one
82
+ linksToSplice . sort ( ( a , b ) => a . start - b . start ) ;
71
83
72
- if ( spliceA === spliceB ) continue ;
73
-
74
- // The splices overlap if neither ends before the other starts
75
- if ( spliceA . end >= spliceB . start && spliceB . end >= spliceA . start ) {
76
- // console.log("Removing overlapping");
77
- linksToSplice . splice ( n2 , 1 ) ;
78
- continue removeOverlapping ;
79
- }
84
+ // Remove overlaps
85
+ for ( let i = 0 ; i < linksToSplice . length - 1 ; i ++ ) {
86
+ const current = linksToSplice [ i ] ;
87
+ const next = linksToSplice [ i + 1 ] ;
88
+ if ( current . end > next . start ) {
89
+ // Overlap detected, remove the next link
90
+ linksToSplice . splice ( i + 1 , 1 ) ;
91
+ i -- ; // Adjust index after removal
80
92
}
81
- ++ n ;
82
93
}
83
94
84
95
if ( linksToSplice . length === 0 ) return text ;
85
96
86
- // linksToSplice.sort((a, b) => a.start - b.start);
87
- // console.dir(linksToSplice);
97
+ // Build the final result
88
98
let res : JSX . Element [ ] = [ ] ;
89
- let n = 0 ;
99
+ let lastIndex = 0 ;
90
100
91
101
for ( let link of linksToSplice ) {
102
+ if ( lastIndex < link . start ) {
103
+ res . push (
104
+ < Fragment key = { randomString ( ) } >
105
+ { text . substring ( lastIndex , link . start ) }
106
+ </ Fragment >
107
+ ) ;
108
+ }
109
+ res . push ( link . link ) ;
110
+ lastIndex = link . end ;
111
+ }
112
+
113
+ if ( lastIndex < text . length ) {
92
114
res . push (
93
- < Fragment key = { text . substring ( n , link . start ) + randomString ( ) } >
94
- { text . substring ( n , link . start ) }
95
- </ Fragment >
115
+ < Fragment key = { text . substring ( lastIndex ) + randomString ( ) } >
116
+ { text . substring ( lastIndex ) }
117
+ </ Fragment >
96
118
) ;
97
- res . push ( link . link ) ;
98
- n = link . end ;
99
119
}
100
- res . push (
101
- < Fragment key = { text . slice ( n ) + randomString ( ) } > { text . slice ( n ) } </ Fragment >
102
- ) ;
103
120
104
121
return res ;
105
122
}
0 commit comments