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.20</Version>
<Version>10.0.21</Version>
</PropertyGroup>

<PropertyGroup>
Expand Down
98 changes: 58 additions & 40 deletions src/components/BootstrapBlazor.PdfReader/PdfReader.razor.js
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,11 @@ const disposePdf = pdf => {
if (thumbnailsContainer) {
thumbnailsContainer.innerHTML = "";
}

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

Expand Down Expand Up @@ -513,7 +518,7 @@ const addToolbarEventHandlers = (el, pdfViewer, invoke, options) => {
rotateView(pdfViewer, 90);
});
EventHandler.on(toolbar, "click", ".bb-view-print", async e => {
printPdf(options.url);
await printPdf(el, options);
await invoke.invokeMethodAsync("Printing");
})
Copy link

Copilot AI Dec 18, 2025

Choose a reason for hiding this comment

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

Avoid automated semicolon insertion (95% of all statements in the enclosing function have an explicit semicolon).

Suggested change
})
});

Copilot uses AI. Check for mistakes.
EventHandler.on(toolbar, "click", ".dropdown-item-pages", async e => {
Expand All @@ -526,23 +531,15 @@ const addToolbarEventHandlers = (el, pdfViewer, invoke, options) => {
pdfViewer.spreadMode = 0;
}
});
EventHandler.on(toolbar, "click", ".bb-view-download", e => {
EventHandler.on(toolbar, "click", ".bb-view-download", async e => {
let fileName = el.getAttribute('data-bb-download');
if (options.url) {
if (fileName === null) {
const docTitle = el.querySelector('.bb-view-subject');
if (docTitle) {
fileName = docTitle.textContent;
}
if (fileName === null) {
const docTitle = el.querySelector('.bb-view-subject');
if (docTitle) {
fileName = docTitle.textContent;
}
downloadPdf(options.url, fileName);
}
else if (options.data) {
const blob = new Blob([options.data], { type: 'application/pdf' });
const url = window.URL.createObjectURL(blob);
downloadPdf(url, fileName);
window.URL.revokeObjectURL(url);
}
await downloadPdf(options, fileName);
});

EventHandler.on(toolbar, "click", ".dropdown-item-presentation", async e => {
Expand Down Expand Up @@ -571,16 +568,23 @@ const addToolbarEventHandlers = (el, pdfViewer, invoke, options) => {
});
}

const downloadPdf = (url, fileName) => {
const downloadPdf = async (options, fileName) => {
if (fileName === null) {
fileName = "download.pdf";
}
const anchorElement = document.createElement('a');
anchorElement.href = url;
anchorElement.download = fileName;
document.body.appendChild(anchorElement);
anchorElement.click();
document.body.removeChild(anchorElement);

await getPdfUrl(options, url => {
const anchorElement = document.createElement('a');
anchorElement.href = url;
anchorElement.download = fileName;
document.body.appendChild(anchorElement);
anchorElement.click();
document.body.removeChild(anchorElement);

return new Promise((resolve, reject) => {
resolve();
});
Comment on lines +583 to +586
Copy link

Copilot AI Dec 18, 2025

Choose a reason for hiding this comment

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

The Promise created here is unnecessary and doesn't serve any purpose. The promise is immediately resolved synchronously without waiting for any asynchronous operation. The callback should either return a meaningful promise or not return anything at all since the caller doesn't appear to need the return value.

Suggested change
return new Promise((resolve, reject) => {
resolve();
});

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

const removeToolbarEventHandlers = el => {
Expand Down Expand Up @@ -748,25 +752,39 @@ const makeThumb = async page => {
return canvas;
}

const printPdf = url => {
let iframe = document.querySelector(".bb-view-print-iframe");
if (iframe) {
iframe.remove();
}

iframe = document.createElement("iframe");
iframe.classList.add("bb-view-print-iframe");
iframe.style.position = "fixed";
iframe.style.right = "100%";
iframe.style.bottom = "100%";
iframe.src = url;

iframe.onload = () => {
iframe.contentWindow.focus();
iframe.contentWindow.print();
};
const printPdf = async (el, options) => {
let iframe = el.querySelector(".bb-view-print-iframe");
if (iframe === null) {
iframe = document.createElement("iframe");
iframe.classList.add("bb-view-print-iframe");
iframe.style.position = "fixed";
iframe.style.right = "100%";
iframe.style.bottom = "100%";
el.appendChild(iframe);
}

await getPdfUrl(options, url => {
iframe.src = url;
iframe.onload = () => {
iframe.contentWindow.focus();
iframe.contentWindow.print();
};
return new Promise((resolve, reject) => {
resolve();
});
Comment on lines +772 to +774
Copy link

Copilot AI Dec 18, 2025

Choose a reason for hiding this comment

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

The Promise created here is unnecessary and doesn't serve any purpose. The promise is immediately resolved synchronously without waiting for any asynchronous operation. The callback should either return a meaningful promise (e.g., one that resolves when iframe.onload completes) or not return anything at all since the caller doesn't appear to need the return value.

Suggested change
return new Promise((resolve, reject) => {
resolve();
});

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

document.body.appendChild(iframe);
const getPdfUrl = async (options, callback) => {
if (options.url) {
callback(options.url);
Copy link

Copilot AI Dec 18, 2025

Choose a reason for hiding this comment

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

When options.url is provided, the callback is invoked but its return value is not awaited. This is inconsistent with line 785 where the callback is awaited when options.data is used. This inconsistency could lead to race conditions or unexpected behavior. Either await the callback in both cases or remove the await in both cases, depending on whether the callback is expected to be asynchronous.

Suggested change
callback(options.url);
await callback(options.url);

Copilot uses AI. Check for mistakes.
}
else if (options.data) {
const blob = new Blob([options.data], { type: 'application/pdf' });
var url = window.URL.createObjectURL(blob);
Copy link

Copilot AI Dec 18, 2025

Choose a reason for hiding this comment

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

Use 'const' or 'let' instead of 'var' to declare the url variable. The use of 'var' is inconsistent with modern JavaScript best practices and can lead to unexpected scoping issues.

Suggested change
var url = window.URL.createObjectURL(blob);
const url = window.URL.createObjectURL(blob);

Copilot uses AI. Check for mistakes.
await callback(url);
window.URL.revokeObjectURL(url);
Copy link

Copilot AI Dec 18, 2025

Choose a reason for hiding this comment

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

The blob URL is revoked immediately after calling the callback, which may cause issues if the callback uses the URL asynchronously. For example, in printPdf, the URL is assigned to iframe.src, but the actual loading happens asynchronously via the onload event. Revoking the URL before the iframe finishes loading could result in a failed load. Consider revoking the URL only after the asynchronous operation completes, or adding a delay before revocation.

Copilot uses AI. Check for mistakes.
}
}

export function dispose(id) {
Expand Down
Loading