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,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Razor">

<PropertyGroup>
<Version>10.0.1-beta01</Version>
<Version>10.0.1-beta04</Version>
</PropertyGroup>

<PropertyGroup>
Expand All @@ -17,10 +17,13 @@
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\..\..\BootstrapBlazor\src\BootstrapBlazor\BootstrapBlazor.csproj" />
<!--<PackageReference Include="BootstrapBlazor" Version="$(BBVersion)" />-->
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\..\..\BootstrapBlazor\src\BootstrapBlazor\BootstrapBlazor.csproj" />
</ItemGroup>

<ItemGroup>
<Using Include="Microsoft.JSInterop" />
</ItemGroup>
Expand Down
14 changes: 11 additions & 3 deletions src/components/BootstrapBlazor.PdfReader/PdfReader.razor
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,21 @@
<div class="bb-view-icon bb-view-fit-width" @onclick="FitToWidth"><i class="fa-solid fa-arrows-left-right-to-line"></i></div>
<div class="bb-view-icon bb-view-fit-rotate" @onclick="RotateLeft"><i class="fa-solid fa-rotate-left"></i></div>
<div class="bb-view-icon bb-view-fit-rotate" @onclick="RotateRight"><i class="fa-solid fa-rotate-right"></i></div>
<div class="bb-view-divider"></div>
<div class="bb-view-icon bb-view-draw"><i class="fa-solid fa-pen-to-square"></i></div>
</div>
<div class="bb-view-controls">
<div class="bb-view-icon bb-view-download"><i class="fa-solid fa-arrow-right-to-bracket fa-rotate-90"></i></div>
<div class="bb-view-icon bb-view-print"><i class="fa-solid fa-print"></i></div>
<div class="bb-view-icon bb-view-home"><i class="fa-solid fa-flag"></i></div>
<Dropdown TValue="string" Color="Color.None" SkipValidate="true" ShowLabel="false"
IsPopover="false" MenuAlignment="Alignment.Right" Icon="@MoreButtonIcon">
<ItemsTemplate>
@if (Options.ShowTwoPagesOnViewButton)
{
<div class="dropdown-item dropdown-item-pages" @onclick="OnToggleTwoPagesOneView"><i class="@_twoPagesOneViewIcon"></i><span>Two pages on view</span></div>
Copy link

Copilot AI Nov 26, 2025

Choose a reason for hiding this comment

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

[nitpick] The text 'Two pages on view' is hardcoded in English while other component strings appear to support Chinese (based on C# comments). Consider localizing this string for consistency with the rest of the component, especially since the codebase uses Chinese documentation.

Copilot uses AI. Check for mistakes.
<Divider></Divider>
}
<div class="dropdown-item"><i class="fa-solid fa-fw"></i><span>Document properties</span></div>
</ItemsTemplate>
</Dropdown>
</div>
</div>
}
Expand Down
28 changes: 27 additions & 1 deletion src/components/BootstrapBlazor.PdfReader/PdfReader.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@ public partial class PdfReader
[NotNull]
public PdfReaderOptions? Options { get; set; }

/// <summary>
/// 获得/设置 更多按钮图标 默认为 null 使用内置图标
/// </summary>
[Parameter]
public string? MoreButtonIcon { get; set; }

private string? ClassString => CssBuilder.Default("bb-pdf-reader")
.AddClassFromAttributes(AdditionalAttributes)
.Build();
Expand All @@ -38,6 +44,8 @@ public partial class PdfReader
private uint _currentPage;
private string? _url;
private string? _currentScale;
private bool _enableTwoPagesOneView;
private string? _twoPagesOneViewIcon;

private readonly HashSet<string> AllowedScaleValues = ["page-actual", "page-width", "page-height", "page-fit", "auto"];

Expand Down Expand Up @@ -82,6 +90,14 @@ private void SetCurrentScale(string value)
}
}

private void OnToggleTwoPagesOneView()
{
_enableTwoPagesOneView = !_enableTwoPagesOneView;
Options.EnableTwoPagesOnView = _enableTwoPagesOneView;

_twoPagesOneViewIcon = _enableTwoPagesOneView ? "fa-solid fa-fw fa-check" : "fa-solid fa-fw";
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

suggestion (bug_risk): The icon state for two-page view is only updated via the local toggle method, not when Options is changed externally.

Because _twoPagesOneViewIcon is only set in OnToggleTwoPagesOneView, but _enableTwoPagesOneView is also updated from Options.EnableTwoPagesOnView in OnAfterRenderAsync, a parent updating Options.EnableTwoPagesOnView directly can leave the icon out of sync with the actual state.

To avoid this, either recompute _twoPagesOneViewIcon whenever _enableTwoPagesOneView is updated from Options, or derive the icon directly from _enableTwoPagesOneView instead of keeping a separate field.

Suggested implementation:

    private void OnToggleTwoPagesOneView()
    {
        _enableTwoPagesOneView = !_enableTwoPagesOneView;
        Options.EnableTwoPagesOnView = _enableTwoPagesOneView;
    }
    private uint _currentPage;

    private string TwoPagesOneViewIcon => _enableTwoPagesOneView ? "fa-solid fa-fw fa-check" : "fa-solid fa-fw";
  1. Remove the _twoPagesOneViewIcon field declaration from this file, e.g.:
    • private string _twoPagesOneViewIcon = "fa-solid fa-fw";
  2. In PdfReader.razor (the markup file), replace usages of _twoPagesOneViewIcon with TwoPagesOneViewIcon, for example:
    • class="@_twoPagesOneViewIcon"class="@TwoPagesOneViewIcon".
  3. Ensure any other references to _twoPagesOneViewIcon (if present elsewhere in the code-behind) are updated or removed in favor of the TwoPagesOneViewIcon property.

}

/// <summary>
/// <inheritdoc/>
/// </summary>
Expand All @@ -96,6 +112,9 @@ protected override void OnParametersSet()
Options.CurrentPage = 1;
}
_docTitle = Path.GetFileName(Options.Url);

MoreButtonIcon ??= "fa-solid fa-ellipsis-vertical";
_twoPagesOneViewIcon ??= "fa-solid fa-fw";
}

/// <summary>
Expand All @@ -113,6 +132,7 @@ protected override async Task OnAfterRenderAsync(bool firstRender)
_currentPage = Options.CurrentPage;
_url = Options.Url;
_currentScale = Options.CurrentScale;
_enableTwoPagesOneView = Options.EnableTwoPagesOnView;
}

if (_url != Options.Url)
Expand All @@ -136,6 +156,11 @@ protected override async Task OnAfterRenderAsync(bool firstRender)
_currentScale = Options.CurrentScale;
await InvokeVoidAsync("scale", Id, _currentScale);
}
if (_enableTwoPagesOneView != Options.EnableTwoPagesOnView)
{
_currentScale = Options.CurrentScale;
Copy link

Copilot AI Nov 26, 2025

Choose a reason for hiding this comment

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

The assignment to '_currentScale' is incorrect. This should assign '_enableTwoPagesOneView' to track the state change, not '_currentScale'. The subsequent 'setPages' call uses '_enableTwoPagesOneView' as the parameter.

Suggested change
_currentScale = Options.CurrentScale;
_enableTwoPagesOneView = Options.EnableTwoPagesOnView;

Copilot uses AI. Check for mistakes.
Copy link

Copilot AI Nov 26, 2025

Choose a reason for hiding this comment

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

The JavaScript function is called with the old value '_enableTwoPagesOneView' before it's updated. The assignment should be '_enableTwoPagesOneView = Options.EnableTwoPagesOnView;' and then pass the updated value to 'setPages'.

Suggested change
_currentScale = Options.CurrentScale;
_enableTwoPagesOneView = Options.EnableTwoPagesOnView;

Copilot uses AI. Check for mistakes.
await InvokeVoidAsync("setPages", Id, _enableTwoPagesOneView);
Comment on lines +159 to +162
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

issue (bug_risk): The two-page view sync block likely uses the wrong value and never updates local state, causing external changes to be reverted.

Here you compare _enableTwoPagesOneView with Options.EnableTwoPagesOnView, but then call setPages with the stale _enableTwoPagesOneView and never update it.

If a parent changes Options.EnableTwoPagesOnView from false to true without calling OnToggleTwoPagesOneView, this block will fire but still pass false to setPages, undoing the parent’s change on the JS side.

Consider instead:

if (_enableTwoPagesOneView != Options.EnableTwoPagesOnView)
{
    _enableTwoPagesOneView = Options.EnableTwoPagesOnView;
    await InvokeVoidAsync("setPages", Id, _enableTwoPagesOneView);
}

(or pass Options.EnableTwoPagesOnView directly and then sync _enableTwoPagesOneView.)

}
}

/// <summary>
Expand All @@ -147,7 +172,8 @@ protected override async Task OnAfterRenderAsync(bool firstRender)
Options.Url,
Options.IsFitToPage,
TriggerPagesInit = Options.OnInitAsync != null,
TriggerPageChanged = Options.OnPageChangedAsync != null
TriggerPageChanged = Options.OnPageChangedAsync != null,
TriggerTowPagesOnViewChanged = Options.OnTwoPagesOneViewAsync != null
Copy link

Copilot AI Nov 26, 2025

Choose a reason for hiding this comment

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

Corrected spelling of 'Tow' to 'Two' in property name 'TriggerTowPagesOnViewChanged'.

Suggested change
TriggerTowPagesOnViewChanged = Options.OnTwoPagesOneViewAsync != null
TriggerTwoPagesOnViewChanged = Options.OnTwoPagesOneViewAsync != null

Copilot uses AI. Check for mistakes.
});

/// <summary>
Expand Down
8 changes: 8 additions & 0 deletions src/components/BootstrapBlazor.PdfReader/PdfReader.razor.css
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,14 @@
visibility: hidden;
}

.bb-view-toolbar ::deep .btn {
--bs-btn-color: #fff;
}

.bb-view-toolbar ::deep .dropdown-toggle::after {
content: none;
}

.bb-view-title {
display: flex;
align-items: center;
Expand Down
41 changes: 37 additions & 4 deletions src/components/BootstrapBlazor.PdfReader/PdfReader.razor.js
Original file line number Diff line number Diff line change
Expand Up @@ -102,13 +102,25 @@ export function scale(id, scale) {
}
}

export function setPages(id, enableTowPagesOnView) {
const { el, pdfViewer } = Data.get(id);
Copy link

Copilot AI Nov 26, 2025

Choose a reason for hiding this comment

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

Unused variable el.

Suggested change
const { el, pdfViewer } = Data.get(id);
const { pdfViewer } = Data.get(id);

Copilot uses AI. Check for mistakes.
if (pdfViewer) {
if (enableTowPagesOnView) {
Comment on lines +105 to +108
Copy link

Copilot AI Nov 26, 2025

Choose a reason for hiding this comment

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

Corrected spelling of 'Tow' to 'Two' in parameter name 'enableTowPagesOnView'.

Suggested change
export function setPages(id, enableTowPagesOnView) {
const { el, pdfViewer } = Data.get(id);
if (pdfViewer) {
if (enableTowPagesOnView) {
export function setPages(id, enableTwoPagesOnView) {
const { el, pdfViewer } = Data.get(id);
if (pdfViewer) {
if (enableTwoPagesOnView) {

Copilot uses AI. Check for mistakes.
pdfViewer.spreadMode = 1;
}
else {
pdfViewer.spreadMode = 0;
}
}
}

const addEventListener = (el, pdfViewer, eventBus, invoke, options) => {
eventBus.on("pagesinit", async () => {
if (options.isFitToPage) {
pdfViewer.currentScaleValue = "page-width";
}
else {
pdfViewer.currentScaleValue = 1.0;
pdfViewer.currentScaleValue = "page-actual";
}

const numPages = pdfViewer.pagesCount;
Expand Down Expand Up @@ -149,6 +161,18 @@ const addEventListener = (el, pdfViewer, eventBus, invoke, options) => {

EventHandler.on(minus, "click", e => updateScale(pdfViewer, e.target, -1));
EventHandler.on(plus, "click", e => updateScale(pdfViewer, e.target, 1));

const towPagesOneView = el.querySelector(".dropdown-item-pages");
Copy link

Copilot AI Nov 26, 2025

Choose a reason for hiding this comment

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

Corrected spelling of 'tow' to 'two' in variable name 'towPagesOneView'.

Copilot uses AI. Check for mistakes.
if (towPagesOneView) {
EventHandler.on(towPagesOneView, "click", e => {
if (pdfViewer.spreadMode === 0) {
pdfViewer.spreadMode = 1;
}
else {
pdfViewer.spreadMode = 0;
}
Comment on lines +167 to +173
Copy link

Copilot AI Nov 26, 2025

Choose a reason for hiding this comment

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

The click handler in addEventListener toggles the spreadMode but doesn't invoke the C# callback 'OnTwoPagesOneViewAsync' even though 'TriggerTowPagesOnViewChanged' is passed in options. If the callback should be triggered, add an async invocation similar to other event handlers (e.g., pageChanged). If the callback is not needed, remove the unused 'TriggerTowPagesOnViewChanged' property from options.

Suggested change
EventHandler.on(towPagesOneView, "click", e => {
if (pdfViewer.spreadMode === 0) {
pdfViewer.spreadMode = 1;
}
else {
pdfViewer.spreadMode = 0;
}
EventHandler.on(towPagesOneView, "click", async e => {
if (pdfViewer.spreadMode === 0) {
pdfViewer.spreadMode = 1;
}
else {
pdfViewer.spreadMode = 0;
}
if (options.TriggerTowPagesOnViewChanged === true) {
await invoke.invokeMethodAsync("OnTwoPagesOneViewAsync", pdfViewer.spreadMode);
}

Copilot uses AI. Check for mistakes.
});
}
}

const updateScale = (pdfViewer, button, rate) => {
Expand All @@ -159,7 +183,7 @@ const updateScale = (pdfViewer, button, rate) => {
const scale = pdfViewer.currentScale;
const current = Math.round(parseFloat(scale * 100), 0);
const step = [25, 33, 50, 67, 75, 80, 90, 100, 110, 125, 150, 175, 200, 250, 300, 400, 500];
const findValues = step.filter(s => rate > 0 ? current < s : current > s);
const findValues = step.filter(s => rate > 0 ? current < s : current > s);
let v = 100;
Copy link

Copilot AI Nov 26, 2025

Choose a reason for hiding this comment

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

The initial value of v is unused, since it is always overwritten.

Suggested change
let v = 100;
let v;

Copilot uses AI. Check for mistakes.
if (rate > 0) {
v = findValues.shift();
Expand All @@ -177,7 +201,16 @@ export function dispose(id) {
if (el) {
const minus = el.querySelector(".bb-page-minus");
const plus = el.querySelector(".bb-page-plus");
EventHandler.off(minus, "click");
EventHandler.off(plus, "click");
if (minus) {
EventHandler.off(minus, "click");
}
if (plus) {
EventHandler.off(plus, "click");
}

const towPagesOneView = el.querySelector(".dropdown-item-pages");
Copy link

Copilot AI Nov 26, 2025

Choose a reason for hiding this comment

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

Corrected spelling of 'tow' to 'two' in variable name 'towPagesOneView'.

Copilot uses AI. Check for mistakes.
if (towPagesOneView) {
EventHandler.off(towPagesOneView, "click");
}
}
}
15 changes: 15 additions & 0 deletions src/components/BootstrapBlazor.PdfReader/PdfReaderOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,16 @@ public class PdfReaderOptions
/// </summary>
public bool IsFitToPage { get; set; }

/// <summary>
/// 获得/设置 是否显示双页单视图按钮 默认 true 显示
/// </summary>
public bool ShowTwoPagesOnViewButton { get; set; } = true;

/// <summary>
/// 获得/设置 是否启用双页单视图模式 默认 false
/// </summary>
public bool EnableTwoPagesOnView { get; set; }

/// <summary>
/// 页面初始化回调方法
/// </summary>
Expand All @@ -48,4 +58,9 @@ public class PdfReaderOptions
/// 页面初始化回调方法
/// </summary>
public Func<uint, Task>? OnPageChangedAsync { get; set; }

/// <summary>
/// 设置双页单视图模式回调方法
/// </summary>
public Func<bool, Task>? OnTwoPagesOneViewAsync { get; set; }
Comment on lines +63 to +65
Copy link

Copilot AI Nov 26, 2025

Choose a reason for hiding this comment

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

The callback property name 'OnTwoPagesOneViewAsync' is inconsistent with the feature name used elsewhere ('TwoPagesOnView'). Consider renaming to 'OnTwoPagesOnViewChangedAsync' to match the naming pattern of other callbacks like 'OnPageChangedAsync' and align with 'ShowTwoPagesOnViewButton' and 'EnableTwoPagesOnView'.

Suggested change
/// 设置双页单视图模式回调方法
/// </summary>
public Func<bool, Task>? OnTwoPagesOneViewAsync { get; set; }
/// 双页单视图模式变更回调方法
/// </summary>
public Func<bool, Task>? OnTwoPagesOnViewChangedAsync { get; set; }

Copilot uses AI. Check for mistakes.
}
Loading