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.13</Version>
<Version>10.0.14</Version>
</PropertyGroup>

<PropertyGroup>
Expand Down
3 changes: 3 additions & 0 deletions src/components/BootstrapBlazor.PdfReader/PdfReader.razor
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
@inherits BootstrapModuleComponentBase

<div @attributes="@AdditionalAttributes" id="@Id" class="@ClassString" style="@StyleString">
<div class="bb-view-progress">
<div class="bb-view-progress-bar"></div>
</div>
<div class="bb-view-toolbar">
@if (ShowToolbar)
{
Expand Down
42 changes: 35 additions & 7 deletions src/components/BootstrapBlazor.PdfReader/PdfReader.razor.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,14 +47,12 @@ export async function setData(id, data) {
return;
}

Copy link

Copilot AI Dec 13, 2025

Choose a reason for hiding this comment

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

The previous objectUrl is no longer being revoked before creating a new one in the setData function. This can lead to memory leaks if setData is called multiple times, as the old blob URLs will remain in memory. Consider revoking the old objectUrl before assigning the new one.

Suggested change
// Revoke previous object URL if it exists to prevent memory leaks
if (pdf.objectUrl) {
URL.revokeObjectURL(pdf.objectUrl);
}

Copilot uses AI. Check for mistakes.
const { options, objectUrl } = pdf;
if (objectUrl) {
URL.revokeObjectURL(objectUrl);
}
const objectUrl = createObjectURLFromByte(data);
pdf.objectUrl = objectUrl;

options.url = createObjectURLFromByte(data);
const { options } = pdf;
options.url = objectUrl;
options.data = null;
pdf.objectUrl = options.url;
await loadPdf(pdf);
}

Expand Down Expand Up @@ -125,8 +123,34 @@ export function resetThumbnails(id) {
const loadPdf = async pdf => {
const { el, invoke, options } = pdf;
const loadingTask = pdfjsLib.getDocument(options);

const progressEl = el.querySelector('.bb-view-progress');
if (progressEl) {
progressEl.classList.add('show');
}
const bar = el.querySelector('.bb-view-progress-bar');
if (bar) {
bar.style.setProperty('--bb-view-progress-val', '0');
}

let progressHandler = null;
loadingTask.onProgress = function (progressData) {
const { loaded, total } = progressData;

if (bar) {
const val = loaded / total * 100;
Comment on lines +138 to +141
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: Handle zero or missing total when computing progress percentage.

When total is 0 or missing, loaded / total becomes Infinity or NaN and ends up as an invalid CSS value. Consider guarding with if (!total) { return; } or using an indeterminate state instead of computing a percentage in that case.

Suggested implementation:

    let progressHandler = null;
    loadingTask.onProgress = function (progressData) {
        const { loaded, total } = progressData;

        if (bar) {
            // When total is zero or missing, avoid computing a percentage and
            // fall back to an indeterminate state by clearing the CSS variable.
            if (!total) {
                bar.style.removeProperty('--bb-view-progress-val');
                return;
            }

            let val = loaded / total * 100;
            if (val > 100) {
                val = 100;
            }
            bar.style.setProperty('--bb-view-progress-val', `${val}%`);

if (val > 100) {
val = 100;
Comment on lines +141 to +143
Copy link

Copilot AI Dec 13, 2025

Choose a reason for hiding this comment

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

Division by 'total' can result in division by zero or infinity if total is 0 or undefined. Add a check to ensure total is a positive number before performing the division.

Suggested change
const val = loaded / total * 100;
if (val > 100) {
val = 100;
let val = 0;
if (typeof total === 'number' && total > 0) {
val = loaded / total * 100;
if (val > 100) {
val = 100;
}

Copilot uses AI. Check for mistakes.
}
bar.style.setProperty('--bb-view-progress-val', `${val}%`);
Comment on lines +141 to +145
Copy link

Copilot AI Dec 13, 2025

Choose a reason for hiding this comment

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

The variable 'val' is declared as const on line 141 but is being reassigned on line 143. This will cause a runtime error. Change the declaration from 'const' to 'let' to allow reassignment.

Copilot uses AI. Check for mistakes.

if (progressHandler === null) {
progressHandler = setTimeout(() => {
clearTimeout(progressHandler);
Copy link

Copilot AI Dec 13, 2025

Choose a reason for hiding this comment

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

Calling clearTimeout inside the timeout callback is unnecessary since the timeout has already fired. This line has no effect and should be removed.

Suggested change
clearTimeout(progressHandler);

Copilot uses AI. Check for mistakes.
progressEl.classList.remove('show');
Copy link

Copilot AI Dec 13, 2025

Choose a reason for hiding this comment

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

The progressEl variable is accessed without a null check, but it was checked for null on line 128. If progressEl is null, this will cause a runtime error. Add a null check before accessing progressEl.

Suggested change
progressEl.classList.remove('show');
if (progressEl) {
progressEl.classList.remove('show');
}

Copilot uses AI. Check for mistakes.
}, 300);
}
Comment on lines +141 to +152
Copy link

Copilot AI Dec 13, 2025

Choose a reason for hiding this comment

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

The condition 'progressHandler === null' will only be true once, meaning the timeout to hide the progress bar is set only on the first progress update. Subsequent progress updates won't reset or update this timer. This could cause the progress bar to disappear prematurely while loading is still in progress. Consider clearing the existing timeout before setting a new one, or move this logic to after the loading completes.

Suggested change
const val = loaded / total * 100;
if (val > 100) {
val = 100;
}
bar.style.setProperty('--bb-view-progress-val', `${val}%`);
if (progressHandler === null) {
progressHandler = setTimeout(() => {
clearTimeout(progressHandler);
progressEl.classList.remove('show');
}, 300);
}
let val = loaded / total * 100;
if (val > 100) {
val = 100;
}
bar.style.setProperty('--bb-view-progress-val', `${val}%`);
// Always clear and reset the timeout on each progress update
if (progressHandler !== null) {
clearTimeout(progressHandler);
}
progressHandler = setTimeout(() => {
progressHandler = null;
if (progressEl) {
progressEl.classList.remove('show');
}
}, 300);

Copilot uses AI. Check for mistakes.
}
};

loadingTask.onPassword = function (updatePassword, reason) {
Expand Down Expand Up @@ -161,7 +185,11 @@ const loadPdf = async pdf => {
}

const disposePdf = pdf => {
const { el, observer, loadingTask } = pdf;
const { el, observer, loadingTask, objectUrl } = pdf;
if (objectUrl) {
URL.revokeObjectURL(objectUrl);
}

if (observer) {
observer.disconnect();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,25 @@
height: calc(var(--bb-pdf-view-height) + var(--bb-pdf-toolbar-height));
}

.bb-view-progress {
position: absolute;
top: 0;
left: 0;
right: 0;
height: 0.25rem;
}

.bb-view-progress:not(.show) {
display: none;
}

.bb-view-progress-bar {
height: 100%;
background-color: var(--bs-primary);
width: var(--bb-view-progress-val, 0);
transition: width .3s linear;
Copy link

Copilot AI Dec 13, 2025

Choose a reason for hiding this comment

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

The transition property uses '.3s' which is less readable than '0.3s'. Consider using '0.3s' for consistency and clarity.

Suggested change
transition: width .3s linear;
transition: width 0.3s linear;

Copilot uses AI. Check for mistakes.
}

.bb-view-toolbar {
height: var(--bb-pdf-toolbar-height);
background-color: var(--bb-toolbar-background-color);
Expand Down