move html link creation to linkify function

This commit is contained in:
Aaron Munger 2023-08-14 11:44:28 -07:00
parent 4751626eea
commit b9cd07d8bf
2 changed files with 20 additions and 13 deletions

View file

@ -396,14 +396,9 @@ function appendStylizedStringToContainer(
let container = document.createElement('span');
if (trustHtml) {
const trustedHtml = ttPolicy?.createHTML(stringContent) ?? stringContent;
container.innerHTML = trustedHtml as string;
}
if (container.childElementCount === 0) {
// plain text
container = linkify(stringContent, true, workspaceFolder);
container = linkify(stringContent, true, workspaceFolder, trustHtml);
}
container.className = cssClasses.join(' ');

View file

@ -3,6 +3,8 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ttPolicy } from './htmlHelper';
const CONTROL_CODES = '\\u0000-\\u0020\\u007f-\\u009f';
const WEB_LINK_REGEX = new RegExp('(?:[a-zA-Z][a-zA-Z0-9+.-]{2,}:\\/\\/|data:|www\\.)[^\\s' + CONTROL_CODES + '"]{2,}[^\\s' + CONTROL_CODES + '"\')}\\],:;.!?]', 'ug');
@ -13,10 +15,11 @@ const POSIX_PATH = /(?<=^|\s)((?:\~|\.)?(?:\/[\w\.-]*)+)/;
const LINE_COLUMN = /(?:\:([\d]+))?(?:\:([\d]+))?/;
const isWindows = (typeof navigator !== 'undefined') ? navigator.userAgent && navigator.userAgent.indexOf('Windows') >= 0 : false;
const PATH_LINK_REGEX = new RegExp(`${isWindows ? WIN_PATH.source : POSIX_PATH.source}${LINE_COLUMN.source}`, 'g');
const HTML_LINK_REGEX = /<a\s+(?:[^>]*?\s+)?href=(["'])(.*?)\1[^>]*?>.*?<\/a>/gi;
const MAX_LENGTH = 2000;
type LinkKind = 'web' | 'path' | 'text';
type LinkKind = 'web' | 'path' | 'html' | 'text';
type LinkPart = {
kind: LinkKind;
value: string;
@ -36,7 +39,7 @@ export class LinkDetector {
* When splitLines is true, each line of the text, even if it contains no links, is wrapped in a <span>
* and added as a child of the returned <span>.
*/
linkify(text: string, splitLines?: boolean, workspaceFolder?: string): HTMLElement {
linkify(text: string, splitLines?: boolean, workspaceFolder?: string, trustHtml?: boolean): HTMLElement {
if (splitLines) {
const lines = text.split('\n');
for (let i = 0; i < lines.length - 1; i++) {
@ -46,7 +49,7 @@ export class LinkDetector {
// Remove the last element ('') that split added.
lines.pop();
}
const elements = lines.map(line => this.linkify(line, false, workspaceFolder));
const elements = lines.map(line => this.linkify(line, false, workspaceFolder, trustHtml));
if (elements.length === 1) {
// Do not wrap single line with extra span.
return elements[0];
@ -67,6 +70,15 @@ export class LinkDetector {
case 'path':
container.appendChild(this.createWebLink(part.value));
break;
case 'html':
if (ttPolicy && trustHtml) {
const span = document.createElement('span');
span.innerHTML = ttPolicy.createHTML(part.value).toString();
container.appendChild(span);
} else {
container.appendChild(document.createTextNode(part.value));
}
break;
}
} catch (e) {
container.appendChild(document.createTextNode(part.value));
@ -130,8 +142,8 @@ export class LinkDetector {
return [{ kind: 'text', value: text, captures: [] }];
}
const regexes: RegExp[] = [WEB_LINK_REGEX, PATH_LINK_REGEX];
const kinds: LinkKind[] = ['web', 'path'];
const regexes: RegExp[] = [WEB_LINK_REGEX, PATH_LINK_REGEX, HTML_LINK_REGEX];
const kinds: LinkKind[] = ['web', 'path', 'html'];
const result: LinkPart[] = [];
const splitOne = (text: string, regexIndex: number) => {
@ -168,6 +180,6 @@ export class LinkDetector {
}
const linkDetector = new LinkDetector();
export function linkify(text: string, splitLines?: boolean, workspaceFolder?: string) {
return linkDetector.linkify(text, splitLines, workspaceFolder);
export function linkify(text: string, splitLines?: boolean, workspaceFolder?: string, trustHtml = false) {
return linkDetector.linkify(text, splitLines, workspaceFolder, trustHtml);
}