Skip to content

Commit dc5cee7

Browse files
committed
Reduced publicapi, extend buildrendertree
1 parent 067d23c commit dc5cee7

File tree

6 files changed

+77
-109
lines changed

6 files changed

+77
-109
lines changed

src/Components/Web/src/Media/FileDownload.cs

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -31,27 +31,20 @@ public sealed class FileDownload : MediaComponentBase
3131
/// </summary>
3232
[Parameter] public string? Text { get; set; }
3333

34-
/// <inheritdoc />
35-
protected override string TagName => "a";
36-
37-
/// <inheritdoc />
38-
protected override string TargetAttributeName => string.Empty; // Not used – object URL not tracked for downloads.
39-
40-
/// <inheritdoc />
41-
protected override string MarkerAttributeName => "data-blazor-file-download";
34+
internal override string TargetAttributeName => string.Empty; // Not used – object URL not tracked for downloads.
4235

4336
/// <inheritdoc />
44-
protected override bool ShouldAutoLoad => false;
37+
internal override bool ShouldAutoLoad => false;
4538

4639
/// <summary>
4740
/// Builds the anchor element with click handler wiring. The anchor is given an inert href (if one is not supplied)
4841
/// and the click default action is prevented so navigation does not occur. Styling into a button shape is left to the user.
4942
/// </summary>
50-
protected override void BuildRenderTree(RenderTreeBuilder builder)
43+
private protected override void BuildRenderTree(RenderTreeBuilder builder)
5144
{
52-
builder.OpenElement(0, TagName);
45+
builder.OpenElement(0, "a");
5346

54-
builder.AddAttribute(1, MarkerAttributeName, "");
47+
builder.AddAttribute(1, "data-blazor-file-download", "");
5548

5649
if (IsLoading)
5750
{

src/Components/Web/src/Media/Image.cs

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4+
using Microsoft.AspNetCore.Components.Rendering;
5+
46
namespace Microsoft.AspNetCore.Components.Web.Media;
57

68
/* This is equivalent to a .razor file containing:
@@ -17,12 +19,31 @@ namespace Microsoft.AspNetCore.Components.Web.Media;
1719
/// </summary>
1820
public sealed class Image : MediaComponentBase
1921
{
20-
/// <inheritdoc/>
21-
protected override string TagName => "img";
22+
internal override string TargetAttributeName => "src";
23+
24+
private protected override void BuildRenderTree(RenderTreeBuilder builder)
25+
{
26+
builder.OpenElement(0, "img");
27+
28+
if (!string.IsNullOrEmpty(_currentObjectUrl))
29+
{
30+
builder.AddAttribute(1, TargetAttributeName, _currentObjectUrl);
31+
}
32+
33+
builder.AddAttribute(2, "data-blazor-image", "");
2234

23-
/// <inheritdoc/>
24-
protected override string TargetAttributeName => "src";
35+
var showInitial = Source != null && _currentSource == null && string.IsNullOrEmpty(_currentObjectUrl) && !_hasError;
36+
if (IsLoading || showInitial)
37+
{
38+
builder.AddAttribute(3, "data-state", "loading");
39+
}
40+
else if (_hasError)
41+
{
42+
builder.AddAttribute(3, "data-state", "error");
43+
}
2544

26-
/// <inheritdoc/>
27-
protected override string MarkerAttributeName => "data-blazor-image";
45+
builder.AddMultipleAttributes(4, AdditionalAttributes);
46+
builder.AddElementReferenceCapture(5, r => Element = r);
47+
builder.CloseElement();
48+
}
2849
}

src/Components/Web/src/Media/MediaComponentBase.cs

Lines changed: 18 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@
99
namespace Microsoft.AspNetCore.Components.Web.Media;
1010

1111
/// <summary>
12-
/// Base component that handles turning a media stream into an object URL, caching and lifetime management.
13-
/// Derived components provide the element tag name (e.g., img, video) and target attribute (e.g., src, href).
12+
/// Base component that handles turning a media stream into an object URL plus caching and lifetime management.
13+
/// Subclasses implement their own rendering and provide the target attribute (e.g., <c>src</c> or <c>href</c>) used
1414
/// </summary>
1515
public abstract partial class MediaComponentBase : IComponent, IHandleAfterRender, IAsyncDisposable
1616
{
@@ -20,12 +20,12 @@ public abstract partial class MediaComponentBase : IComponent, IHandleAfterRende
2020
/// The current object URL (blob URL) assigned to the underlying element, or <c>null</c> if not yet loaded
2121
/// or if a previous load failed/was cancelled.
2222
/// </summary>
23-
protected string? _currentObjectUrl;
23+
internal string? _currentObjectUrl;
2424

2525
/// <summary>
2626
/// Indicates whether the last load attempt ended in an error state for the active cache key.
2727
/// </summary>
28-
protected bool _hasError;
28+
internal bool _hasError;
2929

3030
private bool _isDisposed;
3131
private bool _initialized;
@@ -35,68 +35,54 @@ public abstract partial class MediaComponentBase : IComponent, IHandleAfterRende
3535
/// The cache key associated with the currently active/most recent load operation. Used to ignore
3636
/// out-of-order JS interop responses belonging to stale operations.
3737
/// </summary>
38-
protected string? _activeCacheKey;
38+
internal string? _activeCacheKey;
3939

4040
/// <summary>
4141
/// The <see cref="MediaSource"/> instance currently being processed (or <c>null</c> if none).
4242
/// </summary>
43-
protected MediaSource? _currentSource;
43+
internal MediaSource? _currentSource;
4444
private CancellationTokenSource? _loadCts;
4545

4646
/// <summary>
4747
/// Gets a value indicating whether the component is currently loading the media content.
4848
/// True when a source has been provided, no object URL is available yet, and there is no error.
4949
/// </summary>
50-
protected bool IsLoading => _currentSource != null && string.IsNullOrEmpty(_currentObjectUrl) && !_hasError;
50+
internal bool IsLoading => _currentSource != null && string.IsNullOrEmpty(_currentObjectUrl) && !_hasError;
5151

5252
/// <summary>
5353
/// Gets a value indicating whether the renderer is interactive so client-side JS interop can be performed.
5454
/// </summary>
55-
protected bool IsInteractive => _renderHandle.IsInitialized && _renderHandle.RendererInfo.IsInteractive;
55+
internal bool IsInteractive => _renderHandle.IsInitialized && _renderHandle.RendererInfo.IsInteractive;
5656

5757
/// <summary>
5858
/// Gets the reference to the rendered HTML element for this media component.
5959
/// </summary>
60-
protected ElementReference? Element { get; set; }
60+
internal ElementReference? Element { get; set; }
6161

6262
/// <summary>
6363
/// Gets or sets the JS runtime used for interop with the browser to materialize media object URLs.
6464
/// </summary>
65-
[Inject] protected IJSRuntime JSRuntime { get; set; } = default!;
65+
[Inject] internal IJSRuntime JSRuntime { get; set; } = default!;
6666

6767
/// <summary>
6868
/// Gets or sets the logger factory used to create the <see cref="Logger"/> instance.
6969
/// </summary>
70-
[Inject] protected ILoggerFactory LoggerFactory { get; set; } = default!;
70+
[Inject] internal ILoggerFactory LoggerFactory { get; set; } = default!;
7171

7272
/// <summary>
7373
/// Logger for media operations.
7474
/// </summary>
75-
protected ILogger Logger => _logger ??= LoggerFactory.CreateLogger(GetType());
75+
private ILogger Logger => _logger ??= LoggerFactory.CreateLogger(GetType());
7676
private ILogger? _logger;
7777

78-
/// <summary>
79-
/// Gets the element tag name (e.g., "img", "video").
80-
/// </summary>
81-
protected abstract string TagName { get; }
82-
83-
/// <summary>
84-
/// Gets the attribute name to assign the object URL to (e.g., "src" or "href").
85-
/// </summary>
86-
protected abstract string TargetAttributeName { get; }
87-
88-
/// <summary>
89-
/// Gets the custom marker data-attribute name added to the rendered element for diagnostics and tests.
90-
/// Derived components must override to provide a component-specific marker (e.g., "data-blazor-image").
91-
/// </summary>
92-
protected abstract string MarkerAttributeName { get; }
78+
internal abstract string TargetAttributeName { get; }
9379

9480
/// <summary>
9581
/// Determines whether the component should automatically invoke a media load after the first render
9682
/// and whenever the <see cref="Source"/> changes. Override and return <c>false</c> for components
9783
/// (such as download buttons) that defer loading until an explicit user action.
9884
/// </summary>
99-
protected virtual bool ShouldAutoLoad => true;
85+
internal virtual bool ShouldAutoLoad => true;
10086

10187
/// <summary>
10288
/// Gets or sets the media source.
@@ -173,7 +159,7 @@ async Task IHandleAfterRender.OnAfterRenderAsync()
173159
/// Triggers a render of the component by invoking the <see cref="BuildRenderTree"/> method.
174160
/// Ensures that only one render operation is pending at a time to prevent redundant renders.
175161
/// </summary>
176-
protected void Render()
162+
internal void Render()
177163
{
178164
Debug.Assert(_renderHandle.IsInitialized);
179165

@@ -185,38 +171,7 @@ protected void Render()
185171
}
186172
}
187173

188-
/// <summary>
189-
/// Builds the component render tree for the underlying media element and common attributes.
190-
/// Derived components can override to extend the markup.
191-
/// </summary>
192-
/// <param name="builder">The <see cref="RenderTreeBuilder"/> used to construct the render tree.</param>
193-
protected virtual void BuildRenderTree(RenderTreeBuilder builder)
194-
{
195-
builder.OpenElement(0, TagName);
196-
197-
if (!string.IsNullOrEmpty(_currentObjectUrl))
198-
{
199-
builder.AddAttribute(1, TargetAttributeName, _currentObjectUrl);
200-
}
201-
202-
builder.AddAttribute(2, MarkerAttributeName, "");
203-
204-
var showInitial = Source != null && _currentSource == null && string.IsNullOrEmpty(_currentObjectUrl) && !_hasError;
205-
206-
if (IsLoading || showInitial)
207-
{
208-
builder.AddAttribute(3, "data-state", "loading");
209-
}
210-
else if (_hasError)
211-
{
212-
builder.AddAttribute(3, "data-state", "error");
213-
}
214-
215-
builder.AddMultipleAttributes(4, AdditionalAttributes);
216-
builder.AddElementReferenceCapture(5, elementReference => Element = elementReference);
217-
218-
builder.CloseElement();
219-
}
174+
private protected virtual void BuildRenderTree(RenderTreeBuilder builder) { }
220175

221176
private sealed class MediaLoadResult
222177
{
@@ -309,7 +264,7 @@ public ValueTask DisposeAsync()
309264
/// <summary>
310265
/// Cancels any in-flight media load operation, if one is active, by signalling its <see cref="CancellationTokenSource"/>.
311266
/// </summary>
312-
protected void CancelPreviousLoad()
267+
internal void CancelPreviousLoad()
313268
{
314269
try
315270
{
@@ -325,7 +280,7 @@ protected void CancelPreviousLoad()
325280
/// <summary>
326281
/// Creates a new <see cref="CancellationTokenSource"/> for an upcoming load operation and returns its token.
327282
/// </summary>
328-
protected CancellationToken ResetCancellationToken()
283+
internal CancellationToken ResetCancellationToken()
329284
{
330285
_loadCts = new CancellationTokenSource();
331286
return _loadCts.Token;

src/Components/Web/src/Media/Video.cs

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4+
using Microsoft.AspNetCore.Components.Rendering;
5+
46
namespace Microsoft.AspNetCore.Components.Web.Media;
57

68
/* This is equivalent to a .razor file containing:
@@ -17,12 +19,31 @@ namespace Microsoft.AspNetCore.Components.Web.Media;
1719
/// </summary>
1820
public sealed class Video : MediaComponentBase
1921
{
20-
/// <inheritdoc/>
21-
protected override string TagName => "video";
22+
internal override string TargetAttributeName => "src";
23+
24+
private protected override void BuildRenderTree(RenderTreeBuilder builder)
25+
{
26+
builder.OpenElement(0, "video");
27+
28+
if (!string.IsNullOrEmpty(_currentObjectUrl))
29+
{
30+
builder.AddAttribute(1, TargetAttributeName, _currentObjectUrl);
31+
}
32+
33+
builder.AddAttribute(2, "data-blazor-video", "");
2234

23-
/// <inheritdoc/>
24-
protected override string TargetAttributeName => "src";
35+
var showInitial = Source != null && _currentSource == null && string.IsNullOrEmpty(_currentObjectUrl) && !_hasError;
36+
if (IsLoading || showInitial)
37+
{
38+
builder.AddAttribute(3, "data-state", "loading");
39+
}
40+
else if (_hasError)
41+
{
42+
builder.AddAttribute(3, "data-state", "error");
43+
}
2544

26-
/// <inheritdoc/>
27-
protected override string MarkerAttributeName => "data-blazor-video";
45+
builder.AddMultipleAttributes(4, AdditionalAttributes);
46+
builder.AddElementReferenceCapture(5, r => Element = r);
47+
builder.CloseElement();
48+
}
2849
}
Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
11
#nullable enable
2-
abstract Microsoft.AspNetCore.Components.Web.Media.MediaComponentBase.MarkerAttributeName.get -> string!
3-
abstract Microsoft.AspNetCore.Components.Web.Media.MediaComponentBase.TagName.get -> string!
4-
abstract Microsoft.AspNetCore.Components.Web.Media.MediaComponentBase.TargetAttributeName.get -> string!
52
Microsoft.AspNetCore.Components.Forms.InputHidden
63
Microsoft.AspNetCore.Components.Forms.InputHidden.Element.get -> Microsoft.AspNetCore.Components.ElementReference?
74
Microsoft.AspNetCore.Components.Forms.InputHidden.Element.set -> void
@@ -15,29 +12,13 @@ Microsoft.AspNetCore.Components.Web.Media.FileDownload.Text.get -> string?
1512
Microsoft.AspNetCore.Components.Web.Media.FileDownload.Text.set -> void
1613
Microsoft.AspNetCore.Components.Web.Media.Image
1714
Microsoft.AspNetCore.Components.Web.Media.Image.Image() -> void
18-
Microsoft.AspNetCore.Components.Web.Media.MediaComponentBase.CancelPreviousLoad() -> void
19-
Microsoft.AspNetCore.Components.Web.Media.MediaComponentBase.Render() -> void
20-
Microsoft.AspNetCore.Components.Web.Media.MediaComponentBase.ResetCancellationToken() -> System.Threading.CancellationToken
2115
Microsoft.AspNetCore.Components.Web.Media.MediaComponentBase.Source.get -> Microsoft.AspNetCore.Components.Web.Media.MediaSource!
22-
Microsoft.AspNetCore.Components.Web.Media.MediaComponentBase._activeCacheKey -> string?
23-
Microsoft.AspNetCore.Components.Web.Media.MediaComponentBase._currentObjectUrl -> string?
24-
Microsoft.AspNetCore.Components.Web.Media.MediaComponentBase._currentSource -> Microsoft.AspNetCore.Components.Web.Media.MediaSource?
25-
Microsoft.AspNetCore.Components.Web.Media.MediaComponentBase._hasError -> bool
2616
Microsoft.AspNetCore.Components.Web.Media.Video
2717
Microsoft.AspNetCore.Components.Web.Media.Video.Video() -> void
2818
Microsoft.AspNetCore.Components.Web.Media.MediaComponentBase
2919
Microsoft.AspNetCore.Components.Web.Media.MediaComponentBase.AdditionalAttributes.get -> System.Collections.Generic.Dictionary<string!, object!>?
3020
Microsoft.AspNetCore.Components.Web.Media.MediaComponentBase.AdditionalAttributes.set -> void
3121
Microsoft.AspNetCore.Components.Web.Media.MediaComponentBase.DisposeAsync() -> System.Threading.Tasks.ValueTask
32-
Microsoft.AspNetCore.Components.Web.Media.MediaComponentBase.Element.get -> Microsoft.AspNetCore.Components.ElementReference?
33-
Microsoft.AspNetCore.Components.Web.Media.MediaComponentBase.Element.set -> void
34-
Microsoft.AspNetCore.Components.Web.Media.MediaComponentBase.IsInteractive.get -> bool
35-
Microsoft.AspNetCore.Components.Web.Media.MediaComponentBase.IsLoading.get -> bool
36-
Microsoft.AspNetCore.Components.Web.Media.MediaComponentBase.JSRuntime.get -> Microsoft.JSInterop.IJSRuntime!
37-
Microsoft.AspNetCore.Components.Web.Media.MediaComponentBase.JSRuntime.set -> void
38-
Microsoft.AspNetCore.Components.Web.Media.MediaComponentBase.Logger.get -> Microsoft.Extensions.Logging.ILogger!
39-
Microsoft.AspNetCore.Components.Web.Media.MediaComponentBase.LoggerFactory.get -> Microsoft.Extensions.Logging.ILoggerFactory!
40-
Microsoft.AspNetCore.Components.Web.Media.MediaComponentBase.LoggerFactory.set -> void
4122
Microsoft.AspNetCore.Components.Web.Media.MediaComponentBase.MediaComponentBase() -> void
4223
Microsoft.AspNetCore.Components.Web.Media.MediaComponentBase.Source.set -> void
4324
Microsoft.AspNetCore.Components.Web.Media.MediaSource
@@ -50,5 +31,3 @@ Microsoft.AspNetCore.Components.Web.Media.MediaSource.Stream.get -> System.IO.St
5031
override Microsoft.AspNetCore.Components.Forms.InputHidden.BuildRenderTree(Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder! builder) -> void
5132
override Microsoft.AspNetCore.Components.Forms.InputHidden.TryParseValueFromString(string? value, out string? result, out string? validationErrorMessage) -> bool
5233
virtual Microsoft.AspNetCore.Components.Routing.NavLink.ShouldMatch(string! uriAbsolute) -> bool
53-
virtual Microsoft.AspNetCore.Components.Web.Media.MediaComponentBase.BuildRenderTree(Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder! builder) -> void
54-
virtual Microsoft.AspNetCore.Components.Web.Media.MediaComponentBase.ShouldAutoLoad.get -> bool

src/Components/test/testassets/BasicTestApp/BasicTestApp.csproj

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
<Reference Include="Microsoft.AspNetCore.Components.CustomElements" />
2727
<Reference Include="Microsoft.AspNetCore.Components.Authorization" />
2828
<Reference Include="Microsoft.AspNetCore.Components.QuickGrid" />
29-
<Reference Include="Microsoft.AspNetCore.Components.Web" />
3029
<Reference Include="Microsoft.AspNetCore.SignalR.Client" />
3130
<Reference Include="Microsoft.Extensions.Logging.Configuration" />
3231
<Reference Include="Newtonsoft.Json" />

0 commit comments

Comments
 (0)