Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix custom annotation link #741

Merged
merged 2 commits into from
Sep 24, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { randomString } from "../../../../app/util";
import EntityLink from "../../../../components/EntityLink";
import Entity from "../../../../model/Entity";
import LinkedEntities from "../../../../model/LinkedEntities";
import Image3D from "../../../../components/Image3D";

export default function addLinksToText(
text: string,
Expand All @@ -13,15 +12,53 @@ export default function addLinksToText(
currentEntity: Entity | undefined,
entityType: "ontologies" | "classes" | "properties" | "individuals"
) {
let linksToSplice: Array<{ start: number; end: number; link: JSX.Element }> =
[];

let linksToSplice: Array<{ start: number; end: number; link: JSX.Element }> = [];
let urlMatches: Array<{ start: number; end: number }> = []; // To store the ranges of URLs

// First, find all URLs and record their ranges
const urlRe = /[A-z]+:\/\/[^\s]+/g;
for (let match = urlRe.exec(text); match; match = urlRe.exec(text)) {
const url = match[0];
linksToSplice.push({
start: match.index,
end: match.index + url.length,
link: (
<span key={url + randomString()}>
<Link
to={url}
className="link-default pr-1"
target="_blank"
rel="noopener noreferrer"
>
{url}
</Link>
</span>
),
});
urlMatches.push({ start: match.index, end: match.index + url.length });
}

// Then, process entity IDs
for (let entityId of Object.keys(linkedEntities.linkedEntities)) {
for (
let n = text.indexOf(entityId, 0);
n !== -1;
n = text.indexOf(entityId, n)
) {
// We need to handle this case when entity ID is part of a URL and it then gets linked to an entity but
// resulting url is broken. So, we need to keep the URL as is if the entity ID is part of a URL.
// Check if the entity ID is within any URL range
let isWithinURL = urlMatches.some(
(urlRange) =>
n >= urlRange.start && n + entityId.length <= urlRange.end
);
if (isWithinURL) {
// Skip this entity ID because it's part of a URL
n += entityId.length;
continue;
}

linksToSplice.push({
start: n,
end: n + entityId.length,
Expand All @@ -41,65 +78,45 @@ export default function addLinksToText(
}
}

const urlRe = /[A-z]+:\/\/[^\s]+/g;
for (let match = urlRe.exec(text); match; match = urlRe.exec(text)) {
const url = match[0];
// console.log("found match " + url);
linksToSplice.push({
start: match.index,
end: match.index + url.length,
link: (
<span>
<Link
key={url + randomString()}
to={url}
className="link-default pr-1"
target="_blank"
rel="noopener noreferrer"
>
{url}
</Link>
</span>
),
});
}

removeOverlapping: for (let n = 0; n < linksToSplice.length; ) {
for (let n2 = 0; n2 < linksToSplice.length; ++n2) {
let spliceA = linksToSplice[n];
let spliceB = linksToSplice[n2];
// Remove overlapping links by sorting and keeping the first one
linksToSplice.sort((a, b) => a.start - b.start);

if (spliceA === spliceB) continue;

// The splices overlap if neither ends before the other starts
if (spliceA.end >= spliceB.start && spliceB.end >= spliceA.start) {
// console.log("Removing overlapping");
linksToSplice.splice(n2, 1);
continue removeOverlapping;
}
// Remove overlaps
for (let i = 0; i < linksToSplice.length - 1; i++) {
const current = linksToSplice[i];
const next = linksToSplice[i + 1];
if (current.end > next.start) {
// Overlap detected, remove the next link
linksToSplice.splice(i + 1, 1);
i--; // Adjust index after removal
}
++n;
}

if (linksToSplice.length === 0) return text;

// linksToSplice.sort((a, b) => a.start - b.start);
// console.dir(linksToSplice);
// Build the final result
let res: JSX.Element[] = [];
let n = 0;
let lastIndex = 0;

for (let link of linksToSplice) {
if (lastIndex < link.start) {
res.push(
<Fragment key={randomString()}>
{text.substring(lastIndex, link.start)}
</Fragment>
);
}
res.push(link.link);
lastIndex = link.end;
}

if (lastIndex < text.length) {
res.push(
<Fragment key={text.substring(n, link.start) + randomString()}>
{text.substring(n, link.start)}
</Fragment>
<Fragment key={text.substring(lastIndex) + randomString()}>
{text.substring(lastIndex)}
</Fragment>
);
res.push(link.link);
n = link.end;
}
res.push(
<Fragment key={text.slice(n) + randomString()}>{text.slice(n)}</Fragment>
);

return res;
}
Loading