feat: Add UI and logic to handle password-protected PDF documents.
This commit is contained in:
@@ -10,6 +10,7 @@ import React, {
|
||||
import type { CSSProperties, JSX, MutableRefObject, RefObject } from 'react';
|
||||
import {
|
||||
GlobalWorkerOptions,
|
||||
PasswordResponses,
|
||||
getDocument,
|
||||
} from 'pdfjs-dist';
|
||||
import type {
|
||||
@@ -106,6 +107,10 @@ const PdfViewer = ({ src, title, className, viewportRef }: PdfViewerProps): JSX.
|
||||
velocity: 0,
|
||||
});
|
||||
const scrollElementRef = useRef<HTMLElement | null>(null);
|
||||
const [isEncrypted, setIsEncrypted] = useState(false);
|
||||
const [passwordError, setPasswordError] = useState(false);
|
||||
const [passwordCallback, setPasswordCallback] = useState<((password: string) => void) | null>(null);
|
||||
const passwordInputRef = useRef<HTMLInputElement>(null);
|
||||
|
||||
const requestQueueFlush = useCallback(() => {
|
||||
const queue = renderQueueRef.current;
|
||||
@@ -283,6 +288,14 @@ const PdfViewer = ({ src, title, className, viewportRef }: PdfViewerProps): JSX.
|
||||
url: src,
|
||||
wasmUrl,
|
||||
});
|
||||
loadingTask.onPassword = (callback, reason) => {
|
||||
setIsEncrypted(true);
|
||||
setPasswordCallback(() => callback);
|
||||
if (reason === PasswordResponses.INCORRECT_PASSWORD) {
|
||||
setPasswordError(true);
|
||||
}
|
||||
};
|
||||
|
||||
const pdf = await loadingTask.promise;
|
||||
if (cancelled) {
|
||||
await pdf.destroy();
|
||||
@@ -342,6 +355,13 @@ const PdfViewer = ({ src, title, className, viewportRef }: PdfViewerProps): JSX.
|
||||
};
|
||||
}, [ensureWasmUrl, renderWidth, src]);
|
||||
|
||||
const handlePasswordSubmit = useCallback((event: React.FormEvent) => {
|
||||
event.preventDefault();
|
||||
if (passwordCallback && passwordInputRef.current) {
|
||||
passwordCallback(passwordInputRef.current.value);
|
||||
}
|
||||
}, [passwordCallback]);
|
||||
|
||||
const viewerClasses = ['document-viewer__object', 'document-viewer__object--pdf', className]
|
||||
.filter(Boolean)
|
||||
.join(' ');
|
||||
@@ -553,22 +573,55 @@ const PdfViewer = ({ src, title, className, viewportRef }: PdfViewerProps): JSX.
|
||||
|
||||
return (
|
||||
<div className={viewerClasses}>
|
||||
<div
|
||||
ref={containerRef}
|
||||
className={`pdf-viewer__canvas-stack pdf-viewer__canvas-stack--${viewMode}`}
|
||||
role="document"
|
||||
aria-label={title || 'PDF document'}
|
||||
style={stackStyle}
|
||||
>
|
||||
{pageElements}
|
||||
</div>
|
||||
{showStatus ? (
|
||||
<div className={statusClasses}>
|
||||
<div className="document-viewer__message">
|
||||
{statusMessage}
|
||||
</div>
|
||||
{isEncrypted && !pdfRef.current ? (
|
||||
<div
|
||||
className="pdf-viewer__password-container"
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
onKeyDown={(e) => e.stopPropagation()}
|
||||
>
|
||||
<form onSubmit={handlePasswordSubmit} className="pdf-viewer__password-form">
|
||||
<div className="pdf-viewer__password-message">
|
||||
This document is password protected.
|
||||
</div>
|
||||
<div className="pdf-viewer__password-input-group">
|
||||
<input
|
||||
ref={passwordInputRef}
|
||||
type="password"
|
||||
className="pdf-viewer__password-input"
|
||||
placeholder="Enter password"
|
||||
autoFocus
|
||||
/>
|
||||
<button type="submit" className="button button--primary">
|
||||
Unlock
|
||||
</button>
|
||||
</div>
|
||||
{passwordError ? (
|
||||
<div className="pdf-viewer__password-error">
|
||||
Incorrect password. Please try again.
|
||||
</div>
|
||||
) : null}
|
||||
</form>
|
||||
</div>
|
||||
) : null}
|
||||
) : (
|
||||
<>
|
||||
<div
|
||||
ref={containerRef}
|
||||
className={`pdf-viewer__canvas-stack pdf-viewer__canvas-stack--${viewMode}`}
|
||||
role="document"
|
||||
aria-label={title || 'PDF document'}
|
||||
style={stackStyle}
|
||||
>
|
||||
{pageElements}
|
||||
</div>
|
||||
{showStatus ? (
|
||||
<div className={statusClasses}>
|
||||
<div className="document-viewer__message">
|
||||
{statusMessage}
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user