feat(wopi): implement required rest api as a WOPI host

This commit is contained in:
HFO4 2023-01-09 19:30:50 +08:00
parent 9d8d233018
commit b5d38e3cf7

View File

@ -1,22 +1,31 @@
import React, { useCallback, useEffect, useState } from "react";
import { makeStyles } from "@material-ui/core/styles";
import { makeStyles, useTheme } from "@material-ui/core/styles";
import { useLocation, useParams, useRouteMatch } from "react-router";
import API from "../../middleware/Api";
import { useDispatch } from "react-redux";
import { useDispatch, useSelector } from "react-redux";
import pathHelper from "../../utils/page";
import { toggleSnackbar } from "../../redux/explorer";
import {
closeAllModals,
openShareDialog,
setModalsLoading,
setSelectedTarget,
toggleSnackbar,
} from "../../redux/explorer";
import UseFileSubTitle from "../../hooks/fileSubtitle";
import i18n from "i18next";
import CreatShare from "../Modals/CreateShare";
const useStyles = makeStyles(() => ({
layout: {
width: "auto",
},
container: {
border: "none",
width: "100%",
height: "calc(100vh - 64px)",
marginBottom: -10,
"@global": {
iframe: {
border: "none",
width: "100%",
height: "calc(100vh - 64px)",
marginBottom: -10,
},
},
}));
@ -25,20 +34,35 @@ function useQuery() {
}
export default function DocViewer() {
const [url, setURL] = useState("");
const [session, setSession] = useState(null);
const [file, setFile] = useState(null);
const math = useRouteMatch();
const location = useLocation();
const query = useQuery();
const { id } = useParams();
UseFileSubTitle(query, math, location);
const theme = useTheme();
const { title } = UseFileSubTitle(query, math, location);
const shareOpened = useSelector((state) => state.viewUpdate.modals.share);
const modalLoading = useSelector((state) => state.viewUpdate.modalsLoading);
const dispatch = useDispatch();
const ToggleSnackbar = useCallback(
(vertical, horizontal, msg, color) =>
dispatch(toggleSnackbar(vertical, horizontal, msg, color)),
[dispatch]
);
const CloseAllModals = useCallback(
() => dispatch(closeAllModals()),
[dispatch]
);
const OpenShareDialog = useCallback(
() => dispatch(openShareDialog()),
[dispatch]
);
const SetModalsLoading = useCallback(
(status) => dispatch(setModalsLoading(status)),
[dispatch]
);
useEffect(() => {
let requestURL = "/file/doc/" + query.get("id");
@ -51,7 +75,18 @@ export default function DocViewer() {
}
API.get(requestURL)
.then((response) => {
setURL(response.data);
if (response.data.access_token) {
response.data.url = response.data.url.replaceAll(
"lng",
i18n.resolvedLanguage.toLowerCase()
);
response.data.url = response.data.url.replaceAll(
"darkmode",
theme.palette.type === "dark" ? "2" : "1"
);
}
setSession(response.data);
})
.catch((error) => {
ToggleSnackbar("top", "right", error.message, "error");
@ -60,10 +95,91 @@ export default function DocViewer() {
}, [math.params[0], location]);
const classes = useStyles();
const handlePostMessage = (e) => {
console.log("Received PostMessage from " + e.origin, e.data);
let msg;
try {
msg = JSON.parse(e.data);
} catch (e) {
return;
}
if (msg.MessageId === "UI_Sharing") {
setFile([
{
name: title,
id: query.get("id"),
type: "file",
},
]);
OpenShareDialog();
}
};
useEffect(() => {
const frameholder = document.getElementById("frameholder");
const office_frame = document.createElement("iframe");
if (session && session.access_token && frameholder) {
office_frame.name = "office_frame";
office_frame.id = "office_frame";
// The title should be set for accessibility
office_frame.title = "Office Frame";
// This attribute allows true fullscreen mode in slideshow view
// when using PowerPoint's 'view' action.
office_frame.setAttribute("allowfullscreen", "true");
// The sandbox attribute is needed to allow automatic redirection to the O365 sign-in page in the business user flow
office_frame.setAttribute(
"sandbox",
"allow-scripts allow-same-origin allow-forms allow-popups allow-top-navigation allow-popups-to-escape-sandbox"
);
frameholder.appendChild(office_frame);
document.getElementById("office_form").submit();
window.addEventListener("message", handlePostMessage, false);
return () => {
window.removeEventListener("message", handlePostMessage, false);
};
}
}, [session]);
return (
<div className={classes.layout}>
{url !== "" && (
<iframe title={"ms"} className={classes.container} src={url} />
<CreatShare
open={shareOpened}
onClose={() => CloseAllModals()}
modalsLoading={modalLoading}
setModalsLoading={SetModalsLoading}
selected={file}
/>
{session && !session.access_token && (
<iframe title={"ms"} src={session.url} />
)}
{session && session.access_token && (
<>
<form
id="office_form"
name="office_form"
target="office_frame"
action={session.url}
method="post"
>
<input
name="access_token"
value={session.access_token}
type="hidden"
/>
<input
name="access_token_ttl"
value={session.access_token_ttl}
type="hidden"
/>
</form>
<span id="frameholder"></span>
</>
)}
</div>
);