diff --git a/Our.Umbraco.TagHelpers/InlineSvgTagHelper.cs b/Our.Umbraco.TagHelpers/InlineSvgTagHelper.cs index d1dd8e1..8bede85 100644 --- a/Our.Umbraco.TagHelpers/InlineSvgTagHelper.cs +++ b/Our.Umbraco.TagHelpers/InlineSvgTagHelper.cs @@ -85,6 +85,31 @@ public InlineSvgTagHelper(MediaFileManager mediaFileManager, IWebHostEnvironment [HtmlAttributeName("ignore-appsettings")] public bool IgnoreAppSettings { get; set; } + + + private string CalculateSvgContentCacheKey () { + if (MediaItem is not null) + { + return string.Concat("MediaItem-SvgContents (", MediaItem.Key.ToString(), ")"); + } + + if (string.IsNullOrWhiteSpace(FileSource) == false) + { + return string.Concat("File-SvgContents (", FileSource, ")"); + } + + return string.Empty; + } + + private string CalculateSetAttrsCacheKey (string cleanedFileContents) + => $"SvgWithAttributes ({CssClass?.GetHashCode()}_{cleanedFileContents.GetHashCode()})"; + + private int FetchCacheMinutes () + => CacheMinutes > 0 ? CacheMinutes : _globalSettings.OurSVG.CacheMinutes; + + private bool FetchEnsureViewBoxStatus () => + EnsureViewBox || (_globalSettings.OurSVG.EnsureViewBox && !IgnoreAppSettings); + public override void Process(TagHelperContext context, TagHelperOutput output) { // Can only use media-item OR src @@ -99,23 +124,14 @@ public override void Process(TagHelperContext context, TagHelperOutput output) } string? cleanedFileContents = null; - - if(Cache || (_globalSettings.OurSVG.Cache && !IgnoreAppSettings)) + var doCache = Cache || (_globalSettings.OurSVG.Cache && !IgnoreAppSettings); + if (doCache) { - var cacheName = string.Empty; - var cacheMins = CacheMinutes > 0 ? CacheMinutes : _globalSettings.OurSVG.CacheMinutes; - - if (MediaItem is not null) - { - cacheName = string.Concat("MediaItem-SvgContents (", MediaItem.Key.ToString(), ")"); - } - else if (string.IsNullOrWhiteSpace(FileSource) == false) - { - cacheName = string.Concat("File-SvgContents (", FileSource, ")"); - } + var cacheKey = CalculateSvgContentCacheKey(); + var cacheMins = FetchCacheMinutes(); - cleanedFileContents = _appCaches.RuntimeCache.GetCacheItem(cacheName, () => - { + cleanedFileContents = _appCaches.RuntimeCache.GetCacheItem(cacheKey, () => + { return GetFileContents(); }, TimeSpan.FromMinutes(cacheMins)); } @@ -130,12 +146,28 @@ public override void Process(TagHelperContext context, TagHelperOutput output) return; } + string svgWithAttributes; + if (doCache) + { + var cacheKey = CalculateSetAttrsCacheKey(cleanedFileContents); + var cacheMins = FetchCacheMinutes(); + + svgWithAttributes = _appCaches.RuntimeCache.GetCacheItem(cacheKey, () => + { + return ParseAndSetAttrs(cleanedFileContents); + }, TimeSpan.FromMinutes(cacheMins)); + } + else + { + svgWithAttributes = ParseAndSetAttrs(cleanedFileContents); + } + // Remove the src attribute or media-item from the output.Attributes.RemoveAll("src"); output.Attributes.RemoveAll("media-item"); output.TagName = null; // Remove - output.Content.SetHtmlContent(cleanedFileContents); + output.Content.SetHtmlContent(svgWithAttributes); } private string? GetFileContents() @@ -201,18 +233,38 @@ public override void Process(TagHelperContext context, TagHelperOutput output) @"syntax:error:", RegexOptions.IgnoreCase | RegexOptions.Singleline); - if ((EnsureViewBox || (_globalSettings.OurSVG.EnsureViewBox && !IgnoreAppSettings)) || !string.IsNullOrEmpty(CssClass)) + return cleanedFileContents; + } + + /// + /// Set CSS Class, Viewbox, and/or width/height + /// + /// SVG file contents + /// SVG file contents with attributes + private string ParseAndSetAttrs (string cleanedFileContents) { + var doEnsureViewBox = FetchEnsureViewBoxStatus(); + var hasCssClass = !string.IsNullOrEmpty(CssClass); + + // No work to do (save the unnecessary LoadHtml) + if (!doEnsureViewBox && !hasCssClass) + { + return cleanedFileContents; + } + + HtmlDocument doc = new HtmlDocument(); + doc.LoadHtml(cleanedFileContents); + var svgs = doc.DocumentNode.SelectNodes("//svg"); + foreach (var svgNode in svgs) { - HtmlDocument doc = new HtmlDocument(); - doc.LoadHtml(cleanedFileContents); - var svgs = doc.DocumentNode.SelectNodes("//svg"); - foreach (var svgNode in svgs) + if (hasCssClass) { - if (!string.IsNullOrEmpty(CssClass)) - { - svgNode.AddClass(CssClass); - } - if ((EnsureViewBox || (_globalSettings.OurSVG.EnsureViewBox && !IgnoreAppSettings)) && svgNode.Attributes.Contains("width") && svgNode.Attributes.Contains("height") && !svgNode.Attributes.Contains("viewbox")) + svgNode.AddClass(CssClass); + } + + if (doEnsureViewBox) + { + var hasDimensionsAndNoViewbox = svgNode.Attributes.Contains("width") && svgNode.Attributes.Contains("height") && !svgNode.Attributes.Contains("viewbox"); + if (hasDimensionsAndNoViewbox) { var width = StringUtils.GetDecimal(svgNode.GetAttributeValue("width", "0")); var height = StringUtils.GetDecimal(svgNode.GetAttributeValue("height", "0")); @@ -222,8 +274,8 @@ public override void Process(TagHelperContext context, TagHelperOutput output) svgNode.Attributes.Remove("height"); } } - cleanedFileContents = doc.DocumentNode.OuterHtml; } + cleanedFileContents = doc.DocumentNode.OuterHtml; return cleanedFileContents; }