diff --git a/src/Rhythm.Drop.Web.Infrastructure/TagHelperRenderers/Images/DropImageTagHelperRendererBase.cs b/src/Rhythm.Drop.Web.Infrastructure/TagHelperRenderers/Images/DropImageTagHelperRendererBase.cs
index 9b49d74..5f89784 100644
--- a/src/Rhythm.Drop.Web.Infrastructure/TagHelperRenderers/Images/DropImageTagHelperRendererBase.cs
+++ b/src/Rhythm.Drop.Web.Infrastructure/TagHelperRenderers/Images/DropImageTagHelperRendererBase.cs
@@ -1,234 +1,59 @@
namespace Rhythm.Drop.Web.Infrastructure.TagHelperRenderers.Images;
-using Microsoft.AspNetCore.Html;
-using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Razor.TagHelpers;
using Rhythm.Drop.Models.Images;
using Rhythm.Drop.Web.Infrastructure.TagHelperRenderers;
using System.Threading.Tasks;
///
-/// A base class for rendering when used in a .
+/// A base implementation for rendering a when used in a as an img HTML tag (without a picture HTML tag).
///
public abstract class DropImageTagHelperRendererBase : TagHelperRendererBase, IDropImageTagHelperRenderer
{
///
- protected override async Task RenderModelAsync(DropImageTagHelperRendererContext model, TagHelperContext context, TagHelperOutput output)
+ protected override Task RenderModelAsync(DropImageTagHelperRendererContext model, TagHelperContext context, TagHelperOutput output)
{
if (model.Image is null)
{
output.SuppressOutput();
- return;
+ return Task.CompletedTask;
}
- await Task.Run(() =>
- {
- var image = model.Image;
-
- if (ShouldRenderOutputAsPicture(image, context, output))
- {
- RenderOutputAsPicture(image, model.LoadingMode, context, output);
- }
- else
- {
- RenderOutputAsImg(image, model.LoadingMode, context, output);
- }
- });
- }
-
- ///
- /// Determines whether the output should be rendered as a picture HTML tag or a single img HTML tag.
- ///
- /// The image.
- /// The context.
- /// The output.
- /// A . If the output should be rendered a picture HTML tag. Otherwise it should be rendered a single img HTML tag.
- ///
- protected virtual bool ShouldRenderOutputAsPicture(IImage image, TagHelperContext context, TagHelperOutput output)
- {
- return image.Sources.Count > 0;
- }
-
- ///
- /// Renders a and as a picture HTML tag.
- ///
- /// The image.
- /// The loading mode.
- /// The context.
- /// The output.
- ///
- /// This is intended to be a developer friendly extension point to modify the a picture tag.
- /// This can be replaced entirely or the base method can be used as a starting point for modifications.
- ///
- protected virtual void RenderOutputAsPicture(IImage image, LoadingMode renderMode, TagHelperContext context, TagHelperOutput output)
- {
- output.TagName = "picture";
- output.TagMode = TagMode.StartTagAndEndTag;
-
- foreach (var source in image.Sources)
- {
- var sourceHtml = BuildImageSourceHtmlContent(source, renderMode, context, output);
-
- output.Content.AppendHtml(sourceHtml);
- }
+ var image = model.Image;
- var imgHtml = BuildImgHtmlContent(image, renderMode, context, output);
- output.Content.AppendHtml(imgHtml);
- }
-
- ///
- /// Renders a and as a single img HTML tag.
- ///
- /// The image.
- /// The loading mode.
- /// The context.
- /// The output.
- ///
- /// This is intended to be a developer friendly extension point to modify the img tag when no picture tag is present.
- /// This can be replaced entirely or the base method can be used as a starting point for modifications.
- ///
- protected virtual void RenderOutputAsImg(IImage image, LoadingMode renderMode, TagHelperContext context, TagHelperOutput output)
- {
output.TagName = "img";
- output.Attributes.SetAttribute("src", image.Url);
- output.Attributes.SetAttribute("alt", image.AltText);
-
- if (renderMode is LoadingMode.Lazy)
- {
- output.Attributes.SetAttribute("loading", "lazy");
- }
-
- if (image.Width > 0)
- {
- output.Attributes.SetAttribute("width", image.Width);
- }
-
- if (image.Height > 0)
- {
- output.Attributes.SetAttribute("height", image.Height);
- }
-
output.TagMode = TagMode.SelfClosing;
- }
- ///
- /// Creates a used by .
- ///
- /// The image.
- /// The loading mode.
- /// The context.
- /// The output.
- /// A .
- ///
- /// This is intended to be a developer friendly extension point to modify the img tag used by a picture tag.
- /// This can be replaced entirely or the base method can be used as a starting point for modifications.
- ///
- protected virtual TagBuilder CreateImgTagBuilder(IImage image, LoadingMode renderMode, TagHelperContext context, TagHelperOutput output)
- {
- var tagBuilder = new TagBuilder("img");
- tagBuilder.Attributes.Add("src", image.Url);
- tagBuilder.Attributes.Add("alt", image.AltText);
-
- if (renderMode is LoadingMode.Lazy)
- {
- tagBuilder.Attributes.Add("loading", "lazy");
- }
-
- if (image.Width > 0)
- {
- tagBuilder.Attributes.Add("width", image.Width.ToString());
- }
+ SetTagAttributes(image, model.LoadingMode, context, output);
- if (image.Height > 0)
- {
- tagBuilder.Attributes.Add("height", image.Height.ToString());
- }
-
- return tagBuilder;
+ return Task.CompletedTask;
}
///
- /// Creates a used by .
+ /// Sets the attributes of the tag helper output.
///
- /// The image source.
- /// The loading mode.
+ /// The model.
+ /// The loading mode.
/// The context.
/// The output.
- /// A .
- ///
- /// This is intended to be a developer friendly extension point to modify the source tag used by a picture tag.
- /// This can be replaced entirely or the base method can be used as a starting point for modifications.
- ///
- protected virtual TagBuilder CreateImageSourceTagBuilder(IImageSource source, LoadingMode renderMode, TagHelperContext context, TagHelperOutput output)
+ protected virtual void SetTagAttributes(IImage model, LoadingMode loadingMode, TagHelperContext context, TagHelperOutput output)
{
- var tagBuilder = new TagBuilder("source");
-
- tagBuilder.Attributes.Add("srcset", source.SourceSet.ToMarkupString());
-
- if (source.MediaQuery is not null)
- {
- tagBuilder.Attributes.Add("media", source.MediaQuery.ToMarkupString());
- }
+ output.Attributes.SetAttribute("src", model.Url);
+ output.Attributes.SetAttribute("alt", model.AltText);
- if (string.IsNullOrEmpty(source.MimeType) is false)
+ if (loadingMode is LoadingMode.Lazy)
{
- tagBuilder.Attributes.Add("type", source.MimeType);
+ output.Attributes.SetAttribute("loading", "lazy");
}
- if (source.Width > 0)
+ if (model.Width > 0)
{
- tagBuilder.Attributes.Add("width", source.Width.ToString());
+ output.Attributes.SetAttribute("width", model.Width);
}
- if (source.Height > 0)
+ if (model.Height > 0)
{
- tagBuilder.Attributes.Add("height", source.Height.ToString());
+ output.Attributes.SetAttribute("height", model.Height);
}
-
- return tagBuilder;
- }
-
- ///
- /// Builds the required by a img HTML tag when rendered within an picture HTML tag.
- ///
- /// The image.
- /// The loading mode.
- /// The context.
- /// The output.
- /// A .
- ///
- /// This is intended to be a developer friendly extension point to modify the source tag used by a picture tag.
- /// This should only bn replaced entirely if you do not intend to use the output from .
- ///
- protected IHtmlContent BuildImgHtmlContent(IImage image, LoadingMode renderMode, TagHelperContext context, TagHelperOutput output)
- {
- var tagBuilder = CreateImgTagBuilder(image, renderMode, context, output);
-
- return tagBuilder.RenderSelfClosingTag();
- }
-
- ///
- /// Builds the required by a source HTML tag when rendered within an picture HTML tag.
- ///
- /// The image source.
- /// The loading mode.
- /// The context.
- /// The output.
- /// A .
- ///
- /// This is intended to be a developer friendly extension point to modify the source tag used by a picture tag.
- /// This should only bn replaced entirely if you do not intend to use the output from .
- ///
- protected IHtmlContent BuildImageSourceHtmlContent(IImageSource source, LoadingMode renderMode, TagHelperContext context, TagHelperOutput output)
- {
- var tagBuilder = CreateImageSourceTagBuilder(source, renderMode, context, output);
-
- return tagBuilder.RenderSelfClosingTag();
- }
-
- ///
- protected override async Task RenderNullOrInvalidAsync(TagHelperContext context, TagHelperOutput output)
- {
- await Task.Run(output.SuppressOutput);
}
}
\ No newline at end of file
diff --git a/src/Rhythm.Drop.Web.Infrastructure/TagHelperRenderers/Images/DropPictureImageTagHelperRendererBase.cs b/src/Rhythm.Drop.Web.Infrastructure/TagHelperRenderers/Images/DropPictureImageTagHelperRendererBase.cs
new file mode 100644
index 0000000..01e6c3a
--- /dev/null
+++ b/src/Rhythm.Drop.Web.Infrastructure/TagHelperRenderers/Images/DropPictureImageTagHelperRendererBase.cs
@@ -0,0 +1,58 @@
+namespace Rhythm.Drop.Web.Infrastructure.TagHelperRenderers.Images;
+
+using Microsoft.AspNetCore.Razor.TagHelpers;
+using Rhythm.Drop.Models.Images;
+using System.Threading.Tasks;
+
+///
+/// A base implementation for rendering a when used in a as an img HTML tag within a picture HTML tag.
+///
+public abstract class DropPictureImageTagHelperRendererBase : TagHelperRendererBase, IDropPictureImageTagHelperRenderer
+{
+ ///
+ protected override Task RenderModelAsync(DropImageTagHelperRendererContext model, TagHelperContext context, TagHelperOutput output)
+ {
+ if (model.Image is null)
+ {
+ output.SuppressOutput();
+ return Task.CompletedTask;
+ }
+
+ var image = model.Image;
+
+ output.TagName = "img";
+ output.TagMode = TagMode.SelfClosing;
+
+ SetTagAttributes(image, model.LoadingMode, context, output);
+
+ return Task.CompletedTask;
+ }
+
+ ///
+ /// Sets the attributes of the tag helper output.
+ ///
+ /// The model.
+ /// The loading mode.
+ /// The context.
+ /// The output.
+ protected virtual void SetTagAttributes(IImage model, LoadingMode loadingMode, TagHelperContext context, TagHelperOutput output)
+ {
+ output.Attributes.SetAttribute("src", model.Url);
+ output.Attributes.SetAttribute("alt", model.AltText);
+
+ if (loadingMode is LoadingMode.Lazy)
+ {
+ output.Attributes.SetAttribute("loading", "lazy");
+ }
+
+ if (model.Width > 0)
+ {
+ output.Attributes.SetAttribute("width", model.Width);
+ }
+
+ if (model.Height > 0)
+ {
+ output.Attributes.SetAttribute("height", model.Height);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Rhythm.Drop.Web.Infrastructure/TagHelperRenderers/Images/DropPictureTagHelperRendererBase.cs b/src/Rhythm.Drop.Web.Infrastructure/TagHelperRenderers/Images/DropPictureTagHelperRendererBase.cs
new file mode 100644
index 0000000..d061734
--- /dev/null
+++ b/src/Rhythm.Drop.Web.Infrastructure/TagHelperRenderers/Images/DropPictureTagHelperRendererBase.cs
@@ -0,0 +1,183 @@
+namespace Rhythm.Drop.Web.Infrastructure.TagHelperRenderers.Images;
+
+using Microsoft.AspNetCore.Html;
+using Microsoft.AspNetCore.Mvc.Rendering;
+using Microsoft.AspNetCore.Razor.TagHelpers;
+using Rhythm.Drop.Models.Images;
+using System.Threading.Tasks;
+
+///
+/// A base implementation for rendering a when used in a as a picture HTML tag.
+///
+public abstract class DropPictureTagHelperRendererBase : TagHelperRendererBase, IDropPictureTagHelperRenderer
+{
+ ///
+ protected override async Task RenderModelAsync(DropImageTagHelperRendererContext model, TagHelperContext context, TagHelperOutput output)
+ {
+ if (model.Image is null)
+ {
+ output.SuppressOutput();
+ return;
+ }
+
+ var image = model.Image;
+ var loadingMode = model.LoadingMode;
+
+ output.TagName = "picture";
+ output.TagMode = TagMode.StartTagAndEndTag;
+
+ AppendSourcesContent(image, loadingMode, context, output);
+ await AppendImageContentAsync(image, loadingMode, context, output);
+ }
+
+ ///
+ /// Appends the collection to the tag helper output.
+ ///
+ /// The model.
+ /// The loading mode.
+ /// The context.
+ /// The output.
+ protected virtual void AppendSourcesContent(IImage model, LoadingMode loadingMode, TagHelperContext context, TagHelperOutput output)
+ {
+ foreach (var source in model.Sources)
+ {
+ var sourceHtml = BuildImageSourceHtmlContent(source, loadingMode, context, output);
+ output.PreContent.AppendHtml(sourceHtml);
+ }
+ }
+
+ ///
+ /// Appends the image HTML tag to the tag helper output if one doesn't already exist.
+ ///
+ /// The model.
+ /// The loading mode.
+ /// The context.
+ /// The output.
+ /// A .
+ protected virtual async Task AppendImageContentAsync(IImage model, LoadingMode loadingMode, TagHelperContext context, TagHelperOutput output)
+ {
+ var childContent = await output.GetChildContentAsync();
+ if (childContent.IsEmptyOrWhiteSpace is false)
+ {
+ return;
+ }
+
+ var imgHtml = BuildImgHtmlContent(model, loadingMode, context, output);
+ output.Content.AppendHtml(imgHtml);
+ }
+
+ ///
+ /// Creates a used by .
+ ///
+ /// The image.
+ /// The loading mode.
+ /// The context.
+ /// The output.
+ /// A .
+ ///
+ /// This is intended to be a developer friendly extension point to modify the img tag used by a picture tag.
+ /// This can be replaced entirely or the base method can be used as a starting point for modifications.
+ ///
+ protected virtual TagBuilder CreateImgTagBuilder(IImage image, LoadingMode renderMode, TagHelperContext context, TagHelperOutput output)
+ {
+ var tagBuilder = new TagBuilder("img");
+ tagBuilder.Attributes.Add("src", image.Url);
+ tagBuilder.Attributes.Add("alt", image.AltText);
+
+ if (renderMode is LoadingMode.Lazy)
+ {
+ tagBuilder.Attributes.Add("loading", "lazy");
+ }
+
+ if (image.Width > 0)
+ {
+ tagBuilder.Attributes.Add("width", image.Width.ToString());
+ }
+
+ if (image.Height > 0)
+ {
+ tagBuilder.Attributes.Add("height", image.Height.ToString());
+ }
+
+ return tagBuilder;
+ }
+
+ ///
+ /// Creates a used by .
+ ///
+ /// The image source.
+ /// The loading mode.
+ /// The context.
+ /// The output.
+ /// A .
+ ///
+ /// This is intended to be a developer friendly extension point to modify the source tag used by a picture tag.
+ /// This can be replaced entirely or the base method can be used as a starting point for modifications.
+ ///
+ protected virtual TagBuilder CreateImageSourceTagBuilder(IImageSource source, LoadingMode loadingMode, TagHelperContext context, TagHelperOutput output)
+ {
+ var tagBuilder = new TagBuilder("source");
+
+ tagBuilder.Attributes.Add("srcset", source.SourceSet.ToMarkupString());
+
+ if (source.MediaQuery is not null)
+ {
+ tagBuilder.Attributes.Add("media", source.MediaQuery.ToMarkupString());
+ }
+
+ if (string.IsNullOrEmpty(source.MimeType) is false)
+ {
+ tagBuilder.Attributes.Add("type", source.MimeType);
+ }
+
+ if (source.Width > 0)
+ {
+ tagBuilder.Attributes.Add("width", source.Width.ToString());
+ }
+
+ if (source.Height > 0)
+ {
+ tagBuilder.Attributes.Add("height", source.Height.ToString());
+ }
+
+ return tagBuilder;
+ }
+
+ ///
+ /// Builds the required by a img HTML tag when rendered within an picture HTML tag.
+ ///
+ /// The image.
+ /// The loading mode.
+ /// The context.
+ /// The output.
+ /// A .
+ ///
+ /// This is intended to be a developer friendly extension point to modify the source tag used by a picture tag.
+ /// This should only bn replaced entirely if you do not intend to use the output from .
+ ///
+ protected IHtmlContent BuildImgHtmlContent(IImage image, LoadingMode renderMode, TagHelperContext context, TagHelperOutput output)
+ {
+ var tagBuilder = CreateImgTagBuilder(image, renderMode, context, output);
+
+ return tagBuilder.RenderSelfClosingTag();
+ }
+
+ ///
+ /// Builds the required by a source HTML tag when rendered within an picture HTML tag.
+ ///
+ /// The image source.
+ /// The loading mode.
+ /// The context.
+ /// The output.
+ /// A .
+ ///
+ /// This is intended to be a developer friendly extension point to modify the source tag used by a picture tag.
+ /// This should only bn replaced entirely if you do not intend to use the output from .
+ ///
+ protected IHtmlContent BuildImageSourceHtmlContent(IImageSource source, LoadingMode loadingMode, TagHelperContext context, TagHelperOutput output)
+ {
+ var tagBuilder = CreateImageSourceTagBuilder(source, loadingMode, context, output);
+
+ return tagBuilder.RenderSelfClosingTag();
+ }
+}
\ No newline at end of file
diff --git a/src/Rhythm.Drop.Web.Infrastructure/TagHelperRenderers/Images/IDropImageTagHelperRenderer.cs b/src/Rhythm.Drop.Web.Infrastructure/TagHelperRenderers/Images/IDropImageTagHelperRenderer.cs
index 5349e4d..f245195 100644
--- a/src/Rhythm.Drop.Web.Infrastructure/TagHelperRenderers/Images/IDropImageTagHelperRenderer.cs
+++ b/src/Rhythm.Drop.Web.Infrastructure/TagHelperRenderers/Images/IDropImageTagHelperRenderer.cs
@@ -5,7 +5,7 @@
using Rhythm.Drop.Web.Infrastructure.TagHelperRenderers;
///
-/// A contract for rendering when used in a .
+/// A contract for rendering a when used in a as an img HTML tag (without a picture HTML tag).
///
/// This contract exists for dependency injection purposes. Check out the abstract implementations for a more guided implementation.
public interface IDropImageTagHelperRenderer : ITagHelperRenderer
diff --git a/src/Rhythm.Drop.Web.Infrastructure/TagHelperRenderers/Images/IDropPictureImageTagHelperRenderer.cs b/src/Rhythm.Drop.Web.Infrastructure/TagHelperRenderers/Images/IDropPictureImageTagHelperRenderer.cs
new file mode 100644
index 0000000..3ebd39f
--- /dev/null
+++ b/src/Rhythm.Drop.Web.Infrastructure/TagHelperRenderers/Images/IDropPictureImageTagHelperRenderer.cs
@@ -0,0 +1,12 @@
+namespace Rhythm.Drop.Web.Infrastructure.TagHelperRenderers.Images;
+
+using Microsoft.AspNetCore.Razor.TagHelpers;
+using Rhythm.Drop.Models.Images;
+
+///
+/// A contract for rendering a when used in a as an img HTML tag within a picture HTML tag.
+///
+/// This contract exists for dependency injection purposes. Check out the abstract implementations for a more guided implementation.
+public interface IDropPictureImageTagHelperRenderer : ITagHelperRenderer
+{
+}
\ No newline at end of file
diff --git a/src/Rhythm.Drop.Web.Infrastructure/TagHelperRenderers/Images/IDropPictureTagHelperRenderer.cs b/src/Rhythm.Drop.Web.Infrastructure/TagHelperRenderers/Images/IDropPictureTagHelperRenderer.cs
new file mode 100644
index 0000000..2878f3e
--- /dev/null
+++ b/src/Rhythm.Drop.Web.Infrastructure/TagHelperRenderers/Images/IDropPictureTagHelperRenderer.cs
@@ -0,0 +1,12 @@
+namespace Rhythm.Drop.Web.Infrastructure.TagHelperRenderers.Images;
+
+using Microsoft.AspNetCore.Razor.TagHelpers;
+using Rhythm.Drop.Models.Images;
+
+///
+/// A contract for rendering a when used in a as a picture HTML tag.
+///
+/// This contract exists for dependency injection purposes. Check out the abstract implementations for a more guided implementation.
+public interface IDropPictureTagHelperRenderer : ITagHelperRenderer
+{
+}
\ No newline at end of file
diff --git a/src/Rhythm.Drop.Web.Infrastructure/TagHelperRenderers/RhythmDropBuilderExtensions.cs b/src/Rhythm.Drop.Web.Infrastructure/TagHelperRenderers/RhythmDropBuilderExtensions.cs
index 5426518..ee245cd 100644
--- a/src/Rhythm.Drop.Web.Infrastructure/TagHelperRenderers/RhythmDropBuilderExtensions.cs
+++ b/src/Rhythm.Drop.Web.Infrastructure/TagHelperRenderers/RhythmDropBuilderExtensions.cs
@@ -62,4 +62,30 @@ public static IRhythmDropBuilder SetDropImageTagHelperRenderer
+ /// Sets the drop picture tag helper renderer.
+ ///
+ /// The current builder.
+ /// The type of the new drop picture tag helper renderer.
+ /// Returns the current .
+ public static IRhythmDropBuilder SetDropPictureTagHelperRenderer(this IRhythmDropBuilder builder) where TDropPictureTagHelperRenderer : class, IDropPictureTagHelperRenderer
+ {
+ builder.Services.Replace(ServiceLifetime.Scoped);
+
+ return builder;
+ }
+
+ ///
+ /// Sets the drop picture image tag helper renderer.
+ ///
+ /// The current builder.
+ /// The type of the new drop picture image tag helper renderer.
+ /// Returns the current .
+ public static IRhythmDropBuilder SetDropPictureImageTagHelperRenderer(this IRhythmDropBuilder builder) where TDropPictureImageTagHelperRenderer : class, IDropPictureImageTagHelperRenderer
+ {
+ builder.Services.Replace(ServiceLifetime.Scoped);
+
+ return builder;
+ }
}
\ No newline at end of file
diff --git a/src/Rhythm.Drop.Web/TagHelperRenderers/Images/DefaultDropPictureImageTagHelperRenderer.cs b/src/Rhythm.Drop.Web/TagHelperRenderers/Images/DefaultDropPictureImageTagHelperRenderer.cs
new file mode 100644
index 0000000..576f547
--- /dev/null
+++ b/src/Rhythm.Drop.Web/TagHelperRenderers/Images/DefaultDropPictureImageTagHelperRenderer.cs
@@ -0,0 +1,11 @@
+namespace Rhythm.Drop.Web.TagHelperRenderers.Images;
+
+using Rhythm.Drop.Web.Infrastructure.TagHelperRenderers.Images;
+
+///
+/// The default implementation of .
+///
+/// This implementation should cover most scenarios but can be replaced if needed on a project-by-project basis.
+internal sealed class DefaultDropPictureImageTagHelperRenderer : DropPictureImageTagHelperRendererBase
+{
+}
diff --git a/src/Rhythm.Drop.Web/TagHelperRenderers/Images/DefaultDropPictureTagHelperRenderer.cs b/src/Rhythm.Drop.Web/TagHelperRenderers/Images/DefaultDropPictureTagHelperRenderer.cs
new file mode 100644
index 0000000..d3775ea
--- /dev/null
+++ b/src/Rhythm.Drop.Web/TagHelperRenderers/Images/DefaultDropPictureTagHelperRenderer.cs
@@ -0,0 +1,11 @@
+namespace Rhythm.Drop.Web.TagHelperRenderers.Images;
+
+using Rhythm.Drop.Web.Infrastructure.TagHelperRenderers.Images;
+
+///
+/// The default implementation of .
+///
+/// This implementation should cover most scenarios but can be replaced if needed on a project-by-project basis.
+internal sealed class DefaultDropPictureTagHelperRenderer : DropPictureTagHelperRendererBase
+{
+}
\ No newline at end of file
diff --git a/src/Rhythm.Drop.Web/TagHelperRenderers/RhythmDropBuilderExtensions.cs b/src/Rhythm.Drop.Web/TagHelperRenderers/RhythmDropBuilderExtensions.cs
index 46d8d35..e485d92 100644
--- a/src/Rhythm.Drop.Web/TagHelperRenderers/RhythmDropBuilderExtensions.cs
+++ b/src/Rhythm.Drop.Web/TagHelperRenderers/RhythmDropBuilderExtensions.cs
@@ -23,6 +23,8 @@ public static IRhythmDropBuilder AddTagHelperRenderers(this IRhythmDropBuilder b
.SetDefaultDropAttributesTagHelperRenderer()
.SetDefaultDropComponentsTagHelperRenderer()
.SetDefaultDropImageTagHelperRenderer()
+ .SetDefaultDropPictureTagHelperRenderer()
+ .SetDefaultDropPictureImageTagHelperRenderer()
.SetDefaultDropLinkTagHelperRenderer();
}
@@ -65,4 +67,24 @@ public static IRhythmDropBuilder SetDefaultDropImageTagHelperRenderer(this IRhyt
{
return builder.SetDropImageTagHelperRenderer();
}
+
+ ///
+ /// Sets the default drop picture tag helper renderer.
+ ///
+ /// The current builder.
+ /// Returns the current .
+ public static IRhythmDropBuilder SetDefaultDropPictureTagHelperRenderer(this IRhythmDropBuilder builder)
+ {
+ return builder.SetDropPictureTagHelperRenderer();
+ }
+
+ ///
+ /// Sets the default drop picture image tag helper renderer.
+ ///
+ /// The current builder.
+ /// Returns the current .
+ public static IRhythmDropBuilder SetDefaultDropPictureImageTagHelperRenderer(this IRhythmDropBuilder builder)
+ {
+ return builder.SetDropPictureImageTagHelperRenderer();
+ }
}
\ No newline at end of file
diff --git a/src/Rhythm.Drop.Web/TagHelpers/DropImageTagHelper.cs b/src/Rhythm.Drop.Web/TagHelpers/DropImageTagHelper.cs
index 407fb59..acaa705 100644
--- a/src/Rhythm.Drop.Web/TagHelpers/DropImageTagHelper.cs
+++ b/src/Rhythm.Drop.Web/TagHelpers/DropImageTagHelper.cs
@@ -10,8 +10,8 @@
/// A tag helper that renders a .
///
/// The tag helper renderer.
-[HtmlTargetElement("drop-image", TagStructure = TagStructure.WithoutEndTag)]
-public sealed class DropImageTagHelper(IDropImageTagHelperRenderer tagHelperRenderer) : TagHelper
+[HtmlTargetElement(ImgTagName, Attributes = DropModelAttributeName, TagStructure = TagStructure.WithoutEndTag)]
+public sealed class DropImageTagHelper(IDropImageTagHelperRenderer tagHelperRenderer) : DropImageTagHelperBase
{
///
/// The tag helper renderer.
@@ -21,13 +21,13 @@ public sealed class DropImageTagHelper(IDropImageTagHelperRenderer tagHelperRend
///
/// Gets or sets the model.
///
- [HtmlAttributeName("model")]
+ [HtmlAttributeName(DropModelAttributeName)]
public IImage? Model { get; set; }
///
/// Gets or sets the loading mode for this tag helper.
///
- [HtmlAttributeName("loading-mode")]
+ [HtmlAttributeName(LoadingModeAttributeName)]
public LoadingMode LoadingMode { get; set; } = LoadingMode.Default;
///
diff --git a/src/Rhythm.Drop.Web/TagHelpers/DropImageTagHelperBase.cs b/src/Rhythm.Drop.Web/TagHelpers/DropImageTagHelperBase.cs
new file mode 100644
index 0000000..6d10019
--- /dev/null
+++ b/src/Rhythm.Drop.Web/TagHelpers/DropImageTagHelperBase.cs
@@ -0,0 +1,41 @@
+namespace Rhythm.Drop.Web.TagHelpers;
+
+using Rhythm.Drop.Models.Images;
+using Microsoft.AspNetCore.Razor.TagHelpers;
+using Rhythm.Drop.Web.Infrastructure;
+
+///
+/// A base tag helper used to render a a picture HTML tag.
+///
+public abstract class DropImageTagHelperBase : TagHelper
+{
+ ///
+ /// The tag name of a picture HTML tag.
+ ///
+ protected const string PictureTagName = "picture";
+
+ ///
+ /// The tag name of an img HTML tag.
+ ///
+ protected const string ImgTagName = "img";
+
+ ///
+ /// The attribute name used to get the model.
+ ///
+ protected const string DropModelAttributeName = "drop-model";
+
+ ///
+ /// The attribute name used to get the .
+ ///
+ protected const string LoadingModeAttributeName = "loading-mode";
+
+ ///
+ /// The name of the context item used to get and set the .
+ ///
+ protected const string DropModelContextItemName = "Drop-Model";
+
+ ///
+ /// The name of the context item used to get and set the .
+ ///
+ protected const string DropLoadingModeContextItemName = "Drop-LoadingMode";
+}
\ No newline at end of file
diff --git a/src/Rhythm.Drop.Web/TagHelpers/DropPictureImageTagHelper.cs b/src/Rhythm.Drop.Web/TagHelpers/DropPictureImageTagHelper.cs
new file mode 100644
index 0000000..fd8b5a2
--- /dev/null
+++ b/src/Rhythm.Drop.Web/TagHelpers/DropPictureImageTagHelper.cs
@@ -0,0 +1,59 @@
+namespace Rhythm.Drop.Web.TagHelpers;
+
+using Microsoft.AspNetCore.Razor.TagHelpers;
+using Rhythm.Drop.Models.Images;
+using Rhythm.Drop.Web.Infrastructure;
+using Rhythm.Drop.Web.Infrastructure.TagHelperRenderers.Images;
+using System.Diagnostics.CodeAnalysis;
+using System.Threading.Tasks;
+
+///
+/// A tag helper used within a .
+/// This tag helper is ignored if not used within a and not rendered if the passed down to this tag helper is .
+///
+/// The tag helper renderer.
+[HtmlTargetElement(ImgTagName, ParentTag = PictureTagName, TagStructure = TagStructure.NormalOrSelfClosing)]
+public sealed class DropPictureImageTagHelper(IDropPictureImageTagHelperRenderer tagHelperRenderer) : DropImageTagHelperBase
+{
+ ///
+ /// The tag helper renderer.
+ ///
+ private readonly IDropPictureImageTagHelperRenderer _tagHelperRenderer = tagHelperRenderer;
+
+ ///
+ public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
+ {
+ if (TryGetModelFromContext(context, out var model) is false)
+ {
+ await base.ProcessAsync(context, output);
+ return;
+ }
+
+ var loadingMode = GetLoadingModeOrDefaultFromContext(context);
+ var rendererContext = new DropImageTagHelperRendererContext(model, loadingMode);
+
+ await _tagHelperRenderer.RenderAsync(rendererContext, context, output);
+ }
+
+ private static bool TryGetModelFromContext(TagHelperContext context, [NotNullWhen(true)] out IImage? model)
+ {
+ if (context.Items.ContainsKey(DropLoadingModeContextItemName) is false)
+ {
+ model = default;
+ return false;
+ }
+
+ model = context.Items[DropModelContextItemName] as IImage;
+ return model is not null;
+ }
+
+ private static LoadingMode GetLoadingModeOrDefaultFromContext(TagHelperContext context)
+ {
+ if (context.Items.ContainsKey(DropLoadingModeContextItemName) is false)
+ {
+ return LoadingMode.Default;
+ }
+
+ return context.Items[DropLoadingModeContextItemName] as LoadingMode? ?? LoadingMode.Default;
+ }
+}
\ No newline at end of file
diff --git a/src/Rhythm.Drop.Web/TagHelpers/DropPictureTagHelper.cs b/src/Rhythm.Drop.Web/TagHelpers/DropPictureTagHelper.cs
new file mode 100644
index 0000000..78dc6b8
--- /dev/null
+++ b/src/Rhythm.Drop.Web/TagHelpers/DropPictureTagHelper.cs
@@ -0,0 +1,52 @@
+namespace Rhythm.Drop.Web.TagHelpers;
+
+using Microsoft.AspNetCore.Razor.TagHelpers;
+using Rhythm.Drop.Models.Images;
+using Rhythm.Drop.Web.Infrastructure;
+using Rhythm.Drop.Web.Infrastructure.TagHelperRenderers.Images;
+using System.Threading.Tasks;
+
+///
+/// A picture tag that renders a .
+///
+/// The tag helper renderer.
+[HtmlTargetElement(PictureTagName, Attributes = DropModelAttributeName, TagStructure = TagStructure.NormalOrSelfClosing)]
+[RestrictChildren(ImgTagName)]
+public sealed class DropPictureTagHelper(IDropPictureTagHelperRenderer tagHelperRenderer) : DropImageTagHelperBase
+{
+ ///
+ /// The tag helper renderer.
+ ///
+ private readonly IDropPictureTagHelperRenderer _tagHelperRenderer = tagHelperRenderer;
+
+ ///
+ /// Gets or sets the image.
+ ///
+ [HtmlAttributeName(DropModelAttributeName)]
+ public IImage? Model { get; set; }
+
+ ///
+ /// Gets or sets the render mode.
+ ///
+ [HtmlAttributeName(LoadingModeAttributeName)]
+ public LoadingMode RenderMode { get; set; } = LoadingMode.Default;
+
+ ///
+ public override void Init(TagHelperContext context)
+ {
+ if (Model is not null)
+ {
+ // set the context items to be used by any child tags.
+ context.Items[DropModelContextItemName] = Model;
+ context.Items[DropLoadingModeContextItemName] = RenderMode;
+ }
+ }
+
+ ///
+ public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
+ {
+ var renderContext = new DropImageTagHelperRendererContext(Model, RenderMode);
+
+ await _tagHelperRenderer.RenderAsync(renderContext, context, output);
+ }
+}
\ No newline at end of file
diff --git a/tests/Rhythm.Drop.Web.Tests/TagHelperRenderers/Images/DefaultImageTagHelperRendererTests.cs b/tests/Rhythm.Drop.Web.Tests/TagHelperRenderers/Images/DefaultImageTagHelperRendererTests.cs
index fd4d518..c3b2fcc 100644
--- a/tests/Rhythm.Drop.Web.Tests/TagHelperRenderers/Images/DefaultImageTagHelperRendererTests.cs
+++ b/tests/Rhythm.Drop.Web.Tests/TagHelperRenderers/Images/DefaultImageTagHelperRendererTests.cs
@@ -79,26 +79,4 @@ public async Task RenderAsync_With_Simple_Image_And_Dimensions_Returns_Output_Wi
Assert.That(output.Attributes, Has.One.Matches(x => x.Name == "height" && x.Value.ToString() == image.Height.ToString()));
});
}
-
-
- [Test]
- public async Task RenderAsync_With_Image_That_Has_Sources_Returns_Output_With_Picture_TagName()
- {
- // arrange
- var tagHelperRenderer = new DefaultDropImageTagHelperRenderer();
- var image = new Image("/image.gif", "Test", default, default, [new ImageSource("/image2.gif")]);
- var rendererContext = new DropImageTagHelperRendererContext(image, LoadingMode.Default);
- var context = CreateTagHelperContext(DefaultTagName);
- var output = CreateTagHelperOutput(DefaultTagName);
-
- // act
- await tagHelperRenderer.RenderAsync(rendererContext, context, output);
-
- // assert
- Assert.Multiple(() =>
- {
- Assert.That(output.TagName, Is.EqualTo("picture"));
- Assert.That(output.Content.IsModified, Is.True);
- });
- }
}