Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk.Razor">

<PropertyGroup>
<Version>10.0.1</Version>
</PropertyGroup>

<PropertyGroup>
<PackageTags>Bootstrap Blazor WebAssembly wasm UI Components Pdf Viewer</PackageTags>
<Description>Bootstrap UI components extensions of Pdf Viewer</Description>
Expand Down
52 changes: 39 additions & 13 deletions src/components/BootstrapBlazor.PdfViewer/PdfViewer.razor.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) Argo Zhang ([email protected]). All rights reserved.
// Copyright (c) Argo Zhang ([email protected]). All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
// Website: https://www.blazor.zone or https://argozhang.github.io/

Expand All @@ -7,46 +7,60 @@
namespace BootstrapBlazor.Components;

/// <summary>
/// PdfViewer component for displaying PDF files in a Blazor application.
/// <para lang="zh">PdfViewer 组件</para>
/// <para lang="en">PdfViewer component for displaying PDF files in a Blazor application</para>
/// </summary>
public partial class PdfViewer
{
/// <summary>
/// Gets or sets the url for the PDF file to be displayed.
/// <para lang="zh">获得/设置 文档 Url 属性</para>
/// <para lang="en">Gets or sets the url for the PDF file to be displayed</para>
/// </summary>
[Parameter]
public string? Url { get; set; }

/// <summary>
/// Gets or sets the page index of the PDF file.
/// <para lang="zh">获得/设置 页码索引</para>
/// <para lang="en">Gets or sets the page index of the PDF file</para>
/// </summary>
[Parameter]
public int PageIndex { get; set; }

/// <summary>
/// Gets or sets the viewer height. Default is null.
/// <para lang="zh">获得/设置 查看器高度</para>
/// <para lang="en">Gets or sets the viewer height</para>
/// </summary>
[Parameter]
public string? Height { get; set; }

/// <summary>
/// Gets or sets the document loaded event callback.
/// <para lang="zh">获得/设置 文档加载完成回调事件</para>
/// <para lang="en">Gets or sets the document loaded event callback</para>
/// </summary>
[Parameter]
public Func<Task>? OnLoaded { get; set; }

/// <summary>
/// Gets or sets the document loaded event callback.
/// <para lang="zh">获得/设置 文档不支持回调事件</para>
/// <para lang="en">Gets or sets the document not supported event callback</para>
/// </summary>
[Parameter]
public Func<Task>? NotSupportCallback { get; set; }

/// <summary>
/// Gets or sets whether to use Google Docs for PDF rendering. Default is false.
/// <para lang="zh">获得/设置 是否使用 Google Docs 渲染 PDF</para>
/// <para lang="en">Gets or sets whether to use Google Docs for PDF rendering</para>
/// </summary>
[Parameter]
public bool UseGoogleDocs { get; set; }

/// <summary>
/// <para lang="zh">获得/设置 是否显示工具栏与缩略图侧边栏</para>
/// <para lang="en">Gets or sets whether to display toolbar and thumbnail sidebar</para>
/// </summary>
[Parameter]
public bool ShowToolbar { get; set; } = true;

[Inject, NotNull]
private NavigationManager? NavigationManager { get; set; }

Expand All @@ -64,7 +78,6 @@ public partial class PdfViewer
/// <inheritdoc/>
/// </summary>
/// <param name="firstRender"></param>
/// <returns></returns>
protected override async Task OnAfterRenderAsync(bool firstRender)
{
await base.OnAfterRenderAsync(firstRender);
Expand All @@ -78,7 +91,6 @@ protected override async Task OnAfterRenderAsync(bool firstRender)
/// <summary>
/// <inheritdoc/>
/// </summary>
/// <returns></returns>
protected override Task InvokeInitAsync() => InvokeVoidAsync("init", Id, Interop, new
{
LoadedCallaback = nameof(TriggerOnLoaded),
Expand All @@ -94,13 +106,28 @@ private string GetAbsoluteUri(string? url)
}

var uri = NavigationManager.ToAbsoluteUri(url);
return $"{uri.AbsoluteUri}#page={PageIndex}";
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (complexity): Consider simplifying the new URI construction logic in GetAbsoluteUri to avoid the extra UriBuilder and BuildFragment indirection while still supporting ShowToolbar and page index behavior.

The new GetAbsoluteUri / BuildFragment flow adds indirection without clear benefit. You can keep the new ShowToolbar behavior while simplifying the URI construction and removing UriBuilder and the extra method.

A more direct implementation that preserves current behavior (including overwriting any existing fragment and using "toolbar=0&navpanes=0" as a single unit) could be:

private string GetAbsoluteUri(string? url)
{
    if (string.IsNullOrEmpty(url))
    {
        return string.Empty;
    }

    var baseUri = NavigationManager.ToAbsoluteUri(url).AbsoluteUri;

    string? fragment = null;

    if (PageIndex > 0)
    {
        fragment = $"page={PageIndex}";
    }

    if (!ShowToolbar)
    {
        var toolbarFragment = "toolbar=0&navpanes=0";
        fragment = string.IsNullOrEmpty(fragment)
            ? toolbarFragment
            : $"{fragment}&{toolbarFragment}";
    }

    return string.IsNullOrEmpty(fragment)
        ? baseUri
        : $"{baseUri}#{fragment}";
}

This:

  • Keeps all existing functionality (page index, optional toolbar/navpanes hiding).
  • Matches the current behavior of replacing any existing fragment.
  • Removes the extra UriBuilder allocation and BuildFragment method.
  • Avoids the List<string> / string.Join overhead for at most two conditions, making the control flow easier to follow.

var builder = new UriBuilder(uri.AbsoluteUri);
builder.Fragment = BuildFragment(builder);
return builder.Uri.ToString();
}

private string BuildFragment(UriBuilder builder)
{
var fragments = new List<string>();
if (PageIndex > 0)
{
fragments.Add($"page={PageIndex}");
}
if (!ShowToolbar)
{
fragments.Add("toolbar=0&navpanes=0");
Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider splitting "toolbar=0&navpanes=0" into two separate fragment entries: fragments.Add("toolbar=0") and fragments.Add("navpanes=0"). While the current implementation works correctly, splitting them improves maintainability and makes the code more consistent - each fragment entry should represent a single parameter rather than pre-joined parameters.

Suggested change
fragments.Add("toolbar=0&navpanes=0");
fragments.Add("toolbar=0");
fragments.Add("navpanes=0");

Copilot uses AI. Check for mistakes.
}
return string.Join('&', fragments);
Comment on lines +114 to +125
Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The builder parameter is passed to BuildFragment but never used. If the input URL already contains a fragment (e.g., "file.pdf#existingfragment"), it will be silently overwritten. If this is intentional behavior, the parameter should be removed. If existing fragments should be preserved or merged, the builder.Fragment should be checked and incorporated into the result.

Copilot uses AI. Check for mistakes.
}

/// <summary>
/// Trigger OnLoaded callback when the PDF document is loaded.
/// </summary>
/// <returns></returns>
[JSInvokable]
public async Task TriggerOnLoaded()
{
Expand All @@ -113,7 +140,6 @@ public async Task TriggerOnLoaded()
/// <summary>
/// Trigger NotSupportCallback when the PDF viewer does not support the document.
/// </summary>
/// <returns></returns>
[JSInvokable]
public async Task TriggerNotSupportCallback()
{
Expand Down
Loading