fix anchor links in wysiwyg (#14950)

* fix anchor links in wysiwyg
This commit is contained in:
Barbara Valdez
2021-04-08 10:56:11 -07:00
committed by GitHub
parent 35e1daa6ba
commit 4f67f32262
3 changed files with 48 additions and 14 deletions

View File

@@ -236,11 +236,14 @@ export class MarkdownToolbarComponent extends AngularDisposable {
needsTransform = false;
} else {
let linkUrl = linkCalloutResult.insertUnescapedLinkUrl;
const isFile = URI.parse(linkUrl).scheme === 'file';
if (isFile && !path.isAbsolute(linkUrl)) {
const notebookDirName = path.dirname(this.cellModel?.notebookModel?.notebookUri.fsPath);
const relativePath = (linkUrl).replace(/\\/g, path.posix.sep);
linkUrl = path.resolve(notebookDirName, relativePath);
const isAnchorLink = linkUrl.startsWith('#');
if (!isAnchorLink) {
const isFile = URI.parse(linkUrl).scheme === 'file';
if (isFile && !path.isAbsolute(linkUrl)) {
const notebookDirName = path.dirname(this.cellModel?.notebookModel?.notebookUri.fsPath);
const relativePath = (linkUrl).replace(/\\/g, path.posix.sep);
linkUrl = path.resolve(notebookDirName, relativePath);
}
}
// Otherwise, re-focus on the output element, and insert the link directly.
this.output?.nativeElement?.focus();

View File

@@ -132,15 +132,28 @@ export class HTMLMarkdownConverter {
this.turndownService.addRule('a', {
filter: 'a',
replacement: (content, node) => {
//On Windows, if notebook is not trusted then the href attr is removed for all non-web URL links
// href contains either a hyperlink or a URI-encoded absolute path. (See resolveUrls method in notebookMarkdown.ts)
const notebookLink = node.href ? URI.parse(node.href) : URI.file(node.title);
const notebookFolder = this.notebookUri ? path.join(path.dirname(this.notebookUri.fsPath), path.sep) : '';
let relativePath = findPathRelativeToContent(notebookFolder, notebookLink);
if (relativePath) {
return `[${node.innerText}](${relativePath})`;
let href = node.href;
let notebookLink: URI | undefined;
const isAnchorLinkInFile = (node.attributes.href?.nodeValue.startsWith('#') || href.includes('#')) && href.startsWith('file://');
if (isAnchorLinkInFile) {
notebookLink = getUriAnchorLink(node, this.notebookUri);
} else {
//On Windows, if notebook is not trusted then the href attr is removed for all non-web URL links
// href contains either a hyperlink or a URI-encoded absolute path. (See resolveUrls method in notebookMarkdown.ts)
notebookLink = href ? URI.parse(href) : URI.file(node.title);
}
return `[${content}](${node.href})`;
const notebookFolder = this.notebookUri ? path.join(path.dirname(this.notebookUri.fsPath), path.sep) : '';
if (notebookLink.fsPath !== this.notebookUri.fsPath) {
let relativePath = findPathRelativeToContent(notebookFolder, notebookLink);
if (relativePath) {
return `[${node.innerText}](${relativePath})`;
}
} else if (notebookLink?.fragment) {
// if the anchor link is to a section in the same notebook then just add the fragment
return `[${content}](${notebookLink.fragment})`;
}
return `[${content}](${href})`;
}
});
// Only nested list case differs from original turndown rule
@@ -275,7 +288,7 @@ function blankReplacement(content, node) {
export function findPathRelativeToContent(notebookFolder: string, contentPath: URI | undefined): string {
if (notebookFolder) {
if (contentPath?.scheme === 'file') {
let relativePath = path.relative(notebookFolder, contentPath.fsPath);
let relativePath = contentPath.fragment ? path.relative(notebookFolder, contentPath.fsPath).concat('#', contentPath.fragment) : path.relative(notebookFolder, contentPath.fsPath);
//if path contains whitespaces then it's not identified as a link
relativePath = relativePath.replace(/\s/g, '%20');
if (relativePath.startsWith(path.join('..', path.sep) || path.join('.', path.sep))) {
@@ -295,3 +308,15 @@ export function addHighlightIfYellowBgExists(node, content: string): string {
}
return content;
}
export function getUriAnchorLink(node, notebookUri: URI): URI {
const sectionLinkToAnotherFile = node.href.includes('#') && !node.attributes.href?.nodeValue.startsWith('#');
if (sectionLinkToAnotherFile) {
let absolutePath = !path.isAbsolute(node.attributes.href?.nodeValue) ? path.resolve(path.dirname(notebookUri.fsPath), node.attributes.href?.nodeValue) : node.attributes.href?.nodeValue;
// if section link is different from the current notebook
return URI.file(absolutePath);
} else {
// else build an uri using the current notebookUri
return URI.from({ scheme: 'file', path: notebookUri.path, fragment: node.attributes.href?.nodeValue });
}
}

View File

@@ -143,6 +143,12 @@ suite('HTML Markdown Converter', function (): void {
assert.equal(htmlMarkdownConverter.convert(htmlString), '[msft](http://www.microsoft.com/images/msft.png)', 'Basic http link test failed');
htmlString = 'Test <a href="http://www.microsoft.com/images/msft.png">msft</a>';
assert.equal(htmlMarkdownConverter.convert(htmlString), 'Test [msft](http://www.microsoft.com/images/msft.png)', 'Basic http link + text test failed');
htmlString = '<a href="#hello">hello</a>';
assert.equal(htmlMarkdownConverter.convert(htmlString), '[hello](#hello)', 'Basic link to a section failed');
htmlString = '<a href="file.md#hello">hello</a>';
assert.equal(htmlMarkdownConverter.convert(htmlString), `[hello](.${path.sep}file.md#hello)`, 'Basic anchor link to a section failed');
htmlString = '<a href="http://www.microsoft.com/images/msft.png#Hello">hello</a>';
assert.equal(htmlMarkdownConverter.convert(htmlString), '[hello](http://www.microsoft.com/images/msft.png#Hello)', 'Http link containing # sign failed');
});
test('Should transform <li> tags', () => {