From cf4335e5ba7613cae62cbd0db9b88781f7b99f3d Mon Sep 17 00:00:00 2001 From: Sipke Schoorstra Date: Fri, 19 Apr 2024 11:20:32 +0200 Subject: [PATCH] #6193: IHtmlFilter and TokenFilter improvements and bugfixes (#6938) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * IHtmlFilter and TokenFilter improvements and bugfixes. This changeset unifies the two separate TokenFilter implementations (one for BodyPart, TextField, etc and another one for certain elements such as Html). It also fixes a bug with the TokenFilter when executing for HtmlWidget, where the wrong content item is being recorded by the handler (the original implementation). Thirdly, it removes awkward code repetition by moving filter execution into a dedicated HtmlFilterRunner service. * Renaming IHtmlFilterRunner to IHtmlFilterProcessor (and its references) * Applying IHtmlFilterProcessor to HtmlMenuItems too + code styling in BodyPartDriver * Fixing FeedControllerTests.CorePartValuesAreExtracted * Code styling --------- Co-authored-by: Jean-Thierry Kéchichian Co-authored-by: Sipke Schoorstra Co-authored-by: Benedek Farkas --- .../Feeds/Controllers/FeedControllerTests.cs | 2 + .../Core/Common/Drivers/BodyPartDriver.cs | 45 +++++++------------ .../Core/Common/Drivers/TextFieldDriver.cs | 9 ++-- .../Core/Common/Models/BodyPart.cs | 8 ++++ .../Core/Common/Services/BbcodeFilter.cs | 21 +++++---- .../Core/Common/Services/TextFieldFilter.cs | 6 +-- .../CorePartsFeedItemBuilder.cs | 10 ++--- .../Feeds/StandardBuilders/ItemInspector.cs | 12 ++--- .../StandardQueries/ContainerFeedQuery.cs | 13 +++--- .../Views/MenuItemLink-HtmlMenuItem.cshtml | 11 ++++- .../Markdown/Services/MarkdownFilter.cs | 13 +++--- .../Services/Rendering/CloudVideoFilter.cs | 6 +-- .../Drivers/HeadingElementDriver.cs | 10 ++--- .../Drivers/HtmlElementDriver.cs | 13 +++--- .../Drivers/MarkdownElementDriver.cs | 13 +++--- .../Drivers/ParagraphElementDriver.cs | 10 ++--- .../Drivers/TextElementDriver.cs | 13 +++--- .../Orchard.Layouts/Filters/TokensFilter.cs | 34 -------------- .../Modules/Orchard.Layouts/Module.txt | 2 +- .../Orchard.Layouts/Orchard.Layouts.csproj | 4 -- .../Services/ElementFilterProcessor.cs | 19 -------- .../Services/IElementFilter.cs | 8 ---- .../Services/IElementFilterProcessor.cs | 8 ---- .../StandardQueries/QueryFeedQuery.cs | 13 +++--- .../Orchard.Tags/Feeds/TagFeedQuery.cs | 35 +++++---------- .../Orchard.Tokens/Filters/TokensFilter.cs | 36 +++++---------- .../Modules/Orchard.Tokens/Module.txt | 1 + src/Orchard/Orchard.Framework.csproj | 4 ++ src/Orchard/Services/HtmlFilter.cs | 5 +++ src/Orchard/Services/HtmlFilterContext.cs | 8 ++++ src/Orchard/Services/HtmlFilterProcessor.cs | 16 +++++++ src/Orchard/Services/IHtmlFilter.cs | 4 +- src/Orchard/Services/IHtmlFilterProcessor.cs | 28 ++++++++++++ 33 files changed, 202 insertions(+), 238 deletions(-) delete mode 100644 src/Orchard.Web/Modules/Orchard.Layouts/Filters/TokensFilter.cs delete mode 100644 src/Orchard.Web/Modules/Orchard.Layouts/Services/ElementFilterProcessor.cs delete mode 100644 src/Orchard.Web/Modules/Orchard.Layouts/Services/IElementFilter.cs delete mode 100644 src/Orchard.Web/Modules/Orchard.Layouts/Services/IElementFilterProcessor.cs create mode 100644 src/Orchard/Services/HtmlFilter.cs create mode 100644 src/Orchard/Services/HtmlFilterContext.cs create mode 100644 src/Orchard/Services/HtmlFilterProcessor.cs create mode 100644 src/Orchard/Services/IHtmlFilterProcessor.cs diff --git a/src/Orchard.Core.Tests/Feeds/Controllers/FeedControllerTests.cs b/src/Orchard.Core.Tests/Feeds/Controllers/FeedControllerTests.cs index 56c07dc07..151d9773a 100644 --- a/src/Orchard.Core.Tests/Feeds/Controllers/FeedControllerTests.cs +++ b/src/Orchard.Core.Tests/Feeds/Controllers/FeedControllerTests.cs @@ -20,6 +20,7 @@ using Orchard.Core.Feeds.StandardBuilders; using Orchard.Tests.Modules; using Orchard.Tests.Stubs; using Orchard.Core.Title.Models; +using Orchard.Services; namespace Orchard.Core.Tests.Feeds.Controllers { [TestFixture] @@ -177,6 +178,7 @@ namespace Orchard.Core.Tests.Feeds.Controllers { builder.RegisterInstance(mockContentManager.Object).As(); builder.RegisterType().As(); builder.RegisterType().As(); + builder.RegisterType().As(); builder.RegisterInstance(query).As(); var container = builder.Build(); diff --git a/src/Orchard.Web/Core/Common/Drivers/BodyPartDriver.cs b/src/Orchard.Web/Core/Common/Drivers/BodyPartDriver.cs index 064dee05f..55c46eac2 100644 --- a/src/Orchard.Web/Core/Common/Drivers/BodyPartDriver.cs +++ b/src/Orchard.Web/Core/Common/Drivers/BodyPartDriver.cs @@ -1,12 +1,9 @@ -using System.Collections.Generic; -using System.Linq; -using System.Web; +using System.Web; using Orchard.Mvc.Html; using Orchard.ContentManagement; using Orchard.ContentManagement.Aspects; using Orchard.ContentManagement.Drivers; using Orchard.Core.Common.Models; -using Orchard.Core.Common.Settings; using Orchard.Core.Common.ViewModels; using Orchard.Services; using System.Web.Mvc; @@ -15,13 +12,13 @@ using Orchard.ContentManagement.Handlers; namespace Orchard.Core.Common.Drivers { public class BodyPartDriver : ContentPartDriver { - private readonly IEnumerable _htmlFilters; + private readonly IHtmlFilterProcessor _htmlFilterProcessor; private readonly RequestContext _requestContext; private const string TemplateName = "Parts.Common.Body"; - public BodyPartDriver(IOrchardServices services, IEnumerable htmlFilters, RequestContext requestContext) { - _htmlFilters = htmlFilters; + public BodyPartDriver(IOrchardServices services, IHtmlFilterProcessor htmlFilterProcessor, RequestContext requestContext) { + _htmlFilterProcessor = htmlFilterProcessor; Services = services; _requestContext = requestContext; } @@ -33,32 +30,27 @@ namespace Orchard.Core.Common.Drivers { } protected override DriverResult Display(BodyPart part, string displayType, dynamic shapeHelper) { + string GetProcessedBodyText() => _htmlFilterProcessor.ProcessFilters(part.Text, part.GetFlavor(), part); + return Combined( - ContentShape("Parts_Common_Body", - () => { - var bodyText = _htmlFilters.Aggregate(part.Text, (text, filter) => filter.ProcessContent(text, GetFlavor(part))); - return shapeHelper.Parts_Common_Body(Html: new HtmlString(bodyText)); - }), - ContentShape("Parts_Common_Body_Summary", - () => { - var bodyText = _htmlFilters.Aggregate(part.Text, (text, filter) => filter.ProcessContent(text, GetFlavor(part))); - return shapeHelper.Parts_Common_Body_Summary(Html: new HtmlString(bodyText)); - }) - ); + ContentShape("Parts_Common_Body", () => + shapeHelper.Parts_Common_Body(Html: new HtmlString(GetProcessedBodyText()))), + ContentShape("Parts_Common_Body_Summary", () => + shapeHelper.Parts_Common_Body_Summary(Html: new HtmlString(GetProcessedBodyText())))); } protected override DriverResult Editor(BodyPart part, dynamic shapeHelper) { var model = BuildEditorViewModel(part,_requestContext); - return ContentShape("Parts_Common_Body_Edit", - () => shapeHelper.EditorTemplate(TemplateName: TemplateName, Model: model, Prefix: Prefix)); + return ContentShape("Parts_Common_Body_Edit", () => + shapeHelper.EditorTemplate(TemplateName: TemplateName, Model: model, Prefix: Prefix)); } protected override DriverResult Editor(BodyPart part, IUpdateModel updater, dynamic shapeHelper) { var model = BuildEditorViewModel(part, _requestContext); updater.TryUpdateModel(model, Prefix, null, null); - return ContentShape("Parts_Common_Body_Edit", - () => shapeHelper.EditorTemplate(TemplateName: TemplateName, Model: model, Prefix: Prefix)); + return ContentShape("Parts_Common_Body_Edit", () => + shapeHelper.EditorTemplate(TemplateName: TemplateName, Model: model, Prefix: Prefix)); } protected override void Importing(BodyPart part, ContentManagement.Handlers.ImportContentContext context) { @@ -83,18 +75,11 @@ namespace Orchard.Core.Common.Drivers { private static BodyEditorViewModel BuildEditorViewModel(BodyPart part,RequestContext requestContext) { return new BodyEditorViewModel { BodyPart = part, - EditorFlavor = GetFlavor(part), + EditorFlavor = part.GetFlavor(), AddMediaPath = new PathBuilder(part,requestContext).AddContentType().AddContainerSlug().ToString() }; } - private static string GetFlavor(BodyPart part) { - var typePartSettings = part.Settings.GetModel(); - return (typePartSettings != null && !string.IsNullOrWhiteSpace(typePartSettings.Flavor)) - ? typePartSettings.Flavor - : part.PartDefinition.Settings.GetModel().FlavorDefault; - } - class PathBuilder { private readonly IContent _content; private string _path; diff --git a/src/Orchard.Web/Core/Common/Drivers/TextFieldDriver.cs b/src/Orchard.Web/Core/Common/Drivers/TextFieldDriver.cs index b29b3cb44..8154ad25e 100644 --- a/src/Orchard.Web/Core/Common/Drivers/TextFieldDriver.cs +++ b/src/Orchard.Web/Core/Common/Drivers/TextFieldDriver.cs @@ -14,10 +14,10 @@ using Orchard.Utility.Extensions; namespace Orchard.Core.Common.Drivers { public class TextFieldDriver : ContentFieldDriver { - private readonly IEnumerable _htmlFilters; + private readonly IHtmlFilterProcessor _htmlFilterProcessor; - public TextFieldDriver(IOrchardServices services, IEnumerable htmlFilters) { - _htmlFilters = htmlFilters; + public TextFieldDriver(IOrchardServices services, IHtmlFilterProcessor htmlFilterProcessor) { + _htmlFilterProcessor = htmlFilterProcessor; Services = services; T = NullLocalizer.Instance; } @@ -37,8 +37,7 @@ namespace Orchard.Core.Common.Drivers { return ContentShape("Fields_Common_Text", GetDifferentiator(field, part), () => { var settings = field.PartFieldDefinition.Settings.GetModel(); - - object fieldValue = new HtmlString(_htmlFilters.Aggregate(field.Value, (text, filter) => filter.ProcessContent(text, settings.Flavor))); + var fieldValue = new HtmlString(_htmlFilterProcessor.ProcessFilters(field.Value, settings.Flavor, part)); return shapeHelper.Fields_Common_Text(Name: field.Name, Value: fieldValue); }); } diff --git a/src/Orchard.Web/Core/Common/Models/BodyPart.cs b/src/Orchard.Web/Core/Common/Models/BodyPart.cs index 7d191cce2..c797fb686 100644 --- a/src/Orchard.Web/Core/Common/Models/BodyPart.cs +++ b/src/Orchard.Web/Core/Common/Models/BodyPart.cs @@ -1,4 +1,5 @@ using Orchard.ContentManagement; +using Orchard.Core.Common.Settings; namespace Orchard.Core.Common.Models { public class BodyPart : ContentPart { @@ -11,5 +12,12 @@ namespace Orchard.Core.Common.Models { get { return Retrieve(x => x.Format); } set { Store(x => x.Format, value); } } + + public string GetFlavor() { + var typePartSettings = Settings.GetModel(); + return string.IsNullOrWhiteSpace(typePartSettings?.Flavor) + ? PartDefinition.Settings.GetModel().FlavorDefault + : typePartSettings.Flavor; + } } } diff --git a/src/Orchard.Web/Core/Common/Services/BbcodeFilter.cs b/src/Orchard.Web/Core/Common/Services/BbcodeFilter.cs index 33c406cfd..78a2e4f89 100644 --- a/src/Orchard.Web/Core/Common/Services/BbcodeFilter.cs +++ b/src/Orchard.Web/Core/Common/Services/BbcodeFilter.cs @@ -5,27 +5,26 @@ using System.Web; using Orchard.Services; namespace Orchard.Core.Common.Services { - public class BbcodeFilter : IHtmlFilter { - public string ProcessContent(string text, string flavor) { - return BbcodeReplace(text); + public class BbcodeFilter : HtmlFilter { + public override string ProcessContent(string text, HtmlFilterContext context) { + return BbcodeReplace(text, context); } // Can be moved somewhere else once we have IoC enabled body text filters. - private static string BbcodeReplace(string text) { - if (string.IsNullOrEmpty(text)) - return string.Empty; + private static string BbcodeReplace(string text, HtmlFilterContext context) { + if (String.IsNullOrEmpty(text)) + return String.Empty; - // optimize code path if nothing to do + // Optimize code path if nothing to do. if (!text.Contains("[url]") && !text.Contains("[img]") && !text.Contains("[url=")) { return text; } var sb = new StringBuilder(text); - var index = -1; var allIndexes = new List(); - // process all [url] + // Process all [url]. while (-1 != (index = text.IndexOf("[url]", index + 1, StringComparison.Ordinal))) { allIndexes.Add(index); } @@ -63,7 +62,7 @@ namespace Orchard.Core.Common.Services { var url = text.Substring(start + 5, urlEnd - start - 5); var title = text.Substring(urlEnd + 1, end - urlEnd - 1); - // substitue [url] by + // Substitute [url] by . sb.Remove(start, end - start + 6); sb.Insert(start, String.Format("{1}", url, title)); } @@ -85,7 +84,7 @@ namespace Orchard.Core.Common.Services { var url = text.Substring(start + 5, end - start - 5); - // substitue [url] by + // Substitue [url] by . sb.Remove(start, end - start + 6); if (!string.IsNullOrEmpty(url)) { diff --git a/src/Orchard.Web/Core/Common/Services/TextFieldFilter.cs b/src/Orchard.Web/Core/Common/Services/TextFieldFilter.cs index 263d17af5..75713da33 100644 --- a/src/Orchard.Web/Core/Common/Services/TextFieldFilter.cs +++ b/src/Orchard.Web/Core/Common/Services/TextFieldFilter.cs @@ -4,10 +4,10 @@ using Orchard.Services; using Orchard.Utility.Extensions; namespace Orchard.Core.Common.Services { - public class TextFieldFilter : IHtmlFilter { - public string ProcessContent(string text, string flavor) { + public class TextFieldFilter : HtmlFilter { + public override string ProcessContent(string text, HtmlFilterContext context) { // Flavor is null for a normal input/text field - return flavor == null || string.Equals(flavor, "textarea", StringComparison.OrdinalIgnoreCase) ? ReplaceNewLines(text) : text; + return context.Flavor == null || String.Equals(context.Flavor, "textarea", StringComparison.OrdinalIgnoreCase) ? ReplaceNewLines(text) : text; } private static string ReplaceNewLines(string text) { diff --git a/src/Orchard.Web/Core/Feeds/StandardBuilders/CorePartsFeedItemBuilder.cs b/src/Orchard.Web/Core/Feeds/StandardBuilders/CorePartsFeedItemBuilder.cs index 79f36b8ab..84a9957ad 100644 --- a/src/Orchard.Web/Core/Feeds/StandardBuilders/CorePartsFeedItemBuilder.cs +++ b/src/Orchard.Web/Core/Feeds/StandardBuilders/CorePartsFeedItemBuilder.cs @@ -13,15 +13,15 @@ namespace Orchard.Core.Feeds.StandardBuilders { public class CorePartsFeedItemBuilder : IFeedItemBuilder { private readonly IContentManager _contentManager; private readonly RouteCollection _routes; - private readonly IEnumerable _htmlFilters; + private readonly IHtmlFilterProcessor _htmlFilterProcessor; public CorePartsFeedItemBuilder( IContentManager contentManager, RouteCollection routes, - IEnumerable htmlFilters) { + IHtmlFilterProcessor htmlFilterProcessor) { _contentManager = contentManager; _routes = routes; - _htmlFilters = htmlFilters; + _htmlFilterProcessor = htmlFilterProcessor; } public void Populate(FeedContext context) { @@ -29,8 +29,8 @@ namespace Orchard.Core.Feeds.StandardBuilders { var inspector = new ItemInspector( feedItem.Item, - _contentManager.GetItemMetadata(feedItem.Item), - _htmlFilters); + _contentManager.GetItemMetadata(feedItem.Item), + _htmlFilterProcessor); // author is intentionally left empty as it could result in unwanted spam diff --git a/src/Orchard.Web/Core/Feeds/StandardBuilders/ItemInspector.cs b/src/Orchard.Web/Core/Feeds/StandardBuilders/ItemInspector.cs index a382c0fe8..b05c5c8d0 100644 --- a/src/Orchard.Web/Core/Feeds/StandardBuilders/ItemInspector.cs +++ b/src/Orchard.Web/Core/Feeds/StandardBuilders/ItemInspector.cs @@ -12,17 +12,17 @@ namespace Orchard.Core.Feeds.StandardBuilders { public class ItemInspector { private readonly IContent _item; private readonly ContentItemMetadata _metadata; - private readonly IEnumerable _htmlFilters; + private readonly IHtmlFilterProcessor _htmlFilterProcessor; private readonly ICommonPart _common; private readonly ITitleAspect _titleAspect; private readonly BodyPart _body; - public ItemInspector(IContent item, ContentItemMetadata metadata) : this(item, metadata, Enumerable.Empty()) {} + public ItemInspector(IContent item, ContentItemMetadata metadata) : this(item, metadata, null) {} - public ItemInspector(IContent item, ContentItemMetadata metadata, IEnumerable htmlFilters) { + public ItemInspector(IContent item, ContentItemMetadata metadata, IHtmlFilterProcessor htmlFilterProcessor) { _item = item; _metadata = metadata; - _htmlFilters = htmlFilters; + _htmlFilterProcessor = htmlFilterProcessor; _common = item.Get(); _titleAspect = item.Get(); _body = item.Get(); @@ -49,8 +49,8 @@ namespace Orchard.Core.Feeds.StandardBuilders { public string Description { get { - if (_body != null && !string.IsNullOrEmpty(_body.Text)) { - return _htmlFilters.Aggregate(_body.Text, (text, filter) => filter.ProcessContent(text, GetFlavor(_body))); + if (_htmlFilterProcessor != null && _body != null && !string.IsNullOrEmpty(_body.Text)) { + return _htmlFilterProcessor.ProcessFilters(_body.Text, GetFlavor(_body), _body); } return Title; } diff --git a/src/Orchard.Web/Core/Feeds/StandardQueries/ContainerFeedQuery.cs b/src/Orchard.Web/Core/Feeds/StandardQueries/ContainerFeedQuery.cs index c1550e7be..694831a1b 100644 --- a/src/Orchard.Web/Core/Feeds/StandardQueries/ContainerFeedQuery.cs +++ b/src/Orchard.Web/Core/Feeds/StandardQueries/ContainerFeedQuery.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.Web.Mvc; using System.Xml.Linq; using Orchard.ContentManagement; @@ -8,16 +7,16 @@ using Orchard.Core.Feeds.Models; using Orchard.Core.Feeds.StandardBuilders; using Orchard.Mvc.Extensions; using Orchard.Services; -using Orchard.Utility.Extensions; -namespace Orchard.Core.Feeds.StandardQueries { +namespace Orchard.Core.Feeds.StandardQueries +{ public class ContainerFeedQuery : IFeedQueryProvider, IFeedQuery { private readonly IContentManager _contentManager; - private readonly IEnumerable _htmlFilters; + private readonly IHtmlFilterProcessor _htmlFilterProcessor; - public ContainerFeedQuery(IContentManager contentManager, IEnumerable htmlFilters) { + public ContainerFeedQuery(IContentManager contentManager, IHtmlFilterProcessor htmlFilterProcessor) { _contentManager = contentManager; - _htmlFilters = htmlFilters; + _htmlFilterProcessor = htmlFilterProcessor; } public FeedQueryMatch Match(FeedContext context) { @@ -55,7 +54,7 @@ namespace Orchard.Core.Feeds.StandardQueries { return; } - var inspector = new ItemInspector(container, _contentManager.GetItemMetadata(container), _htmlFilters); + var inspector = new ItemInspector(container, _contentManager.GetItemMetadata(container), _htmlFilterProcessor); if (context.Format == "rss") { var link = new XElement("link"); context.Response.Element.SetElementValue("title", inspector.Title); diff --git a/src/Orchard.Web/Core/Navigation/Views/MenuItemLink-HtmlMenuItem.cshtml b/src/Orchard.Web/Core/Navigation/Views/MenuItemLink-HtmlMenuItem.cshtml index 6ac21f404..12a799df2 100644 --- a/src/Orchard.Web/Core/Navigation/Views/MenuItemLink-HtmlMenuItem.cshtml +++ b/src/Orchard.Web/Core/Navigation/Views/MenuItemLink-HtmlMenuItem.cshtml @@ -1 +1,10 @@ -@Html.Raw(Model.Content.BodyPart.Text) +@using Orchard.Core.Common.Models +@using Orchard.Services + +@{ + var htmlFilterProcessor = WorkContext.Resolve(); + var bodyPart = Model.Content.BodyPart as BodyPart; + var bodyText = htmlFilterProcessor.ProcessFilters(bodyPart.Text, bodyPart.GetFlavor(), bodyPart); +} + +@Html.Raw(bodyText) diff --git a/src/Orchard.Web/Modules/Markdown/Services/MarkdownFilter.cs b/src/Orchard.Web/Modules/Markdown/Services/MarkdownFilter.cs index cf5d1db3e..ec66bb30e 100644 --- a/src/Orchard.Web/Modules/Markdown/Services/MarkdownFilter.cs +++ b/src/Orchard.Web/Modules/Markdown/Services/MarkdownFilter.cs @@ -1,15 +1,16 @@ using System; using Orchard.Services; -namespace Markdown.Services { - public class MarkdownFilter : IHtmlFilter { - public string ProcessContent(string text, string flavor) { - return String.Equals(flavor, "markdown", StringComparison.OrdinalIgnoreCase) ? MarkdownReplace(text) : text; +namespace Markdown.Services +{ + public class MarkdownFilter : HtmlFilter { + public override string ProcessContent(string text, HtmlFilterContext context) { + return String.Equals(context.Flavor, "markdown", StringComparison.OrdinalIgnoreCase) ? MarkdownReplace(text) : text; } private static string MarkdownReplace(string text) { - if (string.IsNullOrEmpty(text)) - return string.Empty; + if (String.IsNullOrEmpty(text)) + return String.Empty; return Markdig.Markdown.ToHtml(text); } diff --git a/src/Orchard.Web/Modules/Orchard.Azure.MediaServices/Services/Rendering/CloudVideoFilter.cs b/src/Orchard.Web/Modules/Orchard.Azure.MediaServices/Services/Rendering/CloudVideoFilter.cs index 56d475d85..b98ee9727 100644 --- a/src/Orchard.Web/Modules/Orchard.Azure.MediaServices/Services/Rendering/CloudVideoFilter.cs +++ b/src/Orchard.Web/Modules/Orchard.Azure.MediaServices/Services/Rendering/CloudVideoFilter.cs @@ -12,7 +12,7 @@ using Orchard.MediaLibrary.Models; using Orchard.Services; namespace Orchard.Azure.MediaServices.Services.Rendering { - public class CloudVideoFilter : IHtmlFilter { + public class CloudVideoFilter : HtmlFilter { private readonly IShapeFactory _shapeFactory; private readonly IContentManager _contentManager; private readonly IShapeDisplay _shapeDisplay; @@ -23,8 +23,8 @@ namespace Orchard.Azure.MediaServices.Services.Rendering { _shapeDisplay = shapeDisplay; } - public string ProcessContent(string text, string flavor) { - return String.Equals(flavor, "html", StringComparison.OrdinalIgnoreCase) ? ReplaceVideoPlaceholder(text) : text; + public override string ProcessContent(string text, HtmlFilterContext context) { + return String.Equals(context.Flavor, "html", StringComparison.OrdinalIgnoreCase) ? ReplaceVideoPlaceholder(text) : text; } private string ReplaceVideoPlaceholder(string text) { diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Drivers/HeadingElementDriver.cs b/src/Orchard.Web/Modules/Orchard.Layouts/Drivers/HeadingElementDriver.cs index 0bc14c531..d122e6eb5 100644 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Drivers/HeadingElementDriver.cs +++ b/src/Orchard.Web/Modules/Orchard.Layouts/Drivers/HeadingElementDriver.cs @@ -2,15 +2,15 @@ using Orchard.Layouts.Framework.Display; using Orchard.Layouts.Framework.Drivers; using Orchard.Layouts.Helpers; -using Orchard.Layouts.Services; using Orchard.Layouts.ViewModels; +using Orchard.Services; namespace Orchard.Layouts.Drivers { public class HeadingElementDriver : ElementDriver { - private readonly IElementFilterProcessor _processor; + private readonly IHtmlFilterProcessor _htmlFilterProcessor; - public HeadingElementDriver(IElementFilterProcessor processor) { - _processor = processor; + public HeadingElementDriver(IHtmlFilterProcessor htmlFilterProcessor) { + _htmlFilterProcessor = htmlFilterProcessor; } protected override EditorResult OnBuildEditor(Heading element, ElementEditorContext context) { @@ -30,7 +30,7 @@ namespace Orchard.Layouts.Drivers { } protected override void OnDisplaying(Heading element, ElementDisplayingContext context) { - context.ElementShape.ProcessedContent = _processor.ProcessContent(element.Content, "html", context.GetTokenData()); + context.ElementShape.ProcessedContent = _htmlFilterProcessor.ProcessFilters(element.Content, new HtmlFilterContext { Flavor = "html", Data = context.GetTokenData() }); context.ElementShape.Level = element.Level; } } diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Drivers/HtmlElementDriver.cs b/src/Orchard.Web/Modules/Orchard.Layouts/Drivers/HtmlElementDriver.cs index eb62d7616..8e7c050b6 100644 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Drivers/HtmlElementDriver.cs +++ b/src/Orchard.Web/Modules/Orchard.Layouts/Drivers/HtmlElementDriver.cs @@ -2,15 +2,16 @@ using Orchard.Layouts.Framework.Display; using Orchard.Layouts.Framework.Drivers; using Orchard.Layouts.Helpers; -using Orchard.Layouts.Services; using Orchard.Layouts.ViewModels; +using Orchard.Services; -namespace Orchard.Layouts.Drivers { +namespace Orchard.Layouts.Drivers +{ public class HtmlElementDriver : ElementDriver { - private readonly IElementFilterProcessor _processor; + private readonly IHtmlFilterProcessor _htmlFilterProcessor; - public HtmlElementDriver(IElementFilterProcessor processor) { - _processor = processor; + public HtmlElementDriver(IHtmlFilterProcessor htmlFilterProcessor) { + _htmlFilterProcessor = htmlFilterProcessor; } protected override EditorResult OnBuildEditor(Html element, ElementEditorContext context) { @@ -29,7 +30,7 @@ namespace Orchard.Layouts.Drivers { } protected override void OnDisplaying(Html element, ElementDisplayingContext context) { - context.ElementShape.ProcessedContent = _processor.ProcessContent(element.Content, "html", context.GetTokenData()); + context.ElementShape.ProcessedContent = _htmlFilterProcessor.ProcessFilters(element.Content, new HtmlFilterContext { Flavor = "html", Data = context.GetTokenData() }); } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Drivers/MarkdownElementDriver.cs b/src/Orchard.Web/Modules/Orchard.Layouts/Drivers/MarkdownElementDriver.cs index e988c89a1..8e7f8d612 100644 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Drivers/MarkdownElementDriver.cs +++ b/src/Orchard.Web/Modules/Orchard.Layouts/Drivers/MarkdownElementDriver.cs @@ -2,16 +2,17 @@ using Orchard.Layouts.Framework.Display; using Orchard.Layouts.Framework.Drivers; using Orchard.Layouts.Helpers; -using Orchard.Layouts.Services; using Orchard.Layouts.ViewModels; +using Orchard.Services; using MarkdownElement = Orchard.Layouts.Elements.Markdown; -namespace Orchard.Layouts.Drivers { +namespace Orchard.Layouts.Drivers +{ [OrchardFeature("Orchard.Layouts.Markdown")] public class MarkdownElementDriver : ElementDriver { - private readonly IElementFilterProcessor _processor; - public MarkdownElementDriver(IElementFilterProcessor processor) { - _processor = processor; + private readonly IHtmlFilterProcessor _htmlFilterProcessor; + public MarkdownElementDriver(IHtmlFilterProcessor htmlFilterProcessor) { + _htmlFilterProcessor = htmlFilterProcessor; } protected override EditorResult OnBuildEditor(MarkdownElement element, ElementEditorContext context) { @@ -29,7 +30,7 @@ namespace Orchard.Layouts.Drivers { } protected override void OnDisplaying(MarkdownElement element, ElementDisplayingContext context) { - context.ElementShape.ProcessedContent = _processor.ProcessContent(element.Content, "markdown", context.GetTokenData()); + context.ElementShape.ProcessedContent = _htmlFilterProcessor.ProcessFilters(element.Content, new HtmlFilterContext { Flavor = "markdown", Data = context.GetTokenData() }); } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Drivers/ParagraphElementDriver.cs b/src/Orchard.Web/Modules/Orchard.Layouts/Drivers/ParagraphElementDriver.cs index 0d285207a..1aca94f2a 100644 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Drivers/ParagraphElementDriver.cs +++ b/src/Orchard.Web/Modules/Orchard.Layouts/Drivers/ParagraphElementDriver.cs @@ -2,15 +2,15 @@ using Orchard.Layouts.Framework.Display; using Orchard.Layouts.Framework.Drivers; using Orchard.Layouts.Helpers; -using Orchard.Layouts.Services; using Orchard.Layouts.ViewModels; +using Orchard.Services; namespace Orchard.Layouts.Drivers { public class ParagraphElementDriver : ElementDriver { - private readonly IElementFilterProcessor _processor; + private readonly IHtmlFilterProcessor _htmlFilterProcessor; - public ParagraphElementDriver(IElementFilterProcessor processor) { - _processor = processor; + public ParagraphElementDriver(IHtmlFilterProcessor htmlFilterProcessor) { + _htmlFilterProcessor = htmlFilterProcessor; } protected override EditorResult OnBuildEditor(Paragraph element, ElementEditorContext context) { @@ -28,7 +28,7 @@ namespace Orchard.Layouts.Drivers { } protected override void OnDisplaying(Paragraph element, ElementDisplayingContext context) { - context.ElementShape.ProcessedContent = _processor.ProcessContent(element.Content, "html", context.GetTokenData()); + context.ElementShape.ProcessedContent = _htmlFilterProcessor.ProcessFilters(element.Content, new HtmlFilterContext { Flavor = "html", Data = context.GetTokenData() }); } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Drivers/TextElementDriver.cs b/src/Orchard.Web/Modules/Orchard.Layouts/Drivers/TextElementDriver.cs index e85dad82c..87083dd7d 100644 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Drivers/TextElementDriver.cs +++ b/src/Orchard.Web/Modules/Orchard.Layouts/Drivers/TextElementDriver.cs @@ -2,15 +2,16 @@ using Orchard.Layouts.Framework.Display; using Orchard.Layouts.Framework.Drivers; using Orchard.Layouts.Helpers; -using Orchard.Layouts.Services; using Orchard.Layouts.ViewModels; +using Orchard.Services; -namespace Orchard.Layouts.Drivers { +namespace Orchard.Layouts.Drivers +{ public class TextElementDriver : ElementDriver { - private readonly IElementFilterProcessor _processor; + private readonly IHtmlFilterProcessor _htmlFilterProcessor; - public TextElementDriver(IElementFilterProcessor processor) { - _processor = processor; + public TextElementDriver(IHtmlFilterProcessor htmlFilterProcessor) { + _htmlFilterProcessor = htmlFilterProcessor; } protected override EditorResult OnBuildEditor(Text element, ElementEditorContext context) { @@ -28,7 +29,7 @@ namespace Orchard.Layouts.Drivers { } protected override void OnDisplaying(Text element, ElementDisplayingContext context) { - context.ElementShape.ProcessedContent = _processor.ProcessContent(element.Content, "textarea", context.GetTokenData()); + context.ElementShape.ProcessedContent = _htmlFilterProcessor.ProcessFilters(element.Content, new HtmlFilterContext { Flavor = "textarea", Data = context.GetTokenData() }); } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Filters/TokensFilter.cs b/src/Orchard.Web/Modules/Orchard.Layouts/Filters/TokensFilter.cs deleted file mode 100644 index 1dc8a27a5..000000000 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Filters/TokensFilter.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System; -using Orchard.Environment.Extensions; -using Orchard.Layouts.Services; -using Orchard.Tokens; -using System.Collections.Generic; - -namespace Orchard.Layouts.Filters { - [OrchardFeature("Orchard.Layouts.Tokens")] - public class TokensFilter : IElementFilter { - - private readonly ITokenizer _tokenizer; - - public TokensFilter(ITokenizer tokenizer) { - _tokenizer = tokenizer; - } - - public string ProcessContent(string text, string flavor) { - return ProcessContent(text, flavor, new Dictionary()); - } - - public string ProcessContent(string text, string flavor, IDictionary context) { - if (String.IsNullOrEmpty(text)) - return ""; - - if (!text.Contains("#{")) { - return text; - } - - text = _tokenizer.Replace(text, context, new ReplaceOptions { Encoding = ReplaceOptions.NoEncode }); - - return text; - } - } -} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Module.txt b/src/Orchard.Web/Modules/Orchard.Layouts/Module.txt index 7dec211a0..7a42cf991 100644 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Module.txt +++ b/src/Orchard.Web/Modules/Orchard.Layouts/Module.txt @@ -29,7 +29,7 @@ Features: Dependencies: Orchard.Layouts, Orchard.Projections Orchard.Layouts.Tokens: Name: Element Tokens - Description: Provides an element token provider that enables elements to be rendered using a token and enables tokens to be used inside of various elements such as Html, Text and Paragraph. + Description: Provides an element token provider that enables elements to be rendered using a token. Category: Layout Dependencies: Orchard.Layouts, Orchard.Tokens Orchard.Layouts.UI: diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Orchard.Layouts.csproj b/src/Orchard.Web/Modules/Orchard.Layouts/Orchard.Layouts.csproj index ff45ec930..e207903e8 100644 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Orchard.Layouts.csproj +++ b/src/Orchard.Web/Modules/Orchard.Layouts/Orchard.Layouts.csproj @@ -319,7 +319,6 @@ - @@ -375,9 +374,6 @@ - - - diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Services/ElementFilterProcessor.cs b/src/Orchard.Web/Modules/Orchard.Layouts/Services/ElementFilterProcessor.cs deleted file mode 100644 index 2dd58b24f..000000000 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Services/ElementFilterProcessor.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System.Collections.Generic; -using Orchard.Services; - -namespace Orchard.Layouts.Services { - public class ElementFilterProcessor : IElementFilterProcessor { - private readonly IEnumerable _filters; - public ElementFilterProcessor(IEnumerable filters) { - _filters = filters; - } - - public string ProcessContent(string text, string flavor, IDictionary context) { - foreach (var htmlFilter in _filters) { - var elementFilter = htmlFilter as IElementFilter; - text = elementFilter != null ? elementFilter.ProcessContent(text, flavor, context) : htmlFilter.ProcessContent(text, flavor); - } - return text; - } - } -} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Services/IElementFilter.cs b/src/Orchard.Web/Modules/Orchard.Layouts/Services/IElementFilter.cs deleted file mode 100644 index 23d474c73..000000000 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Services/IElementFilter.cs +++ /dev/null @@ -1,8 +0,0 @@ -using System.Collections.Generic; -using Orchard.Services; - -namespace Orchard.Layouts.Services { - public interface IElementFilter : IHtmlFilter { - string ProcessContent(string text, string flavor, IDictionary context); - } -} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Layouts/Services/IElementFilterProcessor.cs b/src/Orchard.Web/Modules/Orchard.Layouts/Services/IElementFilterProcessor.cs deleted file mode 100644 index f66dbf07a..000000000 --- a/src/Orchard.Web/Modules/Orchard.Layouts/Services/IElementFilterProcessor.cs +++ /dev/null @@ -1,8 +0,0 @@ -using System.Collections.Generic; -using Orchard.Services; - -namespace Orchard.Layouts.Services { - public interface IElementFilterProcessor : IDependency { - string ProcessContent(string text, string flavor, IDictionary context); - } -} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Projections/StandardQueries/QueryFeedQuery.cs b/src/Orchard.Web/Modules/Orchard.Projections/StandardQueries/QueryFeedQuery.cs index d53d7228b..07b0d629e 100644 --- a/src/Orchard.Web/Modules/Orchard.Projections/StandardQueries/QueryFeedQuery.cs +++ b/src/Orchard.Web/Modules/Orchard.Projections/StandardQueries/QueryFeedQuery.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.Linq; using System.Web.Mvc; using System.Xml.Linq; @@ -11,22 +10,22 @@ using Orchard.Mvc.Extensions; using Orchard.Projections.Models; using Orchard.Projections.Services; using Orchard.Services; -using Orchard.Utility.Extensions; -namespace Orchard.Projections.StandardQueries { +namespace Orchard.Projections.StandardQueries +{ public class QueryFeedQuery : IFeedQueryProvider, IFeedQuery { private readonly IContentManager _contentManager; private readonly IProjectionManager _projectionManager; - private readonly IEnumerable _htmlFilters; + private readonly IHtmlFilterProcessor _htmlFilterProcessor; public QueryFeedQuery( IContentManager contentManager, IProjectionManager projectionManager, - IEnumerable htmlFilters) + IHtmlFilterProcessor htmlFilterProcessor) { _contentManager = contentManager; _projectionManager = projectionManager; - _htmlFilters = htmlFilters; + _htmlFilterProcessor = htmlFilterProcessor; } public FeedQueryMatch Match(FeedContext context) { @@ -55,7 +54,7 @@ namespace Orchard.Projections.StandardQueries { return; } - var inspector = new ItemInspector(container, _contentManager.GetItemMetadata(container), _htmlFilters); + var inspector = new ItemInspector(container, _contentManager.GetItemMetadata(container), _htmlFilterProcessor); if (context.Format == "rss") { var link = new XElement("link"); context.Response.Element.SetElementValue("title", inspector.Title); diff --git a/src/Orchard.Web/Modules/Orchard.Tags/Feeds/TagFeedQuery.cs b/src/Orchard.Web/Modules/Orchard.Tags/Feeds/TagFeedQuery.cs index b5fd415c3..2e30e643e 100644 --- a/src/Orchard.Web/Modules/Orchard.Tags/Feeds/TagFeedQuery.cs +++ b/src/Orchard.Web/Modules/Orchard.Tags/Feeds/TagFeedQuery.cs @@ -1,34 +1,21 @@ using System; -using System.Collections.Generic; using System.Web.Mvc; -using System.Xml.Linq; -using Orchard.ContentManagement; -using Orchard.Core.Common.Models; -using Orchard.Core.Feeds.Models; -using Orchard.Core.Feeds.StandardBuilders; -using Orchard.Mvc.Extensions; -using Orchard.Services; -using Orchard.Utility.Extensions; -using Orchard.Core.Feeds; -using Orchard.Tags.Services; -using Orchard.Localization; using System.Web.Routing; +using System.Xml.Linq; +using Orchard.Core.Feeds; +using Orchard.Core.Feeds.Models; using Orchard.Environment.Extensions; +using Orchard.Localization; +using Orchard.Mvc.Extensions; +using Orchard.Tags.Services; namespace Orchard.Tags.Feeds { [OrchardFeature("Orchard.Tags.Feeds")] public class TagFeedQuery : IFeedQueryProvider, IFeedQuery { - private readonly IContentManager _contentManager; - private readonly IEnumerable _htmlFilters; private readonly ITagService _tagService; - public TagFeedQuery( - IContentManager contentManager, - IEnumerable htmlFilters, - ITagService tagService) { - _contentManager = contentManager; + public TagFeedQuery(ITagService tagService) { _tagService = tagService; - _htmlFilters = htmlFilters; T = NullLocalizer.Instance; } @@ -42,11 +29,11 @@ namespace Orchard.Tags.Feeds { var tagName = (string)tagIdValue.ConvertTo(typeof(string)); var tag = _tagService.GetTagByName(tagName); - + if (tag == null) { return null; } - + return new FeedQueryMatch { FeedQuery = this, Priority = -5 }; } @@ -57,10 +44,10 @@ namespace Orchard.Tags.Feeds { var limitValue = context.ValueProvider.GetValue("limit"); var limit = 20; - if (limitValue != null) { + if (limitValue != null) { Int32.TryParse(Convert.ToString(limitValue), out limit); } - + limit = Math.Min(limit, 100); var tagName = (string)tagIdValue.ConvertTo(typeof(string)); diff --git a/src/Orchard.Web/Modules/Orchard.Tokens/Filters/TokensFilter.cs b/src/Orchard.Web/Modules/Orchard.Tokens/Filters/TokensFilter.cs index cab5c586b..fa301871a 100644 --- a/src/Orchard.Web/Modules/Orchard.Tokens/Filters/TokensFilter.cs +++ b/src/Orchard.Web/Modules/Orchard.Tokens/Filters/TokensFilter.cs @@ -1,49 +1,33 @@ using System; -using System.Collections.Generic; -using Orchard.ContentManagement; -using Orchard.ContentManagement.Handlers; using Orchard.Environment.Extensions; using Orchard.Services; namespace Orchard.Tokens.Filters { - [OrchardFeature("Orchard.Tokens.HtmlFilter")] - public class TokensFilter : ContentHandler, IHtmlFilter { + public class TokensFilter : HtmlFilter { private readonly ITokenizer _tokenizer; - private ContentItem _displayed; public TokensFilter(ITokenizer tokenizer) { _tokenizer = tokenizer; } - - protected override void BuildDisplayShape(BuildDisplayContext context) { - _displayed = context.ContentItem; + + public override string ProcessContent(string text, HtmlFilterContext context) { + return TokensReplace(text, context); } - public string ProcessContent(string text, string flavor) { - return TokensReplace(text); - } - - private string TokensReplace(string text) { + private string TokensReplace(string text, HtmlFilterContext context) { if (String.IsNullOrEmpty(text)) return String.Empty; // Optimize code path if nothing to do. - if (!text.Contains("#{")) { + if (!text.Contains("#{")) return text; - } - var data = new Dictionary(); - - if (_displayed != null) - data["Content"] = _displayed; - - text = _tokenizer.Replace(text, data); - - _displayed = null; - - return text; + return _tokenizer.Replace(text, context.Data, + String.Equals(context.Flavor, "html", StringComparison.OrdinalIgnoreCase) + ? new ReplaceOptions { Encoding = ReplaceOptions.HtmlEncode } + : new ReplaceOptions { Encoding = ReplaceOptions.NoEncode }); } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Tokens/Module.txt b/src/Orchard.Web/Modules/Orchard.Tokens/Module.txt index 2be37cd1b..d90c598cd 100644 --- a/src/Orchard.Web/Modules/Orchard.Tokens/Module.txt +++ b/src/Orchard.Web/Modules/Orchard.Tokens/Module.txt @@ -20,3 +20,4 @@ Features: Description: Evaluates tokens in a body. Category: Content Dependencies: Orchard.Tokens + Priority: -1 diff --git a/src/Orchard/Orchard.Framework.csproj b/src/Orchard/Orchard.Framework.csproj index 94eb529a1..d12aa8d05 100644 --- a/src/Orchard/Orchard.Framework.csproj +++ b/src/Orchard/Orchard.Framework.csproj @@ -432,7 +432,11 @@ + + + + diff --git a/src/Orchard/Services/HtmlFilter.cs b/src/Orchard/Services/HtmlFilter.cs new file mode 100644 index 000000000..09b729bb7 --- /dev/null +++ b/src/Orchard/Services/HtmlFilter.cs @@ -0,0 +1,5 @@ +namespace Orchard.Services { + public abstract class HtmlFilter : Component, IHtmlFilter { + public abstract string ProcessContent(string text, HtmlFilterContext context); + } +} diff --git a/src/Orchard/Services/HtmlFilterContext.cs b/src/Orchard/Services/HtmlFilterContext.cs new file mode 100644 index 000000000..cb821de97 --- /dev/null +++ b/src/Orchard/Services/HtmlFilterContext.cs @@ -0,0 +1,8 @@ +using System.Collections.Generic; + +namespace Orchard.Services { + public class HtmlFilterContext { + public string Flavor { get; set; } + public IDictionary Data { get; set; } = new Dictionary(); + } +} diff --git a/src/Orchard/Services/HtmlFilterProcessor.cs b/src/Orchard/Services/HtmlFilterProcessor.cs new file mode 100644 index 000000000..f1d2cfe9e --- /dev/null +++ b/src/Orchard/Services/HtmlFilterProcessor.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; +using System.Linq; + +namespace Orchard.Services { + public class HtmlFilterProcessor : IHtmlFilterProcessor { + private readonly IEnumerable _filters; + + public HtmlFilterProcessor(IEnumerable filters) { + _filters = filters; + } + + public string ProcessFilters(string text, HtmlFilterContext context) { + return _filters.Aggregate(text, (current, htmlFilter) => htmlFilter.ProcessContent(current, context)); + } + } +} diff --git a/src/Orchard/Services/IHtmlFilter.cs b/src/Orchard/Services/IHtmlFilter.cs index 6114dc3fb..0e206dbb0 100644 --- a/src/Orchard/Services/IHtmlFilter.cs +++ b/src/Orchard/Services/IHtmlFilter.cs @@ -1,5 +1,5 @@ namespace Orchard.Services { public interface IHtmlFilter : IDependency { - string ProcessContent(string text, string flavor); + string ProcessContent(string text, HtmlFilterContext context); } -} \ No newline at end of file +} diff --git a/src/Orchard/Services/IHtmlFilterProcessor.cs b/src/Orchard/Services/IHtmlFilterProcessor.cs new file mode 100644 index 000000000..aea5defa3 --- /dev/null +++ b/src/Orchard/Services/IHtmlFilterProcessor.cs @@ -0,0 +1,28 @@ +using System.Collections.Generic; +using Orchard.ContentManagement; + +namespace Orchard.Services { + public interface IHtmlFilterProcessor : IDependency { + string ProcessFilters(string text, HtmlFilterContext context); + } + + public static class HtmlFilterProcessorExtensions { + public static string ProcessFilters( + this IHtmlFilterProcessor processor, + string text, + string flavor, + IDictionary data) => + processor.ProcessFilters(text, new HtmlFilterContext { Flavor = flavor, Data = data }); + + public static string ProcessFilters(this IHtmlFilterProcessor processor, string text, string flavor) => + processor.ProcessFilters(text, new HtmlFilterContext { Flavor = flavor }); + + public static string ProcessFilters(this IHtmlFilterProcessor processor, string text, string flavor, IContent content) => + processor.ProcessFilters( + text, + new HtmlFilterContext { + Flavor = flavor, + Data = new Dictionary { { "Content", content.ContentItem } } + }); + } +}