diff --git a/src/Umbraco.Web/PropertyEditors/RichTextPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/RichTextPropertyEditor.cs index 207e914061..c05a983346 100644 --- a/src/Umbraco.Web/PropertyEditors/RichTextPropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/RichTextPropertyEditor.cs @@ -8,6 +8,7 @@ using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; using Umbraco.Examine; using Umbraco.Web.Macros; +using Umbraco.Web.Templates; namespace Umbraco.Web.PropertyEditors { @@ -73,7 +74,8 @@ namespace Umbraco.Web.PropertyEditors if (val == null) return null; - var parsed = MacroTagParser.FormatRichTextPersistedDataForEditor(val.ToString(), new Dictionary()); + var propertyValueWithMediaResolved = TemplateUtilities.ResolveMediaFromTextString(val.ToString()); + var parsed = MacroTagParser.FormatRichTextPersistedDataForEditor(propertyValueWithMediaResolved, new Dictionary()); return parsed; } diff --git a/src/Umbraco.Web/PropertyEditors/ValueConverters/RteMacroRenderingValueConverter.cs b/src/Umbraco.Web/PropertyEditors/ValueConverters/RteMacroRenderingValueConverter.cs index 1868f9ce94..fbbf058c49 100644 --- a/src/Umbraco.Web/PropertyEditors/ValueConverters/RteMacroRenderingValueConverter.cs +++ b/src/Umbraco.Web/PropertyEditors/ValueConverters/RteMacroRenderingValueConverter.cs @@ -72,9 +72,10 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters var sourceString = source.ToString(); - // ensures string is parsed for {localLink} and urls are resolved correctly + // ensures string is parsed for {localLink} and urls and media are resolved correctly sourceString = TemplateUtilities.ParseInternalLinks(sourceString, preview, Current.UmbracoContext); sourceString = TemplateUtilities.ResolveUrlsFromTextString(sourceString); + sourceString = TemplateUtilities.ResolveMediaFromTextString(sourceString); // ensure string is parsed for macros and macros are executed correctly sourceString = RenderRteMacros(sourceString, preview); diff --git a/src/Umbraco.Web/Templates/TemplateUtilities.cs b/src/Umbraco.Web/Templates/TemplateUtilities.cs index 6da133413d..6c979e9a95 100644 --- a/src/Umbraco.Web/Templates/TemplateUtilities.cs +++ b/src/Umbraco.Web/Templates/TemplateUtilities.cs @@ -75,6 +75,9 @@ namespace Umbraco.Web.Templates private static readonly Regex ResolveUrlPattern = new Regex("(=[\"\']?)(\\W?\\~(?:.(?![\"\']?\\s+(?:\\S+)=|[>\"\']))+.)[\"\']?", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace); + private static readonly Regex ResolveImgPattern = new Regex(@"(]*src="")([^""\?]*)([^""]*""[^>]*data-udi="")([^""]*)(""[^>]*>)", + RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace); + /// /// The RegEx matches any HTML attribute values that start with a tilde (~), those that match are passed to ResolveUrl to replace the tilde with the application path. /// @@ -118,5 +121,46 @@ namespace Umbraco.Web.Templates { return text.CleanForXss(ignoreFromClean); } + + /// + /// Parses the string looking for Umbraco image tags and updates them to their up-to-date image sources. + /// + /// + /// + /// Umbraco image tags are identified by their data-udi attributes + public static string ResolveMediaFromTextString(string text) + { + // don't attempt to proceed without a context + if (Current.UmbracoContext == null || Current.UmbracoContext.MediaCache == null) + { + return text; + } + + return ResolveImgPattern.Replace(text, match => + { + // match groups: + // - 1 = from the beginning of the image tag until src attribute value begins + // - 2 = the src attribute value excluding the querystring (if present) + // - 3 = anything after group 2 and before the data-udi attribute value begins + // - 4 = the data-udi attribute value + // - 5 = anything after group 4 until the image tag is closed + var src = match.Groups[2].Value; + var udi = match.Groups[4].Value; + if(src.IsNullOrWhiteSpace() || udi.IsNullOrWhiteSpace() || GuidUdi.TryParse(udi, out var guidUdi) == false) + { + return match.Value; + } + var media = Current.UmbracoContext.MediaCache.GetById(guidUdi.Guid); + if(media == null) + { + // image does not exist - we could choose to remove the image entirely here (return empty string), + // but that would leave the editors completely in the dark as to why the image doesn't show + return match.Value; + } + + var url = media.Url; + return $"{match.Groups[1].Value}{url}{match.Groups[3].Value}{udi}{match.Groups[5].Value}"; + }); + } } }