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
Expand Up @@ -196,7 +196,7 @@ protected override async Task OnAfterRenderAsync(bool firstRender)
if (_url != Url)
{
_url = Url;
await InvokeInitAsync();
await InvokeVoidAsync("setUrl", Id, _url);
}
if (_currentPage != CurrentPage)
{
Expand Down
138 changes: 99 additions & 39 deletions src/components/BootstrapBlazor.PdfReader/PdfReader.razor.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,42 @@ export async function init(id, invoke, options) {
return;
}

if (options.url === null) {
Data.set(id, { el, invoke, options });

if (options.url) {
setUrl(id, options.url);
}
else {
setData(id, options.data);
Comment on lines +22 to +25
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 setUrl function is called without await in the init function, but setUrl is an async function that performs important operations like loadPdf. This means the init function may complete before the PDF is fully loaded, which could cause race conditions or unexpected behavior. Either await the call or ensure the function doesn't need to complete before init returns.

Suggested change
setUrl(id, options.url);
}
else {
setData(id, options.data);
await setUrl(id, options.url);
}
else {
await setData(id, options.data);

Copilot uses AI. Check for mistakes.
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 setData function is called without await in the init function. Similar to the setUrl issue, this could cause race conditions or unexpected behavior.

Suggested change
setData(id, options.data);
await setData(id, options.data);

Copilot uses AI. Check for mistakes.
}
}

export async function setUrl(id, url) {
const pdf = Data.get(id);
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 setUrl function doesn't check if the pdf object exists before calling disposePdf. If Data.get(id) returns undefined or null (e.g., if init was never called or the component was already disposed), this will cause disposePdf to receive an invalid value, potentially leading to runtime errors when trying to destructure properties.

Suggested change
const pdf = Data.get(id);
const pdf = Data.get(id);
if (!pdf) {
return;
}

Copilot uses AI. Check for mistakes.
disposePdf(pdf);

if (!url) {
return;
}

const pdfViewer = await loadPdf(el, invoke, options);
const observer = setObserver(el);
const { options } = pdf;
options.url = url;
options.data = null;
await loadPdf(pdf);
}

export async function setData(id, data) {
const pdf = Data.get(id);
disposePdf(pdf);
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 setData function doesn't check if the pdf object exists before calling disposePdf. If Data.get(id) returns undefined or null, this will cause similar issues as in setUrl.

Suggested change
disposePdf(pdf);
if (pdf) {
disposePdf(pdf);
}

Copilot uses AI. Check for mistakes.

if (!data) {
return;
}

Data.set(id, { el, pdfViewer, observer });
const { options } = pdf;
options.url = null;
options.data = data;
await loadPdf(pdf);
}

export function setScaleValue(id, value) {
Expand Down Expand Up @@ -74,7 +102,8 @@ export function resetThumbnails(id) {
}
}

const loadPdf = async (el, invoke, options) => {
const loadPdf = async pdf => {
const { el, invoke, options } = pdf;
const loadingTask = pdfjsLib.getDocument(options);
loadingTask.onProgress = function (progressData) {

Expand All @@ -96,6 +125,7 @@ const loadPdf = async (el, invoke, options) => {
eventBus
});

resetToolbarView(el, pdfViewer);
addEventBus(el, pdfViewer, eventBus, invoke, options);

const pdfDocument = await loadingTask.promise;
Expand All @@ -105,7 +135,37 @@ const loadPdf = async (el, invoke, options) => {
loadMetadata(el, pdfViewer, metadata);
});

return pdfViewer;
pdf.pdfViewer = pdfViewer;
pdf.loadingTask = loadingTask;
pdf.observer = setObserver(el);
}

const disposePdf = pdf => {
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 disposePdf function doesn't check if the pdf parameter is null or undefined before destructuring. If called with an invalid value, this will cause a runtime error.

Suggested change
const disposePdf = pdf => {
const disposePdf = pdf => {
if (!pdf) {
return;
}

Copilot uses AI. Check for mistakes.
const { el, observer, loadingTask } = pdf;
if (observer) {
observer.disconnect();
}

if (loadingTask && !loadingTask.destroyed) {
loadingTask.destroy();
}

if (el) {
removeToolbarEventHandlers(el);
const viewContainer = el.querySelector(".bb-view-container");
if (viewContainer) {
[...viewContainer.children].forEach(i => {
if (!i.classList.contains("pdfViewer")) {
i.remove();
}
})
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.

Missing semicolon at the end of the statement. While JavaScript allows this due to automatic semicolon insertion, it's a best practice to include semicolons for consistency with the rest of the codebase.

Suggested change
})
});

Copilot uses AI. Check for mistakes.
}

const thumbnailsContainer = el.querySelector(".bb-view-thumbnails");
if (thumbnailsContainer) {
thumbnailsContainer.innerHTML = "";
}
}
}

const loadMetadata = (el, pdfViewer, metadata) => {
Expand Down Expand Up @@ -474,6 +534,37 @@ const addToolbarEventHandlers = (el, pdfViewer, invoke, options) => {
});
}

const removeToolbarEventHandlers = el => {
if (el) {
const towPagesOneView = el.querySelector(".dropdown-item-pages");
if (towPagesOneView) {
EventHandler.off(towPagesOneView, "click");
}

const toolbar = el.querySelector(".bb-view-toolbar");
if (toolbar) {
EventHandler.off(toolbar, "click");
EventHandler.off(toolbar, "change");
EventHandler.off(toolbar, "focus");
}

const thumbnailsContainer = el.querySelector(".bb-view-thumbnails");
if (thumbnailsContainer) {
EventHandler.off(thumbnailsContainer, "click");
}

const iframe = document.querySelector('.bb-view-print-iframe');
if (iframe) {
iframe.remove();
}

const closeButton = el.querySelector(".btn-close-doc");
if (closeButton) {
EventHandler.off(closeButton, "click");
}
}
}

const resetToolbarView = (el, pdfViewer) => {
const scaleEl = el.querySelector(".bb-view-scale-input");
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.

Unused variable scaleEl.

Suggested change
const scaleEl = el.querySelector(".bb-view-scale-input");

Copilot uses AI. Check for mistakes.
updateScaleValue(el, pdfViewer.currentScale);
Expand Down Expand Up @@ -624,39 +715,8 @@ const printPdf = url => {
}

export function dispose(id) {
const { el, observer } = Data.get(id);
const pdf = Data.get(id);
Data.remove(id);

if (observer) {
observer.disconnect();
}

if (el) {
const towPagesOneView = el.querySelector(".dropdown-item-pages");
if (towPagesOneView) {
EventHandler.off(towPagesOneView, "click");
}

const toolbar = el.querySelector(".bb-view-toolbar");
if (toolbar) {
EventHandler.off(toolbar, "click");
EventHandler.off(toolbar, "change");
EventHandler.off(toolbar, "focus");
}

const thumbnailsContainer = el.querySelector(".bb-view-thumbnails");
if (thumbnailsContainer) {
EventHandler.off(thumbnailsContainer, "click");
}

const iframe = document.querySelector('.bb-view-print-iframe');
if (iframe) {
iframe.remove();
}

const closeButton = el.querySelector(".btn-close-doc");
if (closeButton) {
EventHandler.off(closeButton, "click");
}
}
disposePdf(pdf);
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 dispose function doesn't check if the pdf object exists before calling disposePdf. If Data.get(id) returns undefined, disposePdf will be called with an invalid value.

Suggested change
disposePdf(pdf);
if (pdf) {
disposePdf(pdf);
}

Copilot uses AI. Check for mistakes.
}
Loading