diff --git a/docs/syntax/images.md b/docs/syntax/images.md index 099a4e058..90f1c2a1f 100644 --- a/docs/syntax/images.md +++ b/docs/syntax/images.md @@ -39,10 +39,49 @@ Or, use the `image` directive. ## Inline images ```markdown -Here is the same image used inline ![Elasticsearch](img/observability.png) +Here is the same image used inline ![Elasticsearch](img/observability.png "elasticsearch =50%x50%") ``` -Here is the same image used inline ![Elasticsearch](img/observability.png) +Here is the same image used inline ![Elasticsearch](img/observability.png "elasticsearch =50%x50%") + + +### Inline image titles + +Titles are optional making this the minimal syntax required + +```markdown +![Elasticsearch](img/observability.png) +``` + +Including a title can be done by supplying it as an optional argument. + +```markdown +![Elasticsearch](img/observability.png "elasticsearch") +``` + +### Inline image sizing + +Inline images are supplied at the end through the title argument. + +This is done to maintain maximum compatibility with markdown parsers +and previewers. + +```markdown +![alt](img.png "title =WxH") +![alt](img.png "title =W") +``` + +`W` and `H` can be either an absolute number in pixels or a number followed by `%` to indicate relative sizing. + +If `H` is omitted `W` is used as the height as well. + +```markdown +![alt](img.png "title =250x330") +![alt](img.png "title =50%x40%") +![alt](img.png "title =50%") +``` + + ### SVG diff --git a/src/Elastic.Markdown/Myst/InlineParsers/DiagnosticLinkInlineParser.cs b/src/Elastic.Markdown/Myst/InlineParsers/DiagnosticLinkInlineParser.cs index 230fc77fb..eafdd0c21 100644 --- a/src/Elastic.Markdown/Myst/InlineParsers/DiagnosticLinkInlineParser.cs +++ b/src/Elastic.Markdown/Myst/InlineParsers/DiagnosticLinkInlineParser.cs @@ -4,6 +4,7 @@ using System.Collections.Immutable; using System.IO.Abstractions; +using System.Text.RegularExpressions; using Elastic.Markdown.Diagnostics; using Elastic.Markdown.IO; using Elastic.Markdown.Myst.Comments; @@ -12,6 +13,7 @@ using Markdig.Parsers; using Markdig.Parsers.Inlines; using Markdig.Renderers; +using Markdig.Renderers.Html; using Markdig.Syntax.Inlines; namespace Elastic.Markdown.Myst.InlineParsers; @@ -33,6 +35,14 @@ public void Setup(MarkdownPipelineBuilder pipeline) => public void Setup(MarkdownPipeline pipeline, IMarkdownRenderer renderer) { } } +internal partial class LinkRegexExtensions +{ + + [GeneratedRegex(@"\s\=(?\d+%?)(?:x(?\d+%?))?$", RegexOptions.IgnoreCase, "en-US")] + public static partial Regex MatchTitleStylingInstructions(); + +} + public class DiagnosticLinkInlineParser : LinkInlineParser { // See https://www.iana.org/assignments/uri-schemes/uri-schemes.xhtml for a list of URI schemes @@ -41,6 +51,7 @@ public class DiagnosticLinkInlineParser : LinkInlineParser public override bool Match(InlineProcessor processor, ref StringSlice slice) { var match = base.Match(processor, ref slice); + if (!match || processor.Inline is not LinkInline link) return match; @@ -49,9 +60,38 @@ public override bool Match(InlineProcessor processor, ref StringSlice slice) return match; ValidateAndProcessLink(processor, link, context); + + ParseStylingInstructions(processor, link, context); + return match; } + + private void ParseStylingInstructions(InlineProcessor processor, LinkInline link, ParserContext context) + { + if (string.IsNullOrWhiteSpace(link.Title) || link.Title.IndexOf('=') < 0) + return; + + var matches = LinkRegexExtensions.MatchTitleStylingInstructions().Match(link.Title); + if (!matches.Success) + return; + + var width = matches.Groups["width"].Value; + if (!width.EndsWith("%")) + width += "px"; + var height = matches.Groups["height"].Value; + if (string.IsNullOrEmpty(height)) + height = width; + else if (!height.EndsWith("%")) + height += "px"; + var title = link.Title[..matches.Index]; + + link.Title = title; + var attributes = link.GetAttributes(); + attributes.AddProperty("width", width); + attributes.AddProperty("height", height); + } + private static bool IsInCommentBlock(LinkInline link) => link.Parent?.ParentBlock is CommentBlock; diff --git a/tests/authoring/Inline/InlineImages.fs b/tests/authoring/Inline/InlineImages.fs index 0680a6841..8320b9fdf 100644 --- a/tests/authoring/Inline/InlineImages.fs +++ b/tests/authoring/Inline/InlineImages.fs @@ -28,3 +28,46 @@ type ``relative path to image`` () = markdown |> convertsToHtml """

Elasticsearch

""" + +type ``supplying a tittle`` () = + static let markdown = Setup.Markdown """ +![Elasticsearch](_static/img/observability.png "Hello world") +""" + + [] + let ``validate HTML: includes title`` () = + markdown |> convertsToHtml """ +

Elasticsearch

+ """ + +type ``supplying a tittle with width and height`` () = + static let markdown = Setup.Markdown """ +![o](obs.png "Title =250x400") +""" + + [] + let ``validate HTML: does not include width and height in title`` () = + markdown |> convertsToHtml """ +

o

+ """ + +type ``supplying a tittle with width and height in percentage`` () = + static let markdown = Setup.Markdown """ +![o](obs.png "Title =50%x40%") +""" + + [] + let ``validate HTML: does not include width and height in title`` () = + markdown |> convertsToHtml """ +

o

+ """ +type ``supplying a tittle with width only`` () = + static let markdown = Setup.Markdown """ +![o](obs.png "Title =30%") +""" + + [] + let ``validate HTML: sets height to width if not supplied`` () = + markdown |> convertsToHtml """ +

o

+ """