diff --git a/BlazorBootstrap.Demo.RCL/Components/Pages/PdfViewer/PdfViewerDocumentation.razor b/BlazorBootstrap.Demo.RCL/Components/Pages/PdfViewer/PdfViewerDocumentation.razor index c959b8d54..51f6d6db9 100644 --- a/BlazorBootstrap.Demo.RCL/Components/Pages/PdfViewer/PdfViewerDocumentation.razor +++ b/BlazorBootstrap.Demo.RCL/Components/Pages/PdfViewer/PdfViewerDocumentation.razor @@ -35,6 +35,21 @@ Blazor Bootstrap: Blazor PDF Viewer Component - RTL doc +
+
+ To open a password-protected PDF document, set the Password parameter to the required password. +
+ +
+ +
+
+ If the Password parameter is not set and the PDF document is password-protected, the PDF Viewer component will prompt the user to enter the password. + In the following example, the PDF Viewer prompts the user to enter the password for the protected PDF document. Enter 12345 as the password to view the document. +
+ +
+ @code { private const string pageUrl = RouteConstants.Demos_PDFViewer_Documentation; private const string pageTitle = "Blazor PDF Viewer"; diff --git a/BlazorBootstrap.Demo.RCL/Components/Pages/PdfViewer/PdfViewer_Demo_05_Password_Protected_A.razor b/BlazorBootstrap.Demo.RCL/Components/Pages/PdfViewer/PdfViewer_Demo_05_Password_Protected_A.razor new file mode 100644 index 000000000..2be8ced72 --- /dev/null +++ b/BlazorBootstrap.Demo.RCL/Components/Pages/PdfViewer/PdfViewer_Demo_05_Password_Protected_A.razor @@ -0,0 +1,3 @@ + diff --git a/BlazorBootstrap.Demo.RCL/Components/Pages/PdfViewer/PdfViewer_Demo_05_Password_Protected_B_Prompt_For_Password.razor b/BlazorBootstrap.Demo.RCL/Components/Pages/PdfViewer/PdfViewer_Demo_05_Password_Protected_B_Prompt_For_Password.razor new file mode 100644 index 000000000..7651c0af6 --- /dev/null +++ b/BlazorBootstrap.Demo.RCL/Components/Pages/PdfViewer/PdfViewer_Demo_05_Password_Protected_B_Prompt_For_Password.razor @@ -0,0 +1,12 @@ +@if (showPdfViewer) +{ + +} +else +{ + +} + +@code { + private bool showPdfViewer = false; +} \ No newline at end of file diff --git a/BlazorBootstrap.Demo.RCL/wwwroot/docs/pdf_password_protected.pdf b/BlazorBootstrap.Demo.RCL/wwwroot/docs/pdf_password_protected.pdf new file mode 100644 index 000000000..9c8652248 Binary files /dev/null and b/BlazorBootstrap.Demo.RCL/wwwroot/docs/pdf_password_protected.pdf differ diff --git a/blazorbootstrap/Components/PdfViewer/PdfViewer.razor.cs b/blazorbootstrap/Components/PdfViewer/PdfViewer.razor.cs index 5a0056530..d4a4a18d9 100644 --- a/blazorbootstrap/Components/PdfViewer/PdfViewer.razor.cs +++ b/blazorbootstrap/Components/PdfViewer/PdfViewer.razor.cs @@ -32,7 +32,7 @@ public partial class PdfViewer : BlazorBootstrapComponentBase protected override async Task OnAfterRenderAsync(bool firstRender) { if (firstRender) - await PdfViewerJsInterop.InitializeAsync(objRef!, Id!, scale, rotation, Url!); + await PdfViewerJsInterop.InitializeAsync(objRef!, Id!, scale, rotation, Url!, Password!); await base.OnAfterRenderAsync(firstRender); } @@ -73,6 +73,15 @@ public void DocumentLoaded(PdfViewerModel pdfViewerModel) OnDocumentLoaded.InvokeAsync(new PdfViewerEventArgs(pageNumber, pagesCount)); } + [JSInvokable] + public void DocumentLoadError(string errorMessage) + { + if(string.IsNullOrEmpty(errorMessage)) return; + + if (OnDocumentLoadError.HasDelegate) + OnDocumentLoadError.InvokeAsync(errorMessage); + } + [JSInvokable] public void SetPdfViewerMetaData(PdfViewerModel pdfViewerModel) { @@ -207,6 +216,12 @@ private async Task ZoomOutAsync() [Parameter] public EventCallback OnDocumentLoaded { get; set; } + /// + /// This event fires if there is an error loading the PDF document. + /// + [Parameter] + public EventCallback OnDocumentLoadError { get; set; } + /// /// This event fires immediately after the page is changed. /// @@ -222,6 +237,15 @@ private async Task ZoomOutAsync() [Parameter] public Orientation Orientation { get; set; } = Orientation.Portrait; + /// + /// Gets or sets the password used for the PDF document if it is password-protected. + /// + /// + /// Default value is . + /// + [Parameter] + public string? Password { get; set; } + /// /// Provides JavaScript interop functionality for the PDF viewer. /// diff --git a/blazorbootstrap/Components/PdfViewer/PdfViewerJsInterop.cs b/blazorbootstrap/Components/PdfViewer/PdfViewerJsInterop.cs index 93bfc7f48..087f85bdd 100644 --- a/blazorbootstrap/Components/PdfViewer/PdfViewerJsInterop.cs +++ b/blazorbootstrap/Components/PdfViewer/PdfViewerJsInterop.cs @@ -40,10 +40,10 @@ public async Task GotoPageAsync(object objRef, string elementId, int gotoPageNum await module.InvokeVoidAsync("gotoPage", objRef, elementId, gotoPageNum); } - public async Task InitializeAsync(object objRef, string elementId, double scale, double rotation, string url) + public async Task InitializeAsync(object objRef, string elementId, double scale, double rotation, string url, string password) { var module = await moduleTask.Value; - await module.InvokeVoidAsync("initialize", objRef, elementId, scale, rotation, url); + await module.InvokeVoidAsync("initialize", objRef, elementId, scale, rotation, url, password); } public async Task LastPageAsync(object objRef, string elementId) diff --git a/blazorbootstrap/wwwroot/blazor.bootstrap.pdf.js b/blazorbootstrap/wwwroot/blazor.bootstrap.pdf.js index 67c3e3b02..a920e1782 100644 --- a/blazorbootstrap/wwwroot/blazor.bootstrap.pdf.js +++ b/blazorbootstrap/wwwroot/blazor.bootstrap.pdf.js @@ -194,17 +194,57 @@ pageRotateCwButton.disabled = this.pagesCount === 0; pageRotateCcwButton.disabled = this.pagesCount === 0; */ -export function initialize(dotNetHelper, elementId, scale, rotation, url) { +export function initialize(dotNetHelper, elementId, scale, rotation, url, password = null) { const pdf = new Pdf(elementId); pdf.scale = scale; pdf.rotation = rotation; - pdfJS.getDocument(url).promise.then(function (doc) { - pdf.pdfDoc = doc; - pdf.pagesCount = doc.numPages; - renderPage(pdf, pdf.pageNum); - dotNetHelper.invokeMethodAsync('DocumentLoaded', { pagesCount: pdf.pagesCount, pageNumber: pdf.pageNum }); - }); + // prepare loading options (optional password allowed) + const options = { url }; + if (password) { + options.password = password; // pre-supply if user already has it + } + + // begin loading document + const loadingTask = pdfJS.getDocument(options); + + // handle password only when required (optional password support) + loadingTask.onPassword = function (updatePassword, reason) { + if (reason === pdfJS.PasswordResponses.NEED_PASSWORD) { + // only prompt if PDF actually requires password + const password = prompt("This PDF is password protected. Enter password:"); + updatePassword(password); + } else if (reason === pdfJS.PasswordResponses.INCORRECT_PASSWORD) { + const password = prompt("Incorrect password. Please try again:"); + updatePassword(password); + } + }; + + // handle the promise + loadingTask + .promise + .then(function (doc) { + pdf.pdfDoc = doc; + pdf.pagesCount = doc.numPages; + renderPage(pdf, pdf.pageNum); + + // notify .NET side that document is loaded + dotNetHelper.invokeMethodAsync('DocumentLoaded', { + pagesCount: pdf.pagesCount, + pageNumber: pdf.pageNum + }); + }) + .catch(function (error) { + console.error("PDF loading error:", error); + + // handle password exceptions specifically + if (error.name === "PasswordException") { + console.error("Password required but not provided"); + } + + // notify .NET side that document loading failed + dotNetHelper.invokeMethodAsync('DocumentLoadError', error.message); + }); } function isDomSupported() { diff --git a/docs/docs/05-components/pdf-viewer.mdx b/docs/docs/05-components/pdf-viewer.mdx index 1c72d59d0..38a27f9a9 100644 --- a/docs/docs/05-components/pdf-viewer.mdx +++ b/docs/docs/05-components/pdf-viewer.mdx @@ -20,6 +20,7 @@ The Blazor PDF Viewer component allows users to view PDF files directly in the b | Name | Type | Default | Required | Description | Added Version | |:--|:--|:--|:--|:--|:--| | Orientation | `Orientation` | `Orientation.Portrait` | | Gets or sets the preferred orientation for the PDF viewer. | 2.1.0 | +| Password | string | null | | Gets or sets the password required to open password-protected PDF documents. | 3.5.0 | | Url | string | null | ✔️ | Gets or sets the URL of the PDF document to be displayed. PDF Viewer component supports base64 string as a URL. | 1.11.0 | ## Callback Events @@ -27,6 +28,7 @@ The Blazor PDF Viewer component allows users to view PDF files directly in the b | Event | Description | Added Version | |:--|:--|:--| | OnDocumentLoaded | This event fires immediately after the PDF document is loaded. | 1.11.0 | +| OnDocumentLoadError | This event fires if there is an error loading the PDF document. | 3.5.0 | | OnPageChanged | This event fires immediately after the page is changed. | 1.11.0 | ## Examples @@ -148,3 +150,41 @@ Below screenshot is added for demo purposes only. For additional info, refer to => eventLog = $"Last event: OnPageChanged, CurrentPage: {args.CurrentPage}, TotalPages: {args.TotalPages}"; } ``` + +### Password protected + +To open a password-protected PDF document, set the Password parameter to the required password. + +Blazor Bootstrap: Blazor PDF Viewer Component - Password protected + +```cshtml {} showLineNumbers + +``` + +[See demo here.](https://demos.blazorbootstrap.com/pdf-viewer#password-protected) + +### Prompt for password + +If the Password parameter is not set and the PDF document is password-protected, the PDF Viewer component will prompt the user to enter the password. +In the following example, the PDF Viewer prompts the user to enter the password for the protected PDF document. Enter 12345 as the password to view the document. + +Blazor Bootstrap: Blazor PDF Viewer Component - Prompt for password + +```cshtml {} showLineNumbers +@if (showPdfViewer) +{ + +} +else +{ + +} + +@code { + private bool showPdfViewer = false; +} +``` + +[See demo here.](https://demos.blazorbootstrap.com/pdf-viewer#prompt-for-password)