mirror of
https://github.com/microsoft/PowerToys.git
synced 2024-11-27 23:19:13 +08:00
Display infobar for blocked relative image path (#1695)
* Updated Parsing extension to show infobar when relative URL isblocked and updated corresponding tests * Updated Controller to display infobar when html img tag is embedded in markdown
This commit is contained in:
parent
15cefc664a
commit
c2e219b446
@ -1,117 +1,103 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using Markdig;
|
||||
using Markdig.Extensions.Figures;
|
||||
using Markdig.Extensions.Tables;
|
||||
using Markdig.Renderers;
|
||||
using Markdig.Renderers.Html;
|
||||
using Markdig.Syntax;
|
||||
using Markdig.Syntax.Inlines;
|
||||
|
||||
namespace MarkdownPreviewHandler
|
||||
{
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using Markdig;
|
||||
using Markdig.Extensions.Figures;
|
||||
using Markdig.Extensions.Tables;
|
||||
using Markdig.Renderers;
|
||||
using Markdig.Renderers.Html;
|
||||
using Markdig.Syntax;
|
||||
using Markdig.Syntax.Inlines;
|
||||
|
||||
namespace MarkdownPreviewHandler
|
||||
{
|
||||
/// <summary>
|
||||
/// Callback if extension blocks external images.
|
||||
/// </summary>
|
||||
public delegate void ImagesBlockedCallBack();
|
||||
|
||||
/// <summary>
|
||||
/// Markdig Extension to process html nodes in markdown AST.
|
||||
/// </summary>
|
||||
public class HTMLParsingExtension : IMarkdownExtension
|
||||
{
|
||||
/// <summary>
|
||||
/// Markdig Extension to process html nodes in markdown AST.
|
||||
/// </summary>
|
||||
public class HTMLParsingExtension : IMarkdownExtension
|
||||
{
|
||||
/// <summary>
|
||||
/// Callback if extension blocks external images.
|
||||
/// </summary>
|
||||
private readonly ImagesBlockedCallBack imagesBlockedCallBack;
|
||||
|
||||
/// </summary>
|
||||
private readonly ImagesBlockedCallBack imagesBlockedCallBack;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="HTMLParsingExtension"/> class.
|
||||
/// </summary>
|
||||
/// <param name="imagesBlockedCallBack">Callback function if image is blocked by extension.</param>
|
||||
/// <param name="baseUrl">Absolute path of markdown file.</param>
|
||||
public HTMLParsingExtension(ImagesBlockedCallBack imagesBlockedCallBack, string baseUrl = "")
|
||||
{
|
||||
this.imagesBlockedCallBack = imagesBlockedCallBack;
|
||||
this.BaseUrl = baseUrl;
|
||||
}
|
||||
/// <param name="baseUrl">Absolute path of markdown file.</param>
|
||||
public HTMLParsingExtension(ImagesBlockedCallBack imagesBlockedCallBack, string baseUrl = "")
|
||||
{
|
||||
this.imagesBlockedCallBack = imagesBlockedCallBack;
|
||||
this.BaseUrl = baseUrl;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets path to directory containing markdown file.
|
||||
/// </summary>
|
||||
public string BaseUrl { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets path to directory containing markdown file.
|
||||
/// </summary>
|
||||
public string BaseUrl { get; set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Setup(MarkdownPipelineBuilder pipeline)
|
||||
{
|
||||
// Make sure we don't have a delegate twice
|
||||
pipeline.DocumentProcessed -= this.PipelineOnDocumentProcessed;
|
||||
pipeline.DocumentProcessed += this.PipelineOnDocumentProcessed;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Setup(MarkdownPipeline pipeline, IMarkdownRenderer renderer)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Process nodes in markdown AST.
|
||||
/// </summary>
|
||||
/// <param name="document">Markdown Document.</param>
|
||||
public void PipelineOnDocumentProcessed(MarkdownDocument document)
|
||||
{
|
||||
foreach (var node in document.Descendants())
|
||||
/// <inheritdoc/>
|
||||
public void Setup(MarkdownPipelineBuilder pipeline)
|
||||
{
|
||||
// Make sure we don't have a delegate twice
|
||||
pipeline.DocumentProcessed -= this.PipelineOnDocumentProcessed;
|
||||
pipeline.DocumentProcessed += this.PipelineOnDocumentProcessed;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Setup(MarkdownPipeline pipeline, IMarkdownRenderer renderer)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Process nodes in markdown AST.
|
||||
/// </summary>
|
||||
/// <param name="document">Markdown Document.</param>
|
||||
public void PipelineOnDocumentProcessed(MarkdownDocument document)
|
||||
{
|
||||
foreach (var node in document.Descendants())
|
||||
{
|
||||
if (node is Block)
|
||||
{
|
||||
if (node is Table)
|
||||
{
|
||||
node.GetAttributes().AddClass("table table-striped table-bordered");
|
||||
}
|
||||
else if (node is QuoteBlock)
|
||||
{
|
||||
node.GetAttributes().AddClass("blockquote");
|
||||
}
|
||||
else if (node is Figure)
|
||||
{
|
||||
node.GetAttributes().AddClass("figure");
|
||||
}
|
||||
else if (node is FigureCaption)
|
||||
{
|
||||
node.GetAttributes().AddClass("figure-caption");
|
||||
}
|
||||
}
|
||||
else if (node is Inline)
|
||||
{
|
||||
if (node is LinkInline link)
|
||||
{
|
||||
if (node is Block)
|
||||
{
|
||||
if (node is Table)
|
||||
{
|
||||
node.GetAttributes().AddClass("table table-striped table-bordered");
|
||||
}
|
||||
else if (node is QuoteBlock)
|
||||
{
|
||||
node.GetAttributes().AddClass("blockquote");
|
||||
}
|
||||
else if (node is Figure)
|
||||
{
|
||||
node.GetAttributes().AddClass("figure");
|
||||
}
|
||||
else if (node is FigureCaption)
|
||||
{
|
||||
node.GetAttributes().AddClass("figure-caption");
|
||||
}
|
||||
}
|
||||
else if (node is Inline)
|
||||
{
|
||||
if (node is LinkInline link)
|
||||
{
|
||||
if (link.IsImage)
|
||||
{
|
||||
link.Url = "#";
|
||||
link.GetAttributes().AddClass("img-fluid");
|
||||
}
|
||||
|
||||
if (!Uri.TryCreate(link.Url, UriKind.Absolute, out _))
|
||||
{
|
||||
link.Url = link.Url.TrimStart('/', '\\');
|
||||
this.BaseUrl = this.BaseUrl.TrimEnd('/', '\\');
|
||||
Uri uriLink = new Uri(Path.Combine(this.BaseUrl, link.Url));
|
||||
link.Url = uriLink.ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (link.IsImage)
|
||||
{
|
||||
link.Url = "#";
|
||||
this.imagesBlockedCallBack();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
this.imagesBlockedCallBack();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Windows.Forms;
|
||||
using Common;
|
||||
using Markdig;
|
||||
@ -83,6 +84,12 @@ namespace MarkdownPreviewHandler
|
||||
string fileText = File.ReadAllText(filePath);
|
||||
this.extension.BaseUrl = Path.GetDirectoryName(filePath);
|
||||
|
||||
Regex rgx = new Regex(@"<[ ]*img.*>");
|
||||
if (rgx.IsMatch(fileText))
|
||||
{
|
||||
this.infoBarDisplayed = true;
|
||||
}
|
||||
|
||||
MarkdownPipeline pipeline = this.pipelineBuilder.Build();
|
||||
string parsedMarkdown = Markdown.ToHtml(fileText, pipeline);
|
||||
sb.AppendFormat("{0}{1}{2}", this.htmlHeader, parsedMarkdown, this.htmlFooter);
|
||||
|
@ -47,7 +47,7 @@ namespace PreviewPaneUnitTests
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Extension_UpdatesFigureClassAndRelativeUrltoAbsolute_WhenUsed()
|
||||
public void Extension_UpdatesFigureClassAndBlocksRelativeUrl_WhenUsed()
|
||||
{
|
||||
// arrange
|
||||
String mdString = "![text](a.jpg \"Figure\")";
|
||||
@ -58,37 +58,7 @@ namespace PreviewPaneUnitTests
|
||||
String html = Markdown.ToHtml(mdString, markdownPipeline);
|
||||
|
||||
// Assert
|
||||
Assert.AreEqual(html, "<p><img src=\"file:///C:/Users/a.jpg\" class=\"img-fluid\" alt=\"text\" title=\"Figure\" /></p>\n");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Extension_CreatesCorrectAbsoluteLinkByTrimmingForwardSlash_WhenUsed()
|
||||
{
|
||||
// arrange
|
||||
String mdString = "![text](\\document\\a.jpg \"Figure\")";
|
||||
HTMLParsingExtension htmlParsingExtension = new HTMLParsingExtension(() => { }, "C:\\Users\\");
|
||||
MarkdownPipeline markdownPipeline = BuidPipeline(htmlParsingExtension);
|
||||
|
||||
// Act
|
||||
String html = Markdown.ToHtml(mdString, markdownPipeline);
|
||||
|
||||
// Assert
|
||||
Assert.AreEqual(html, "<p><img src=\"file:///C:/Users/document/a.jpg\" class=\"img-fluid\" alt=\"text\" title=\"Figure\" /></p>\n");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Extension_CreatesCorrectAbsoluteLinkByTrimmingBackwardSlash_WhenUsed()
|
||||
{
|
||||
// arrange
|
||||
String mdString = "![text](/document/a.jpg \"Figure\")";
|
||||
HTMLParsingExtension htmlParsingExtension = new HTMLParsingExtension(() => { }, "C:/Users/");
|
||||
MarkdownPipeline markdownPipeline = BuidPipeline(htmlParsingExtension);
|
||||
|
||||
// Act
|
||||
String html = Markdown.ToHtml(mdString, markdownPipeline);
|
||||
|
||||
// Assert
|
||||
Assert.AreEqual(html, "<p><img src=\"file:///C:/Users/document/a.jpg\" class=\"img-fluid\" alt=\"text\" title=\"Figure\" /></p>\n");
|
||||
Assert.AreEqual(html, "<p><img src=\"#\" class=\"img-fluid\" alt=\"text\" title=\"Figure\" /></p>\n");
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
|
@ -0,0 +1,2 @@
|
||||
## Something
|
||||
<img src="./a.jpg" \>
|
@ -42,6 +42,20 @@ namespace PreviewPaneUnitTests
|
||||
Assert.IsInstanceOfType(markdownPreviewHandlerControl.Controls[1], typeof(RichTextBox));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MarkdownPreviewHandlerControl__AddsInfoBarToFormIfHTMLImageTagIsPresent_WhenDoPreviewIsCalled()
|
||||
{
|
||||
// Arrange
|
||||
MarkdownPreviewHandlerControl markdownPreviewHandlerControl = new MarkdownPreviewHandlerControl();
|
||||
|
||||
// Act
|
||||
markdownPreviewHandlerControl.DoPreview<string>("HelperFiles/MarkdownWithHTMLImageTag.txt");
|
||||
|
||||
// Assert
|
||||
Assert.AreEqual(markdownPreviewHandlerControl.Controls.Count, 2);
|
||||
Assert.IsInstanceOfType(markdownPreviewHandlerControl.Controls[1], typeof(RichTextBox));
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MarkdownPreviewHandlerControl__DoesNotAddInfoBarToFormIfExternalImageLinkNotPresent_WhenDoPreviewIsCalled()
|
||||
{
|
||||
|
@ -116,6 +116,9 @@
|
||||
<Content Include="HelperFiles\MarkdownWithExternalImage.txt">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="HelperFiles\MarkdownWithHTMLImageTag.txt">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="HelperFiles\MarkdownWithscript.txt">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
|
Loading…
Reference in New Issue
Block a user