Web: Added PDF viewer

This commit is contained in:
Akmal Isomadinov 2023-04-28 17:04:46 +05:00
parent 266b3c73b5
commit a42103b2bd
10 changed files with 199 additions and 8 deletions

View File

@ -37,7 +37,7 @@ class MediaViewerDataStore {
return;
}
if (!file.canOpenPlayer) return;
if (!file.canOpenPlayer && !file.fileExst === ".pdf") return;
this.previewFile = file;
this.id = file.id;
@ -140,7 +140,9 @@ class MediaViewerDataStore {
if (filesList.length > 0) {
filesList.forEach((file) => {
const canOpenPlayer =
file.viewAccessability.ImageView || file.viewAccessability.MediaView;
file.viewAccessability.ImageView ||
file.viewAccessability.MediaView ||
file.fileExst === ".pdf";
if (canOpenPlayer) {
playlist.push({

View File

@ -8,6 +8,7 @@ import {
export const mediaTypes = Object.freeze({
audio: 1,
video: 2,
pdf: 3,
});
export enum KeyboardEventKeys {
@ -56,6 +57,7 @@ export const mapSupplied = {
".avi": { supply: "m4v", type: mediaTypes.video, convertable: true },
".mpeg": { supply: "m4v", type: mediaTypes.video, convertable: true },
".mpg": { supply: "m4v", type: mediaTypes.video, convertable: true },
".pdf": { supply: "pdf", type: mediaTypes.pdf },
} as Record<string, { supply: string; type: number } | undefined>;
export function isVideo(fileExst: string): boolean {

View File

@ -284,8 +284,9 @@ function MediaViewer({
const onDelete = () => {
const { playlist, onDelete } = props;
let currentFileId = playlist.find((file) => file.id === playlistPos)
?.fileId;
let currentFileId = playlist.find(
(file) => file.id === playlistPos
)?.fileId;
if (currentFileId === lastRemovedFileId) return;
@ -302,8 +303,9 @@ function MediaViewer({
const onDownload = () => {
const { playlist, onDownload } = props;
let currentFileId = playlist.find((file) => file.id === playlistPos)
?.fileId;
let currentFileId = playlist.find(
(file) => file.id === playlistPos
)?.fileId;
if (!isNullOrUndefined(currentFileId)) onDownload(currentFileId);
};
@ -394,6 +396,7 @@ function MediaViewer({
let isAudio = false;
let canOpen = true;
let isImage = false;
let isPdf = false;
const archiveRoom =
props.archiveRoomsId === targetFile?.rootFolderId ||
@ -408,12 +411,16 @@ function MediaViewer({
isImage = true;
} else {
isImage = false;
isVideo = mapSupplied[ext]
? mapSupplied[ext]?.type == mediaTypes.video
: false;
isAudio = mapSupplied[ext]
? mapSupplied[ext]?.type == mediaTypes.audio
: false;
isPdf = mapSupplied[ext] ? mapSupplied[ext]?.type == mediaTypes.pdf : false;
}
return (
@ -437,6 +444,7 @@ function MediaViewer({
isImage={isImage}
isAudio={isAudio}
isVideo={isVideo}
isPdf={isPdf}
isPreviewFile={props.isPreviewFile}
onDownloadClick={onDownload}
archiveRoom={archiveRoom}

View File

@ -0,0 +1,5 @@
interface PDFViewerProps {
src: string;
}
export default PDFViewerProps;

View File

@ -0,0 +1,164 @@
import React, { useEffect, useLayoutEffect, useState, useRef } from "react";
import styled from "styled-components";
import { loadScript, combineUrl } from "@docspace/common/utils";
import PDFViewerProps from "./PDFViewer.props";
import ViewerLoader from "../ViewerLoader";
import "./lib/AllFonts.js";
import "./lib/device_scale.js";
import "./lib/browser.js";
import "./lib/stringserialize.js";
import "./lib/skin.js";
import "./lib/font/loader.js";
import "./lib/font/map.js";
import "./lib/font/character.js";
import "./lib/SerializeCommonWordExcel.js";
import "./lib/Externals.js";
import "./lib/GlobalLoaders.js";
import "./lib/scroll.js";
import "./lib/WorkEvents.js";
import "./lib/Overlay.js";
// import "./lib/bookmarks.js";
import "./lib/file.js";
import "./lib/api.js";
const pdfViewerId = "pdf-viewer";
const PdfViewrWrapper = styled.div`
position: fixed;
z-index: 305;
inset: 0;
display: flex;
justify-content: center;
align-items: center;
#mainPanel {
width: 100%;
height: 100%;
position: relative;
}
.block_elem {
position: absolute;
padding: 0;
margin: 0;
}
`;
const ErrorMessage = styled.p`
padding: 20px 30px;
background-color: rgba(0, 0, 0, 0.6);
`;
function PDFViewer({ src }: PDFViewerProps) {
const containerRef = useRef<HTMLDivElement>(null);
const [file, setFile] = useState<ArrayBuffer | string | null>();
const [isError, setIsError] = useState<boolean>(false);
const [isLoadedViewerScript, setIsLoadedViewerScript] = useState<boolean>(
() => {
const result = document.getElementById(pdfViewerId);
return result !== null;
}
);
const [isLoadingScript, setIsLoadingScript] = useState<boolean>(false);
const [isLoadingFile, setIsLoadingFile] = useState<boolean>(false);
useLayoutEffect(() => {
const origin = window.location.origin;
const path = window.DocSpaceConfig.pdfViewerUrl;
if (!isLoadedViewerScript) {
setIsLoadingScript(true);
loadScript(
combineUrl(origin, path),
pdfViewerId,
() => {
//@ts-ignore
window.Viewer = new window.AscViewer.CViewer("mainPanel", {});
setIsLoadedViewerScript(true);
setIsLoadingScript(false);
},
(event) => {
setIsLoadingScript(false);
setIsError(true);
console.error(event);
}
);
}
}, []);
useEffect(() => {
setIsLoadingFile(true);
fetch(src)
.then((value) => {
return value.blob();
})
.then((value) => {
const reader = new FileReader();
reader.onload = function (e) {
setFile(e.target?.result);
};
reader.readAsArrayBuffer(value);
})
.catch((event) => {
setIsError(true);
console.error(event);
})
.finally(() => {
setIsLoadingFile(false);
});
}, [src]);
useEffect(() => {
if (isLoadedViewerScript && !isLoadingFile && file) {
try {
if (!containerRef.current?.hasChildNodes()) {
//@ts-ignore
window.Viewer = new window.AscViewer.CViewer("mainPanel", {});
}
//@ts-ignore
window.Viewer.open(file);
} catch (error) {
setIsError(true);
console.log(error);
}
}
}, [file, isLoadedViewerScript, isLoadingFile]);
if (isError) {
return (
<PdfViewrWrapper>
<ErrorMessage>Something went wrong</ErrorMessage>
</PdfViewrWrapper>
);
}
return (
<>
<PdfViewrWrapper>
<ViewerLoader isLoading={isLoadingFile || isLoadingScript} />
<div
ref={containerRef}
style={{
visibility: isLoadingFile || isLoadingScript ? "hidden" : "visible",
}}
id="mainPanel"
></div>
</PdfViewrWrapper>
</>
);
}
export default PDFViewer;

View File

@ -8,6 +8,7 @@ interface ViewerProps {
isVideo: boolean;
visible: boolean;
isImage: boolean;
isPdf: boolean;
playlist: PlaylistType[];
inactive: boolean;

View File

@ -14,6 +14,7 @@ import DesktopDetails from "../DesktopDetails";
import ViewerPlayer from "../ViewerPlayer";
import type ViewerProps from "./Viewer.props";
import PDFViewer from "../PDFViewer";
function Viewer(props: ViewerProps) {
const timerIDRef = useRef<NodeJS.Timeout>();
@ -197,8 +198,8 @@ function Viewer(props: ViewerProps) {
/>,
containerRef.current
)
: (props.isVideo || props.isAudio) &&
ReactDOM.createPortal(
: props.isVideo || props.isAudio
? ReactDOM.createPortal(
<ViewerPlayer
isError={isError}
src={props.fileUrl}
@ -228,6 +229,11 @@ function Viewer(props: ViewerProps) {
restartToolbarVisibleTimer={restartToolbarVisibleTimer}
/>,
containerRef.current
)
: props.isPdf &&
ReactDOM.createPortal(
<PDFViewer src={props.fileUrl ?? ""} />,
containerRef.current
)}
</StyledViewerContainer>
);

View File

@ -13,6 +13,7 @@ interface ViewerWrapperProps {
isImage: boolean;
isAudio: boolean;
isVideo: boolean;
isPdf: boolean;
isPreviewFile: boolean;
archiveRoom: boolean;

View File

@ -86,6 +86,7 @@ function ViewerWrapper(props: ViewerWrapperProps) {
fileUrl={props.fileUrl}
isAudio={props.isAudio}
isVideo={props.isVideo}
isPdf={props.isPdf}
visible={props.visible}
isImage={props.isImage}
playlist={props.playlist}

View File

@ -1,6 +1,7 @@
declare global {
interface Window {
Tiff: new (arg: object) => any;
DocSpaceConfig: any;
}
}