Doceditor: refactoring
This commit is contained in:
parent
a9e9eb0c4e
commit
b0322cd68b
@ -1,122 +1,225 @@
|
||||
"use client";
|
||||
|
||||
import React from "react";
|
||||
import { ThemeProvider } from "styled-components";
|
||||
import { I18nextProvider } from "react-i18next";
|
||||
import { i18n } from "i18next";
|
||||
import { isMobile } from "react-device-detect";
|
||||
|
||||
import { DocumentEditor } from "@onlyoffice/document-editor-react";
|
||||
import IConfig from "@onlyoffice/document-editor-react/dist/esm/model/config";
|
||||
import IConfig from "@onlyoffice/document-editor-react/dist/esm/types/model/config";
|
||||
import { EditorProps, TGoBack } from "@/types";
|
||||
|
||||
import { EditorProps } from "@/types";
|
||||
import useSocketHelper from "@/hooks/useSocketHelper";
|
||||
import useSelectFolderDialog from "@/hooks/useSelectFolderDialog";
|
||||
import useSelectFileDialog from "@/hooks/useSelectFileDialog";
|
||||
import useTheme from "@/hooks/useTheme";
|
||||
import useI18N from "@/hooks/useI18N";
|
||||
import useInit from "@/hooks/useInit";
|
||||
import useEditorEvents from "@/hooks/useEditorEvents";
|
||||
|
||||
import SelectFolderDialog from "./SelectFolderDialog";
|
||||
import SelectFileDialog from "./SelectFileDialog";
|
||||
import { FolderType } from "@docspace/shared/enums";
|
||||
import { getBackUrl, getIsZoom } from "@/utils";
|
||||
import { IS_DESKTOP_EDITOR } from "@/utils/constants";
|
||||
import {
|
||||
onSDKRequestHistoryClose,
|
||||
onSDKRequestEditRights,
|
||||
onSDKInfo,
|
||||
onSDKWarning,
|
||||
onSDKError,
|
||||
onSDKRequestRename,
|
||||
} from "@/utils/events";
|
||||
|
||||
import { getEditorTheme } from "@docspace/shared/utils";
|
||||
|
||||
const Editor = ({
|
||||
config,
|
||||
editorUrl,
|
||||
settings,
|
||||
successAuth,
|
||||
user,
|
||||
view,
|
||||
doc,
|
||||
documentserverUrl,
|
||||
fileInfo,
|
||||
t,
|
||||
onSDKRequestSaveAs,
|
||||
onSDKRequestInsertImage,
|
||||
onSDKRequestSelectSpreadsheet,
|
||||
onSDKRequestSelectDocument,
|
||||
onSDKRequestReferenceSource,
|
||||
}: EditorProps) => {
|
||||
const fileInfo = config?.file;
|
||||
const documentserverUrl = editorUrl.docServiceUrl;
|
||||
const instanceId = config?.document?.referenceData.instanceId;
|
||||
|
||||
const { i18n } = useI18N({ settings, user });
|
||||
const { theme } = useTheme({ user });
|
||||
|
||||
const { socketHelper } = useSocketHelper({ socketUrl: settings.socketUrl });
|
||||
const {
|
||||
onSDKRequestSaveAs,
|
||||
onCloseSelectFolderDialog,
|
||||
onSubmitSelectFolderDialog,
|
||||
getIsDisabledSelectFolderDialog,
|
||||
isVisibleSelectFolderDialog,
|
||||
titleSelectorFolderDialog,
|
||||
} = useSelectFolderDialog({});
|
||||
const {
|
||||
onSDKRequestInsertImage,
|
||||
onSDKRequestReferenceSource,
|
||||
onSDKRequestSelectDocument,
|
||||
onSDKRequestSelectSpreadsheet,
|
||||
onCloseSelectFileDialog,
|
||||
onSubmitSelectFileDialog,
|
||||
getIsDisabledSelectFileDialog,
|
||||
onDocumentReady,
|
||||
onSDKRequestOpen,
|
||||
onSDKRequestReferenceData,
|
||||
onSDKAppReady,
|
||||
onSDKRequestClose,
|
||||
onSDKRequestCreateNew,
|
||||
onSDKRequestHistory,
|
||||
onSDKRequestUsers,
|
||||
onSDKRequestSendNotify,
|
||||
onSDKRequestRestore,
|
||||
onSDKRequestHistoryData,
|
||||
onDocumentStateChange,
|
||||
onMetaChange,
|
||||
onMakeActionLink,
|
||||
|
||||
selectFileDialogFileTypeDetection,
|
||||
createUrl,
|
||||
documentReady,
|
||||
usersInRoom,
|
||||
setDocTitle,
|
||||
} = useEditorEvents({
|
||||
user,
|
||||
successAuth,
|
||||
fileInfo,
|
||||
config,
|
||||
doc,
|
||||
t,
|
||||
});
|
||||
|
||||
selectFileDialogVisible,
|
||||
} = useSelectFileDialog({ instanceId });
|
||||
|
||||
const onDocumentReady = (): void => {
|
||||
throw new Error("Function not implemented.");
|
||||
};
|
||||
useInit({
|
||||
config,
|
||||
successAuth,
|
||||
fileInfo,
|
||||
user,
|
||||
documentReady,
|
||||
setDocTitle,
|
||||
t,
|
||||
});
|
||||
|
||||
const newConfig: IConfig = {
|
||||
document: config.document,
|
||||
documentType: config.documentType,
|
||||
editorConfig: config.editorConfig,
|
||||
token: config.token,
|
||||
type: config.type,
|
||||
events: {},
|
||||
};
|
||||
|
||||
if (successAuth && newConfig.events) {
|
||||
newConfig.editorConfig = { ...config.editorConfig };
|
||||
|
||||
if (view && newConfig.editorConfig) newConfig.editorConfig.mode = "view";
|
||||
if (isMobile) config.type = "mobile";
|
||||
|
||||
let goBack: TGoBack = {} as TGoBack;
|
||||
|
||||
if (fileInfo) {
|
||||
const search = typeof window !== "undefined" ? window.location.search : "";
|
||||
const editorGoBack = new URLSearchParams(search).get("editorGoBack");
|
||||
|
||||
if (editorGoBack === "false") {
|
||||
} else if (editorGoBack === "event") {
|
||||
goBack = {
|
||||
requestClose: true,
|
||||
text: t?.("FileLocation"),
|
||||
};
|
||||
} else {
|
||||
goBack = {
|
||||
requestClose:
|
||||
typeof window !== "undefined"
|
||||
? window.DocSpaceConfig?.editor?.requestClose ?? false
|
||||
: false,
|
||||
text: t?.("FileLocation"),
|
||||
};
|
||||
if (
|
||||
typeof window !== "undefined" &&
|
||||
!window.DocSpaceConfig?.editor?.requestClose
|
||||
) {
|
||||
goBack.blank =
|
||||
typeof window !== "undefined"
|
||||
? window.DocSpaceConfig?.editor?.openOnNewPage ?? true
|
||||
: false;
|
||||
goBack.url = getBackUrl(fileInfo.rootFolderId, fileInfo.folderId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (newConfig.editorConfig)
|
||||
newConfig.editorConfig.customization = {
|
||||
...newConfig.editorConfig.customization,
|
||||
goback: { ...goBack },
|
||||
uiTheme: getEditorTheme(user?.theme),
|
||||
};
|
||||
|
||||
if (newConfig.document && newConfig.document.info)
|
||||
newConfig.document.info.favorite = false;
|
||||
|
||||
// const url = window.location.href;
|
||||
|
||||
// if (url.indexOf("anchor") !== -1) {
|
||||
// const splitUrl = url.split("anchor=");
|
||||
// const decodeURI = decodeURIComponent(splitUrl[1]);
|
||||
// const obj = JSON.parse(decodeURI);
|
||||
|
||||
// config.editorConfig.actionLink = {
|
||||
// action: obj.action,
|
||||
// };
|
||||
// }
|
||||
|
||||
newConfig.events = {
|
||||
onDocumentReady,
|
||||
onRequestHistoryClose: onSDKRequestHistoryClose,
|
||||
onRequestEditRights: () => onSDKRequestEditRights(fileInfo),
|
||||
onAppReady: onSDKAppReady,
|
||||
onInfo: onSDKInfo,
|
||||
onWarning: onSDKWarning,
|
||||
onError: onSDKError,
|
||||
onRequestHistoryData: onSDKRequestHistoryData,
|
||||
onDocumentStateChange,
|
||||
onMetaChange,
|
||||
onMakeActionLink,
|
||||
};
|
||||
|
||||
if (successAuth) {
|
||||
if (fileInfo?.rootFolderType !== FolderType.USER) {
|
||||
//TODO: remove condition for share in my
|
||||
newConfig.events.onRequestUsers = onSDKRequestUsers;
|
||||
newConfig.events.onRequestSendNotify = onSDKRequestSendNotify;
|
||||
}
|
||||
if (!user.isVisitor) {
|
||||
newConfig.events.onRequestSaveAs = onSDKRequestSaveAs;
|
||||
if (
|
||||
IS_DESKTOP_EDITOR ||
|
||||
(typeof window !== "undefined" &&
|
||||
window.DocSpaceConfig?.editor?.openOnNewPage === false)
|
||||
) {
|
||||
newConfig.events.onRequestCreateNew = onSDKRequestCreateNew;
|
||||
}
|
||||
}
|
||||
|
||||
newConfig.events.onRequestInsertImage = onSDKRequestInsertImage;
|
||||
// restore for 1.4 editor version
|
||||
// newConfig.events.onRequestSelectSpreadsheet = onSDKRequestSelectSpreadsheet;
|
||||
// newConfig.events.onRequestSelectDocument = onSDKRequestSelectDocument;
|
||||
// newConfig.events.onRequestReferenceSource = onSDKRequestReferenceSource;
|
||||
if (!user.isVisitor) newConfig.events.onRequestSaveAs = onSDKRequestSaveAs;
|
||||
newConfig.events.onRequestSelectSpreadsheet = onSDKRequestSelectSpreadsheet;
|
||||
newConfig.events.onRequestSelectDocument = onSDKRequestSelectDocument;
|
||||
newConfig.events.onRequestReferenceSource = onSDKRequestReferenceSource;
|
||||
}
|
||||
|
||||
if (!fileInfo.providerKey) {
|
||||
newConfig.events.onRequestReferenceData = onSDKRequestReferenceData;
|
||||
const isZoom = getIsZoom();
|
||||
|
||||
if (!isZoom) {
|
||||
newConfig.events.onRequestOpen = onSDKRequestOpen;
|
||||
}
|
||||
}
|
||||
|
||||
if (fileInfo.security.Rename) {
|
||||
newConfig.events.onRequestRename = (obj: object) =>
|
||||
onSDKRequestRename(obj, fileInfo.id);
|
||||
}
|
||||
|
||||
if (fileInfo.security.ReadHistory) {
|
||||
newConfig.events.onRequestHistory = onSDKRequestHistory;
|
||||
}
|
||||
|
||||
if (fileInfo.security.EditHistory) {
|
||||
newConfig.events.onRequestRestore = onSDKRequestRestore;
|
||||
}
|
||||
|
||||
if (
|
||||
typeof window !== "undefined" &&
|
||||
window.DocSpaceConfig?.editor?.requestClose
|
||||
) {
|
||||
newConfig.events.onRequestClose = onSDKRequestClose;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{" "}
|
||||
<DocumentEditor
|
||||
id={"docspace_editor"}
|
||||
documentServerUrl={documentserverUrl}
|
||||
config={newConfig}
|
||||
height="100%"
|
||||
width="100%"
|
||||
events_onDocumentReady={onDocumentReady}
|
||||
/>
|
||||
{theme && i18n && (
|
||||
<I18nextProvider i18n={i18n}>
|
||||
<ThemeProvider theme={theme}>
|
||||
{isVisibleSelectFolderDialog && !!socketHelper && (
|
||||
<SelectFolderDialog
|
||||
socketHelper={socketHelper}
|
||||
isVisible={isVisibleSelectFolderDialog}
|
||||
onSubmit={onSubmitSelectFolderDialog}
|
||||
onClose={onCloseSelectFolderDialog}
|
||||
titleSelectorFolder={titleSelectorFolderDialog}
|
||||
fileInfo={fileInfo}
|
||||
getIsDisabled={getIsDisabledSelectFolderDialog}
|
||||
/>
|
||||
)}
|
||||
{selectFileDialogVisible && !!socketHelper && (
|
||||
<SelectFileDialog
|
||||
socketHelper={socketHelper}
|
||||
isVisible={selectFileDialogVisible}
|
||||
onSubmit={onSubmitSelectFileDialog}
|
||||
onClose={onCloseSelectFileDialog}
|
||||
getIsDisabled={getIsDisabledSelectFileDialog}
|
||||
fileTypeDetection={selectFileDialogFileTypeDetection}
|
||||
fileInfo={fileInfo}
|
||||
/>
|
||||
)}
|
||||
</ThemeProvider>
|
||||
</I18nextProvider>
|
||||
)}
|
||||
</>
|
||||
<DocumentEditor
|
||||
id={"docspace_editor"}
|
||||
documentServerUrl={documentserverUrl}
|
||||
config={newConfig}
|
||||
height="100%"
|
||||
width="100%"
|
||||
events_onDocumentReady={onDocumentReady}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
|
186
packages/doceditor/src/components/Root.tsx
Normal file
186
packages/doceditor/src/components/Root.tsx
Normal file
@ -0,0 +1,186 @@
|
||||
"use client";
|
||||
|
||||
import React from "react";
|
||||
import { I18nextProvider } from "react-i18next";
|
||||
import { toast } from "react-toastify";
|
||||
|
||||
import { Toast } from "@docspace/shared/components/toast";
|
||||
import { TFile } from "@docspace/shared/api/files/types";
|
||||
import { ThemeProvider } from "@docspace/shared/components/theme-provider";
|
||||
import ErrorBoundary from "@docspace/shared/components/error-boundary/ErrorBoundary";
|
||||
import ErrorContainer from "@docspace/shared/components/error-container/ErrorContainer";
|
||||
import FirebaseHelper from "@docspace/shared/utils/firebase";
|
||||
import { TFirebaseSettings } from "@docspace/shared/api/settings/types";
|
||||
import { TUser } from "@docspace/shared/api/people/types";
|
||||
|
||||
import { TResponse } from "@/types";
|
||||
import useError from "@/hooks/useError";
|
||||
import useI18N from "@/hooks/useI18N";
|
||||
import useTheme from "@/hooks/useTheme";
|
||||
import useDeviceType from "@/hooks/useDeviceType";
|
||||
import useWhiteLabel from "@/hooks/useWhiteLabel";
|
||||
import useRootInit from "@/hooks/useRootInit";
|
||||
import useDeepLink from "@/hooks/useDeepLink";
|
||||
import useSelectFileDialog from "@/hooks/useSelectFileDialog";
|
||||
import useSelectFolderDialog from "@/hooks/useSelectFolderDialog";
|
||||
import useSocketHelper from "@/hooks/useSocketHelper";
|
||||
|
||||
import pkgFile from "../../package.json";
|
||||
|
||||
import DeepLink from "./deep-link";
|
||||
|
||||
import SelectFileDialog from "./SelectFileDialog";
|
||||
import SelectFolderDialog from "./SelectFolderDialog";
|
||||
import Editor from "./Editor";
|
||||
import { IS_VIEW } from "@/utils/constants";
|
||||
|
||||
toast.configure();
|
||||
|
||||
const Root = ({
|
||||
settings,
|
||||
config,
|
||||
successAuth,
|
||||
user,
|
||||
error,
|
||||
isSharingAccess,
|
||||
editorUrl,
|
||||
doc,
|
||||
}: TResponse) => {
|
||||
const documentserverUrl = editorUrl?.docServiceUrl;
|
||||
const fileInfo = config?.file;
|
||||
const firebaseHelper = new FirebaseHelper(
|
||||
settings?.firebase ?? ({} as TFirebaseSettings),
|
||||
);
|
||||
const instanceId = config?.document?.referenceData.instanceId;
|
||||
|
||||
useRootInit({
|
||||
documentType: config?.documentType,
|
||||
fileType: config?.file.fileType,
|
||||
});
|
||||
const { i18n } = useI18N({ settings, user });
|
||||
|
||||
const t = i18n.t ? i18n.t.bind(i18n) : null;
|
||||
const { onError, getErrorMessage } = useError({
|
||||
error,
|
||||
editorUrl: documentserverUrl,
|
||||
t,
|
||||
});
|
||||
const { theme, currentColorTheme } = useTheme({ user });
|
||||
const { currentDeviceType } = useDeviceType();
|
||||
const { logoUrls } = useWhiteLabel();
|
||||
const { isShowDeepLink, setIsShowDeepLink } = useDeepLink({
|
||||
settings,
|
||||
fileInfo,
|
||||
email: user?.email,
|
||||
});
|
||||
|
||||
const { socketHelper } = useSocketHelper({
|
||||
socketUrl: settings?.socketUrl ?? "",
|
||||
});
|
||||
const {
|
||||
onSDKRequestSaveAs,
|
||||
onCloseSelectFolderDialog,
|
||||
onSubmitSelectFolderDialog,
|
||||
getIsDisabledSelectFolderDialog,
|
||||
isVisibleSelectFolderDialog,
|
||||
titleSelectorFolderDialog,
|
||||
} = useSelectFolderDialog({});
|
||||
const {
|
||||
onSDKRequestInsertImage,
|
||||
onSDKRequestReferenceSource,
|
||||
onSDKRequestSelectDocument,
|
||||
onSDKRequestSelectSpreadsheet,
|
||||
onCloseSelectFileDialog,
|
||||
onSubmitSelectFileDialog,
|
||||
getIsDisabledSelectFileDialog,
|
||||
|
||||
selectFileDialogFileTypeDetection,
|
||||
|
||||
selectFileDialogVisible,
|
||||
} = useSelectFileDialog({ instanceId: instanceId ?? "" });
|
||||
|
||||
return (
|
||||
<I18nextProvider i18n={i18n}>
|
||||
<ThemeProvider theme={theme} currentColorScheme={currentColorTheme}>
|
||||
<ErrorBoundary
|
||||
user={user ?? ({} as TUser)}
|
||||
version={pkgFile.version}
|
||||
firebaseHelper={firebaseHelper}
|
||||
currentDeviceType={currentDeviceType}
|
||||
whiteLabelLogoUrls={logoUrls}
|
||||
isNextJS
|
||||
theme={theme}
|
||||
i18n={i18n}
|
||||
onError={onError}
|
||||
>
|
||||
{isShowDeepLink ? (
|
||||
<DeepLink
|
||||
fileInfo={fileInfo}
|
||||
logoUrls={logoUrls}
|
||||
userEmail={user?.email}
|
||||
theme={theme}
|
||||
currentDeviceType={currentDeviceType}
|
||||
deepLinkConfig={settings?.deepLink}
|
||||
setIsShowDeepLink={setIsShowDeepLink}
|
||||
/>
|
||||
) : error && error.message !== "unauthorized" ? (
|
||||
<ErrorContainer
|
||||
headerText={t?.("Common:Error")}
|
||||
customizedBodyText={getErrorMessage()}
|
||||
isEditor
|
||||
/>
|
||||
) : (
|
||||
<>
|
||||
{config && user && documentserverUrl && fileInfo && (
|
||||
<Editor
|
||||
config={config}
|
||||
user={user}
|
||||
view={IS_VIEW}
|
||||
successAuth={successAuth}
|
||||
doc={doc}
|
||||
t={t}
|
||||
documentserverUrl={documentserverUrl}
|
||||
fileInfo={fileInfo}
|
||||
onSDKRequestSaveAs={onSDKRequestSaveAs}
|
||||
onSDKRequestInsertImage={onSDKRequestInsertImage}
|
||||
onSDKRequestReferenceSource={onSDKRequestReferenceSource}
|
||||
onSDKRequestSelectDocument={onSDKRequestSelectDocument}
|
||||
onSDKRequestSelectSpreadsheet={onSDKRequestSelectSpreadsheet}
|
||||
/>
|
||||
)}
|
||||
<Toast />
|
||||
{isVisibleSelectFolderDialog && !!socketHelper && (
|
||||
<SelectFolderDialog
|
||||
socketHelper={socketHelper}
|
||||
isVisible={isVisibleSelectFolderDialog}
|
||||
onSubmit={onSubmitSelectFolderDialog}
|
||||
onClose={onCloseSelectFolderDialog}
|
||||
titleSelectorFolder={titleSelectorFolderDialog}
|
||||
fileInfo={fileInfo ?? ({} as TFile)}
|
||||
getIsDisabled={getIsDisabledSelectFolderDialog}
|
||||
t={t}
|
||||
i18n={i18n}
|
||||
/>
|
||||
)}
|
||||
{selectFileDialogVisible && !!socketHelper && (
|
||||
<SelectFileDialog
|
||||
socketHelper={socketHelper}
|
||||
isVisible={selectFileDialogVisible}
|
||||
onSubmit={onSubmitSelectFileDialog}
|
||||
onClose={onCloseSelectFileDialog}
|
||||
getIsDisabled={getIsDisabledSelectFileDialog}
|
||||
fileTypeDetection={selectFileDialogFileTypeDetection}
|
||||
fileInfo={fileInfo ?? ({} as TFile)}
|
||||
t={t}
|
||||
i18n={i18n}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</ErrorBoundary>
|
||||
</ThemeProvider>
|
||||
</I18nextProvider>
|
||||
);
|
||||
};
|
||||
|
||||
export default Root;
|
@ -1,11 +1,10 @@
|
||||
import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import FilesSelectorWrapper from "@docspace/shared/selectors/Files/FilesSelector.wrapper";
|
||||
|
||||
import { DeviceType, FilesSelectorFilterTypes } from "@docspace/shared/enums";
|
||||
|
||||
import { SelectFileDialogProps } from "@/types";
|
||||
import { useTheme } from "styled-components";
|
||||
|
||||
const SelectFileDialog = ({
|
||||
socketHelper,
|
||||
@ -15,23 +14,23 @@ const SelectFileDialog = ({
|
||||
onClose,
|
||||
onSubmit,
|
||||
fileInfo,
|
||||
t,
|
||||
i18n,
|
||||
}: SelectFileDialogProps) => {
|
||||
const { t, i18n } = useTranslation(["Common", "Editor"]);
|
||||
|
||||
const sessionPath = sessionStorage.getItem("filesSelectorPath");
|
||||
|
||||
const headerLabel = fileTypeDetection.filterParam
|
||||
? t("Common:SelectFile")
|
||||
: t("Common:SelectAction");
|
||||
? t?.("Common:SelectFile") ?? ""
|
||||
: t?.("Common:SelectAction") ?? "";
|
||||
|
||||
const getFileTypeTranslation = React.useCallback(() => {
|
||||
switch (fileTypeDetection.filterParam) {
|
||||
case FilesSelectorFilterTypes.XLSX:
|
||||
return t("Editor:MailMergeFileType");
|
||||
return t?.("Editor:MailMergeFileType") ?? "";
|
||||
case FilesSelectorFilterTypes.IMG:
|
||||
return t("Editor:ImageFileType");
|
||||
return t?.("Editor:ImageFileType") ?? "";
|
||||
case FilesSelectorFilterTypes.DOCX:
|
||||
return t("Editor:DocumentsFileType");
|
||||
return t?.("Editor:DocumentsFileType") ?? "";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
@ -41,16 +40,13 @@ const SelectFileDialog = ({
|
||||
const type = getFileTypeTranslation();
|
||||
return fileTypeDetection.filterParam === FilesSelectorFilterTypes.XLSX
|
||||
? type
|
||||
: t("Editor:SelectFilesType", { fileType: type });
|
||||
: t?.("Editor:SelectFilesType", { fileType: type }) ?? "";
|
||||
}, [fileTypeDetection.filterParam, getFileTypeTranslation, t]);
|
||||
|
||||
const listTitle = selectFilesListTitle();
|
||||
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<FilesSelectorWrapper
|
||||
theme={theme}
|
||||
i18nProp={i18n}
|
||||
withoutBackButton
|
||||
withSearch
|
||||
@ -73,8 +69,8 @@ const SelectFileDialog = ({
|
||||
footerCheckboxLabel=""
|
||||
footerInputHeader=""
|
||||
currentFooterInputValue=""
|
||||
submitButtonLabel={t("Common:SelectAction")}
|
||||
cancelButtonLabel={t("Common:CancelButton")}
|
||||
submitButtonLabel={t?.("Common:SelectAction") ?? ""}
|
||||
cancelButtonLabel={t?.("Common:CancelButton") ?? ""}
|
||||
withCancelButton
|
||||
descriptionText={listTitle}
|
||||
currentDeviceType={DeviceType.desktop}
|
||||
|
@ -8,7 +8,6 @@ import { DeviceType } from "@docspace/shared/enums";
|
||||
|
||||
import { SelectFolderDialogProps } from "@/types";
|
||||
import { TSelectorCancelButton } from "@docspace/shared/components/selector/Selector.types";
|
||||
import { useTheme } from "styled-components";
|
||||
|
||||
const SelectFolderDialog = ({
|
||||
socketHelper,
|
||||
@ -18,23 +17,20 @@ const SelectFolderDialog = ({
|
||||
titleSelectorFolder,
|
||||
fileInfo,
|
||||
getIsDisabled,
|
||||
t,
|
||||
i18n,
|
||||
}: SelectFolderDialogProps) => {
|
||||
const { t, i18n } = useTranslation(["Common", "Editor"]);
|
||||
|
||||
const sessionPath = sessionStorage.getItem("filesSelectorPath");
|
||||
|
||||
const cancelButtonProps: TSelectorCancelButton = {
|
||||
withCancelButton: true,
|
||||
onCancel: onClose,
|
||||
cancelButtonLabel: t("CancelButton"),
|
||||
cancelButtonLabel: t?.("Common:CancelButton") ?? "",
|
||||
cancelButtonId: "select-file-modal-cancel",
|
||||
};
|
||||
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<FilesSelectorWrapper
|
||||
theme={theme}
|
||||
i18nProp={i18n}
|
||||
{...cancelButtonProps}
|
||||
withHeader
|
||||
@ -42,16 +38,16 @@ const SelectFolderDialog = ({
|
||||
withSearch
|
||||
withoutBackButton
|
||||
withCancelButton
|
||||
headerLabel={t("SaveButton")}
|
||||
headerLabel={i18n.t?.("Common:SaveButton") ?? ""}
|
||||
disabledItems={[]}
|
||||
onSubmit={onSubmit}
|
||||
submitButtonLabel={t("SaveHereButton")}
|
||||
submitButtonLabel={i18n.t?.("Common:SaveHereButton") ?? ""}
|
||||
submitButtonId="select-file-modal-submit"
|
||||
socketHelper={socketHelper}
|
||||
socketSubscribers={socketHelper.socketSubscribers}
|
||||
footerInputHeader={t("Editor:FileName")}
|
||||
footerInputHeader={i18n.t?.("Editor:FileName") ?? ""}
|
||||
currentFooterInputValue={titleSelectorFolder}
|
||||
footerCheckboxLabel={t("Editor:OpenSavedDocument")}
|
||||
footerCheckboxLabel={i18n.t?.("Editor:OpenSavedDocument") ?? ""}
|
||||
isPanelVisible={isVisible}
|
||||
isRoomsOnly={false}
|
||||
isThirdParty={false}
|
||||
|
605
packages/doceditor/src/hooks/useEditorEvents.ts
Normal file
605
packages/doceditor/src/hooks/useEditorEvents.ts
Normal file
@ -0,0 +1,605 @@
|
||||
import React from "react";
|
||||
|
||||
import IConfig from "@onlyoffice/document-editor-react/dist/esm/types/model/config";
|
||||
|
||||
import {
|
||||
createFile,
|
||||
getEditDiff,
|
||||
getEditHistory,
|
||||
getProtectUsers,
|
||||
getReferenceData,
|
||||
getSharedUsers,
|
||||
restoreDocumentsVersion,
|
||||
sendEditorNotify,
|
||||
} from "@docspace/shared/api/files";
|
||||
import {
|
||||
TEditHistory,
|
||||
TGetReferenceData,
|
||||
} from "@docspace/shared/api/files/types";
|
||||
import { TUser } from "@docspace/shared/api/people/types";
|
||||
import { EDITOR_ID } from "@docspace/shared/constants";
|
||||
import {
|
||||
assign,
|
||||
frameCallCommand,
|
||||
frameCallEvent,
|
||||
} from "@docspace/shared/utils/common";
|
||||
import { combineUrl } from "@docspace/shared/utils/combineUrl";
|
||||
import { FolderType } from "@docspace/shared/enums";
|
||||
import { toastr } from "@docspace/shared/components/toast";
|
||||
import { TData } from "@docspace/shared/components/toast/Toast.type";
|
||||
import { Nullable } from "@docspace/shared/types";
|
||||
|
||||
import { IS_DESKTOP_EDITOR } from "@/utils/constants";
|
||||
|
||||
import { getCurrentDocumentVersion, setDocumentTitle } from "@/utils";
|
||||
|
||||
import {
|
||||
TCatchError,
|
||||
TDocEditor,
|
||||
TEvent,
|
||||
THistoryData,
|
||||
UseEventsProps,
|
||||
} from "@/types";
|
||||
|
||||
type IConfigEvents = Pick<IConfig, "events">;
|
||||
|
||||
let docEditor: TDocEditor | null = null;
|
||||
|
||||
const useEditorEvents = ({
|
||||
user,
|
||||
successAuth,
|
||||
fileInfo,
|
||||
config,
|
||||
doc,
|
||||
t,
|
||||
}: UseEventsProps) => {
|
||||
const [events, setEvents] = React.useState<IConfigEvents>({});
|
||||
const [documentReady, setDocumentReady] = React.useState(false);
|
||||
const [createUrl, setCreateUrl] = React.useState<Nullable<string>>(null);
|
||||
const [usersInRoom, setUsersInRoom] = React.useState<TUser[]>([]);
|
||||
const [docTitle, setDocTitle] = React.useState("");
|
||||
const [docSaved, setDocSaved] = React.useState(false);
|
||||
|
||||
const onSDKRequestReferenceData = React.useCallback(async (event: object) => {
|
||||
const currEvent = event as TEvent;
|
||||
const referenceData = await getReferenceData(
|
||||
currEvent.data.referenceData ??
|
||||
(currEvent.data as unknown as TGetReferenceData),
|
||||
);
|
||||
|
||||
docEditor?.setReferenceData?.(referenceData);
|
||||
}, []);
|
||||
|
||||
const onSDKRequestOpen = React.useCallback(
|
||||
async (event: object) => {
|
||||
const currEvent = event as TEvent;
|
||||
const windowName = currEvent.data.windowName;
|
||||
const reference = currEvent.data;
|
||||
|
||||
try {
|
||||
const data = {
|
||||
fileKey: reference.referenceData
|
||||
? reference.referenceData.fileKey
|
||||
: "",
|
||||
instanceId: reference.referenceData
|
||||
? reference.referenceData.instanceId
|
||||
: "",
|
||||
fileId: fileInfo.id,
|
||||
path: reference.path || "",
|
||||
};
|
||||
|
||||
const result = await getReferenceData(data);
|
||||
|
||||
if (result.error) throw new Error(result.error);
|
||||
|
||||
var link = result.link;
|
||||
window.open(link, windowName);
|
||||
} catch (e) {
|
||||
var winEditor = window.open("", windowName);
|
||||
|
||||
winEditor?.close();
|
||||
docEditor?.showMessage?.(
|
||||
(e as { message?: string })?.message ??
|
||||
t?.("ErrorConnectionLost") ??
|
||||
"",
|
||||
);
|
||||
}
|
||||
},
|
||||
[fileInfo.id, t],
|
||||
);
|
||||
|
||||
const onSDKAppReady = React.useCallback(() => {
|
||||
docEditor = window.DocEditor.instances[EDITOR_ID];
|
||||
|
||||
console.log("ONLYOFFICE Document Editor is ready", docEditor);
|
||||
const url = window.location.href;
|
||||
|
||||
const index = url.indexOf("#message/");
|
||||
|
||||
if (index > -1) {
|
||||
const splitUrl = url.split("#message/");
|
||||
|
||||
if (splitUrl.length === 2) {
|
||||
const message = decodeURIComponent(splitUrl[1]).replace(/\+/g, " ");
|
||||
|
||||
docEditor?.showMessage?.(message);
|
||||
history.pushState({}, "", url.substring(0, index));
|
||||
} else {
|
||||
if (config?.Error) docEditor?.showMessage?.(config.Error);
|
||||
}
|
||||
}
|
||||
}, [config.Error]);
|
||||
|
||||
const onDocumentReady = React.useCallback(() => {
|
||||
// console.log("onDocumentReady", arguments, { docEditor });
|
||||
setDocumentReady(true);
|
||||
|
||||
frameCallCommand("setIsLoaded");
|
||||
|
||||
if (config?.errorMessage) docEditor?.showMessage?.(config.errorMessage);
|
||||
|
||||
// if (config?.file?.canShare) {
|
||||
// loadUsersRightsList(docEditor);
|
||||
// }
|
||||
|
||||
if (docEditor)
|
||||
assign(
|
||||
window as unknown as { [key: string]: {} },
|
||||
["ASC", "Files", "Editor", "docEditor"],
|
||||
docEditor,
|
||||
); //Do not remove: it's for Back button on Mobile App
|
||||
}, [config.errorMessage]);
|
||||
|
||||
const getBackUrl = React.useCallback(() => {
|
||||
if (!fileInfo) return;
|
||||
const search = window.location.search;
|
||||
const shareIndex = search.indexOf("share=");
|
||||
const key = shareIndex > -1 ? search.substring(shareIndex + 6) : null;
|
||||
|
||||
let backUrl = "";
|
||||
|
||||
if (fileInfo.rootFolderType === FolderType.Rooms) {
|
||||
if (key) {
|
||||
backUrl = `/rooms/share?key=${key}`;
|
||||
} else {
|
||||
backUrl = `/rooms/shared/${fileInfo.folderId}/filter?folder=${fileInfo.folderId}`;
|
||||
}
|
||||
} else {
|
||||
backUrl = `/rooms/personal/filter?folder=${fileInfo.folderId}`;
|
||||
}
|
||||
|
||||
const url = window.location.href;
|
||||
const origin = url.substring(0, url.indexOf("/doceditor"));
|
||||
|
||||
return `${combineUrl(origin, backUrl)}`;
|
||||
}, [fileInfo]);
|
||||
|
||||
const onSDKRequestClose = React.useCallback(() => {
|
||||
const search = window.location.search;
|
||||
const editorGoBack = new URLSearchParams(search).get("editorGoBack");
|
||||
|
||||
if (editorGoBack === "event") {
|
||||
frameCallEvent({ event: "onEditorCloseCallback" });
|
||||
} else {
|
||||
const backUrl = getBackUrl();
|
||||
if (backUrl) window.location.replace(backUrl);
|
||||
}
|
||||
}, [getBackUrl]);
|
||||
|
||||
const getDefaultFileName = React.useCallback(
|
||||
(withExt = false) => {
|
||||
const documentType = config?.documentType;
|
||||
|
||||
const fileExt =
|
||||
documentType === "word"
|
||||
? "docx"
|
||||
: documentType === "slide"
|
||||
? "pptx"
|
||||
: documentType === "cell"
|
||||
? "xlsx"
|
||||
: "docxf";
|
||||
|
||||
let fileName = t?.("Common:NewDocument");
|
||||
|
||||
switch (fileExt) {
|
||||
case "xlsx":
|
||||
fileName = t?.("Common:NewSpreadsheet");
|
||||
break;
|
||||
case "pptx":
|
||||
fileName = t?.("Common:NewPresentation");
|
||||
break;
|
||||
case "docxf":
|
||||
fileName = t?.("Common:NewMasterForm");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (withExt) {
|
||||
fileName = `${fileName}.${fileExt}`;
|
||||
}
|
||||
|
||||
return fileName;
|
||||
},
|
||||
[config?.documentType, t],
|
||||
);
|
||||
|
||||
const onSDKRequestCreateNew = React.useCallback(() => {
|
||||
const defaultFileName = getDefaultFileName(true);
|
||||
|
||||
createFile(fileInfo.folderId, defaultFileName ?? "")
|
||||
?.then((newFile) => {
|
||||
const newUrl = combineUrl(
|
||||
window.DocSpaceConfig?.proxy?.url,
|
||||
`/doceditor?fileId=${encodeURIComponent(newFile.id)}`,
|
||||
);
|
||||
window.open(
|
||||
newUrl,
|
||||
window.DocSpaceConfig?.editor?.openOnNewPage ? "_blank" : "_self",
|
||||
);
|
||||
})
|
||||
.catch((e) => {
|
||||
toastr.error(e);
|
||||
});
|
||||
}, [fileInfo.folderId, getDefaultFileName]);
|
||||
|
||||
const getDocumentHistory = React.useCallback(
|
||||
(fileHistory: TEditHistory[], historyLength: number) => {
|
||||
let result = [];
|
||||
|
||||
for (let i = 0; i < historyLength; i++) {
|
||||
const changes = fileHistory[i].changes;
|
||||
const serverVersion = fileHistory[i].serverVersion;
|
||||
const version = fileHistory[i].version;
|
||||
const versionGroup = fileHistory[i].versionGroup;
|
||||
|
||||
let obj = {
|
||||
...(changes.length !== 0 && { changes }),
|
||||
created: `${new Date(fileHistory[i].created).toLocaleString(
|
||||
config.editorConfig.lang,
|
||||
)}`,
|
||||
...(serverVersion && { serverVersion }),
|
||||
key: fileHistory[i].key,
|
||||
user: {
|
||||
id: fileHistory[i].user.id,
|
||||
name: fileHistory[i].user.name,
|
||||
},
|
||||
version,
|
||||
versionGroup,
|
||||
};
|
||||
|
||||
result.push(obj);
|
||||
}
|
||||
return result;
|
||||
},
|
||||
[config.editorConfig.lang],
|
||||
);
|
||||
|
||||
const onSDKRequestRestore = React.useCallback(
|
||||
async (event: object) => {
|
||||
const restoreVersion = (event as TEvent).data.version;
|
||||
|
||||
try {
|
||||
const updateVersions = await restoreDocumentsVersion(
|
||||
fileInfo.id,
|
||||
restoreVersion ?? 0,
|
||||
doc ?? "",
|
||||
);
|
||||
const historyLength = updateVersions.length;
|
||||
docEditor?.refreshHistory?.({
|
||||
currentVersion: getCurrentDocumentVersion(
|
||||
updateVersions,
|
||||
historyLength,
|
||||
),
|
||||
history: getDocumentHistory(updateVersions, historyLength),
|
||||
});
|
||||
} catch (error) {
|
||||
let errorMessage = "";
|
||||
|
||||
const typedError = error as TCatchError;
|
||||
if (typeof typedError === "object") {
|
||||
errorMessage =
|
||||
("response" in typedError &&
|
||||
typedError?.response?.data?.error?.message) ||
|
||||
("statusText" in typedError && typedError?.statusText) ||
|
||||
("message" in typedError && typedError?.message) ||
|
||||
"";
|
||||
} else {
|
||||
errorMessage = error as string;
|
||||
}
|
||||
|
||||
docEditor?.refreshHistory?.({
|
||||
error: `${errorMessage}`, //TODO: maybe need to display something else.
|
||||
});
|
||||
}
|
||||
},
|
||||
[doc, fileInfo.id, getDocumentHistory],
|
||||
);
|
||||
|
||||
const onSDKRequestHistory = React.useCallback(async () => {
|
||||
try {
|
||||
// const search = window.location.search;
|
||||
// const shareIndex = search.indexOf("share=");
|
||||
// const requestToken =
|
||||
// shareIndex > -1 ? search.substring(shareIndex + 6) : null;
|
||||
// const docIdx = search.indexOf("doc=");
|
||||
|
||||
const fileHistory = await getEditHistory(fileInfo.id, doc ?? "");
|
||||
const historyLength = fileHistory.length;
|
||||
|
||||
docEditor?.refreshHistory?.({
|
||||
currentVersion: getCurrentDocumentVersion(fileHistory, historyLength),
|
||||
history: getDocumentHistory(fileHistory, historyLength),
|
||||
});
|
||||
} catch (error) {
|
||||
let errorMessage = "";
|
||||
const typedError = error as TCatchError;
|
||||
if (typeof typedError === "object") {
|
||||
errorMessage =
|
||||
("response" in typedError &&
|
||||
typedError?.response?.data?.error?.message) ||
|
||||
("statusText" in typedError && typedError?.statusText) ||
|
||||
("message" in typedError && typedError?.message) ||
|
||||
"";
|
||||
} else {
|
||||
errorMessage = error as string;
|
||||
}
|
||||
docEditor?.refreshHistory?.({
|
||||
error: `${errorMessage}`, //TODO: maybe need to display something else.
|
||||
});
|
||||
}
|
||||
}, [doc, fileInfo.id, getDocumentHistory]);
|
||||
|
||||
const onSDKRequestSendNotify = React.useCallback(
|
||||
async (event: object) => {
|
||||
const currEvent = event as TEvent;
|
||||
|
||||
const actionData = currEvent.data.actionLink;
|
||||
const comment = currEvent.data.message;
|
||||
const emails = currEvent.data.emails;
|
||||
|
||||
try {
|
||||
await sendEditorNotify(
|
||||
fileInfo.id,
|
||||
actionData ?? "",
|
||||
emails ?? [],
|
||||
comment ?? "",
|
||||
);
|
||||
|
||||
if (usersInRoom.length === 0) return;
|
||||
|
||||
const usersNotFound = emails?.filter((row) =>
|
||||
usersInRoom.every((value) => {
|
||||
return row !== value.email;
|
||||
}),
|
||||
);
|
||||
|
||||
usersNotFound &&
|
||||
usersNotFound.length > 0 &&
|
||||
docEditor?.showMessage?.(
|
||||
t?.("UsersWithoutAccess", {
|
||||
users: usersNotFound,
|
||||
}) ?? "",
|
||||
);
|
||||
} catch (e) {
|
||||
toastr.error(e as TData);
|
||||
}
|
||||
},
|
||||
[fileInfo.id, t, usersInRoom],
|
||||
);
|
||||
|
||||
const onSDKRequestUsers = React.useCallback(
|
||||
async (event: object) => {
|
||||
try {
|
||||
const currEvent = event as TEvent;
|
||||
const c = currEvent?.data?.c;
|
||||
const users = await (c == "protect"
|
||||
? getProtectUsers(fileInfo.id)
|
||||
: getSharedUsers(fileInfo.id));
|
||||
|
||||
if (c !== "protect") {
|
||||
const usersArray = users.map(
|
||||
(item) =>
|
||||
({
|
||||
email: item.email,
|
||||
name: item.name,
|
||||
}) as unknown as TUser,
|
||||
);
|
||||
setUsersInRoom(usersArray);
|
||||
}
|
||||
|
||||
docEditor?.setUsers?.({
|
||||
c: c ?? "",
|
||||
users,
|
||||
});
|
||||
} catch (e) {
|
||||
docEditor?.showMessage?.(
|
||||
((e as { message?: string })?.message ||
|
||||
t?.("ErrorConnectionLost")) ??
|
||||
"",
|
||||
);
|
||||
}
|
||||
},
|
||||
[fileInfo.id, t],
|
||||
);
|
||||
|
||||
const onSDKRequestHistoryData = React.useCallback(
|
||||
async (event: object) => {
|
||||
const version = (event as { data: number }).data;
|
||||
|
||||
try {
|
||||
// const search = window.location.search;
|
||||
// const shareIndex = search.indexOf("share=");
|
||||
// const requestToken =
|
||||
// shareIndex > -1 ? search.substring(shareIndex + 6) : null;
|
||||
|
||||
const versionDifference = await getEditDiff(
|
||||
fileInfo.id,
|
||||
version,
|
||||
doc ?? "",
|
||||
// requestToken,
|
||||
);
|
||||
const changesUrl = versionDifference.changesUrl;
|
||||
const previous = versionDifference.previous;
|
||||
const token = versionDifference.token;
|
||||
|
||||
const obj: THistoryData = {
|
||||
url: versionDifference.url,
|
||||
version,
|
||||
key: versionDifference.key,
|
||||
fileType: versionDifference.fileType,
|
||||
};
|
||||
|
||||
if (changesUrl) obj.changesUrl = changesUrl;
|
||||
if (previous)
|
||||
obj.previous = {
|
||||
fileType: previous.fileType,
|
||||
key: previous.key,
|
||||
url: previous.url,
|
||||
};
|
||||
if (token) obj.token = token;
|
||||
|
||||
docEditor?.setHistoryData?.(obj);
|
||||
} catch (error) {
|
||||
let errorMessage = "";
|
||||
const typedError = error as TCatchError;
|
||||
if (typeof typedError === "object") {
|
||||
errorMessage =
|
||||
("response" in typedError &&
|
||||
typedError?.response?.data?.error?.message) ||
|
||||
("statusText" in typedError && typedError?.statusText) ||
|
||||
("message" in typedError && typedError?.message) ||
|
||||
"";
|
||||
} else {
|
||||
errorMessage = error as string;
|
||||
}
|
||||
|
||||
docEditor?.setHistoryData?.({
|
||||
error: `${errorMessage}`, //TODO: maybe need to display something else.
|
||||
version,
|
||||
});
|
||||
}
|
||||
},
|
||||
[doc, fileInfo.id],
|
||||
);
|
||||
|
||||
const onDocumentStateChange = React.useCallback(
|
||||
(event: object) => {
|
||||
if (!documentReady) return;
|
||||
|
||||
setDocSaved(!(event as { data: boolean }).data);
|
||||
|
||||
setTimeout(() => {
|
||||
docSaved
|
||||
? setDocumentTitle(
|
||||
docTitle,
|
||||
config.document.fileType,
|
||||
documentReady,
|
||||
successAuth,
|
||||
setDocTitle,
|
||||
)
|
||||
: setDocumentTitle(
|
||||
`*${docTitle}`,
|
||||
config.document.fileType,
|
||||
documentReady,
|
||||
successAuth,
|
||||
setDocTitle,
|
||||
);
|
||||
}, 500);
|
||||
},
|
||||
[config.document.fileType, docSaved, docTitle, documentReady, successAuth],
|
||||
);
|
||||
|
||||
const onMetaChange = React.useCallback(
|
||||
(event: object) => {
|
||||
const newTitle = (event as { data: { title: string } }).data.title;
|
||||
//const favorite = event.data.favorite;
|
||||
|
||||
if (newTitle && newTitle !== docTitle) {
|
||||
setDocumentTitle(
|
||||
newTitle,
|
||||
config.document.fileType,
|
||||
documentReady,
|
||||
successAuth,
|
||||
setDocTitle,
|
||||
);
|
||||
setDocTitle(newTitle);
|
||||
}
|
||||
},
|
||||
[config.document.fileType, docTitle, documentReady, successAuth],
|
||||
);
|
||||
|
||||
const onMakeActionLink = React.useCallback((event: object) => {
|
||||
const url = window.location.href;
|
||||
|
||||
const actionData = (event as { data: {} }).data;
|
||||
|
||||
const link = generateLink(actionData);
|
||||
|
||||
const urlFormation = url.split("&anchor=")[0];
|
||||
|
||||
const linkFormation = `${urlFormation}&anchor=${link}`;
|
||||
|
||||
docEditor?.setActionLink?.(linkFormation);
|
||||
}, []);
|
||||
|
||||
const generateLink = (actionData: {}) => {
|
||||
return encodeURIComponent(JSON.stringify(actionData));
|
||||
};
|
||||
|
||||
React.useEffect(() => {
|
||||
const tempEvents: IConfigEvents = {};
|
||||
|
||||
setEvents(tempEvents);
|
||||
}, [successAuth, user.isVisitor, config?.documentType, fileInfo]);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (
|
||||
IS_DESKTOP_EDITOR ||
|
||||
(typeof window !== "undefined" &&
|
||||
window.DocSpaceConfig?.editor?.openOnNewPage === false)
|
||||
)
|
||||
return;
|
||||
|
||||
//FireFox security issue fix (onRequestCreateNew will be blocked)
|
||||
const documentType = config?.documentType || "word";
|
||||
const defaultFileName = getDefaultFileName();
|
||||
const url = new URL(
|
||||
combineUrl(
|
||||
window.location.origin,
|
||||
window.DocSpaceConfig?.proxy?.url,
|
||||
"/filehandler.ashx",
|
||||
),
|
||||
);
|
||||
url.searchParams.append("action", "create");
|
||||
url.searchParams.append("doctype", documentType);
|
||||
url.searchParams.append("title", defaultFileName ?? "");
|
||||
setCreateUrl(url.toString());
|
||||
}, [config?.documentType, getDefaultFileName]);
|
||||
|
||||
return {
|
||||
events,
|
||||
createUrl,
|
||||
documentReady,
|
||||
usersInRoom,
|
||||
|
||||
onDocumentReady,
|
||||
onSDKRequestOpen,
|
||||
onSDKRequestReferenceData,
|
||||
onSDKAppReady,
|
||||
onSDKRequestClose,
|
||||
onSDKRequestCreateNew,
|
||||
onSDKRequestHistory,
|
||||
onSDKRequestUsers,
|
||||
onSDKRequestSendNotify,
|
||||
onSDKRequestRestore,
|
||||
onSDKRequestHistoryData,
|
||||
onDocumentStateChange,
|
||||
onMetaChange,
|
||||
onMakeActionLink,
|
||||
|
||||
setDocTitle,
|
||||
};
|
||||
};
|
||||
|
||||
export default useEditorEvents;
|
85
packages/doceditor/src/hooks/useInit.ts
Normal file
85
packages/doceditor/src/hooks/useInit.ts
Normal file
@ -0,0 +1,85 @@
|
||||
import React from "react";
|
||||
import { isIOS, deviceType } from "react-device-detect";
|
||||
|
||||
import { FolderType } from "@docspace/shared/enums";
|
||||
|
||||
import { UseInitProps } from "@/types";
|
||||
import { initForm, setDocumentTitle, showDocEditorMessage } from "@/utils";
|
||||
import initDesktop from "@/utils/initDesktop";
|
||||
import { IS_DESKTOP_EDITOR, IS_VIEW } from "@/utils/constants";
|
||||
|
||||
const useInit = ({
|
||||
config,
|
||||
successAuth,
|
||||
fileInfo,
|
||||
user,
|
||||
t,
|
||||
setDocTitle,
|
||||
documentReady,
|
||||
}: UseInitProps) => {
|
||||
React.useEffect(() => {
|
||||
if (isIOS && deviceType === "tablet") {
|
||||
const vh = window.innerHeight * 0.01;
|
||||
document.documentElement.style.setProperty("--vh", `${vh}px`);
|
||||
}
|
||||
}, []);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (
|
||||
!IS_VIEW &&
|
||||
fileInfo &&
|
||||
fileInfo.viewAccessibility.WebRestrictedEditing &&
|
||||
fileInfo.security.FillForms &&
|
||||
fileInfo.rootFolderType === FolderType.Rooms &&
|
||||
!fileInfo.security.Edit &&
|
||||
!config.document.isLinkedForMe
|
||||
) {
|
||||
try {
|
||||
initForm(fileInfo.id);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
}
|
||||
}, [config.document.isLinkedForMe, fileInfo]);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!config) return;
|
||||
|
||||
setDocumentTitle(
|
||||
config.document.title,
|
||||
config.document.fileType,
|
||||
documentReady,
|
||||
successAuth,
|
||||
setDocTitle,
|
||||
);
|
||||
}, [config, documentReady, fileInfo, setDocTitle, successAuth]);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (config && IS_DESKTOP_EDITOR) {
|
||||
initDesktop(config, user, fileInfo.id, t);
|
||||
}
|
||||
}, [config, fileInfo.id, t, user]);
|
||||
|
||||
React.useEffect(() => {
|
||||
try {
|
||||
const url = window.location.href;
|
||||
|
||||
if (
|
||||
successAuth &&
|
||||
url.indexOf("#message/") > -1 &&
|
||||
fileInfo &&
|
||||
fileInfo?.fileExst &&
|
||||
fileInfo?.viewAccessibility?.MustConvert &&
|
||||
fileInfo?.security?.Convert
|
||||
) {
|
||||
showDocEditorMessage(url, fileInfo.id);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
}, [fileInfo, successAuth]);
|
||||
|
||||
return {};
|
||||
};
|
||||
|
||||
export default useInit;
|
@ -25,9 +25,10 @@ const useSelectFolderDialog = ({}: UseSelectFolderDialogProps) => {
|
||||
const onSDKRequestSaveAs = useCallback((event: object) => {
|
||||
if ("data" in event) {
|
||||
const data = event.data as TEventData;
|
||||
setTitle(data.title);
|
||||
setUrl(data.url);
|
||||
setExtension(data.fileType);
|
||||
|
||||
setTitle(data.title ?? "");
|
||||
setUrl(data.url ?? "");
|
||||
setExtension(data.fileType ?? "");
|
||||
|
||||
setIsVisible(true);
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ const useWhiteLabel = () => {
|
||||
requestRunning.current = true;
|
||||
const urls = await getLogoUrls();
|
||||
requestRunning.current = false;
|
||||
console.log("====", urls);
|
||||
|
||||
setLogoUrls(urls);
|
||||
alreadyFetched.current = true;
|
||||
}, []);
|
||||
|
12
packages/doceditor/src/utils/constants.ts
Normal file
12
packages/doceditor/src/utils/constants.ts
Normal file
@ -0,0 +1,12 @@
|
||||
export const IZ_ZOOM =
|
||||
typeof window !== "undefined" &&
|
||||
(window?.navigator?.userAgent?.includes("ZoomWebKit") ||
|
||||
window?.navigator?.userAgent?.includes("ZoomApps"));
|
||||
export const IS_DESKTOP_EDITOR =
|
||||
typeof window !== "undefined"
|
||||
? window["AscDesktopEditor"] !== undefined
|
||||
: false;
|
||||
export const IS_VIEW =
|
||||
typeof window !== "undefined"
|
||||
? window.location.search.indexOf("action=view") !== -1
|
||||
: false;
|
82
packages/doceditor/src/utils/events.ts
Normal file
82
packages/doceditor/src/utils/events.ts
Normal file
@ -0,0 +1,82 @@
|
||||
import { TFile } from "@docspace/shared/api/files/types";
|
||||
import { frameCallCommand } from "@docspace/shared/utils/common";
|
||||
|
||||
import { convertDocumentUrl } from ".";
|
||||
import { updateFile } from "@docspace/shared/api/files";
|
||||
|
||||
export type TInfoEvent = { data: { mode: string } };
|
||||
|
||||
export const onSDKInfo = (event: object) => {
|
||||
const data = (event as TInfoEvent).data;
|
||||
|
||||
console.log("ONLYOFFICE Document Editor is opened in mode " + data.mode);
|
||||
};
|
||||
|
||||
export type TWarningEvent = {
|
||||
data: { warningCode: string; warningDescription: string };
|
||||
};
|
||||
|
||||
export const onSDKWarning = (event: object) => {
|
||||
const data = (event as TWarningEvent).data;
|
||||
frameCallCommand("setIsLoaded");
|
||||
console.log(
|
||||
"ONLYOFFICE Document Editor reports a warning: code " +
|
||||
data.warningCode +
|
||||
", description " +
|
||||
data.warningDescription,
|
||||
);
|
||||
};
|
||||
|
||||
export type TErrorEvent = {
|
||||
data: { errorCode: string; errorDescription: string };
|
||||
};
|
||||
|
||||
export const onSDKError = (event: object) => {
|
||||
const data = (event as TErrorEvent).data;
|
||||
frameCallCommand("setIsLoaded");
|
||||
console.log(
|
||||
"ONLYOFFICE Document Editor reports an error: code " +
|
||||
data.errorCode +
|
||||
", description " +
|
||||
data.errorDescription,
|
||||
);
|
||||
};
|
||||
|
||||
export const onSDKRequestHistoryClose = () => {
|
||||
document.location.reload();
|
||||
};
|
||||
|
||||
export const onSDKRequestEditRights = async (fileInfo: TFile) => {
|
||||
console.log("ONLYOFFICE Document Editor requests editing rights");
|
||||
const url = window.location.href;
|
||||
|
||||
const index = url.indexOf("&action=view");
|
||||
|
||||
if (index) {
|
||||
let convertUrl = url.substring(0, index);
|
||||
|
||||
if (
|
||||
fileInfo?.viewAccessibility?.MustConvert &&
|
||||
fileInfo?.security?.Convert
|
||||
) {
|
||||
const newUrl = await convertDocumentUrl(fileInfo.id);
|
||||
if (newUrl) {
|
||||
convertUrl = newUrl.webUrl;
|
||||
}
|
||||
}
|
||||
history.pushState({}, "", convertUrl);
|
||||
document.location.reload();
|
||||
}
|
||||
};
|
||||
|
||||
export type TRenameEvent = {
|
||||
data: string;
|
||||
};
|
||||
|
||||
export const onSDKRequestRename = async (
|
||||
event: object,
|
||||
id: string | number,
|
||||
) => {
|
||||
const title = (event as TRenameEvent).data;
|
||||
await updateFile(id, title);
|
||||
};
|
@ -1,6 +1,61 @@
|
||||
import { toUrlParams } from "@docspace/shared/utils/common";
|
||||
import { combineUrl } from "@docspace/shared/utils/combineUrl";
|
||||
import { request } from "@docspace/shared/api/client";
|
||||
import { checkFillFormDraft, convertFile } from "@docspace/shared/api/files";
|
||||
import { TEditHistory } from "@docspace/shared/api/files/types";
|
||||
import { FolderType } from "@docspace/shared/enums";
|
||||
|
||||
export const getBackUrl = (
|
||||
rootFolderType: FolderType,
|
||||
folderId: string | number,
|
||||
) => {
|
||||
const search = window.location.search;
|
||||
const shareIndex = search.indexOf("share=");
|
||||
const key = shareIndex > -1 ? search.substring(shareIndex + 6) : null;
|
||||
|
||||
let backUrl = "";
|
||||
|
||||
if (rootFolderType === FolderType.Rooms) {
|
||||
if (key) {
|
||||
backUrl = `/rooms/share?key=${key}`;
|
||||
} else {
|
||||
backUrl = `/rooms/shared/${folderId}/filter?folder=${folderId}`;
|
||||
}
|
||||
} else {
|
||||
backUrl = `/rooms/personal/filter?folder=${folderId}`;
|
||||
}
|
||||
|
||||
const url = window.location.href;
|
||||
const origin = url.substring(0, url.indexOf("/doceditor"));
|
||||
|
||||
return `${combineUrl(origin, backUrl)}`;
|
||||
};
|
||||
|
||||
export const initForm = async (id: string | number) => {
|
||||
const formUrl = await checkFillFormDraft(id);
|
||||
history.pushState({}, "", formUrl);
|
||||
|
||||
document.location.reload();
|
||||
};
|
||||
|
||||
export const showDocEditorMessage = async (
|
||||
url: string,
|
||||
id: string | number,
|
||||
) => {
|
||||
const result = await convertDocumentUrl(id);
|
||||
const splitUrl = url.split("#message/");
|
||||
|
||||
if (result) {
|
||||
const newUrl = `${result.webUrl}#message/${splitUrl[1]}`;
|
||||
|
||||
history.pushState({}, "", newUrl);
|
||||
}
|
||||
};
|
||||
|
||||
export const convertDocumentUrl = async (fileId: number | string) => {
|
||||
const convert = await convertFile(fileId, null, true);
|
||||
return convert && convert[0]?.result;
|
||||
};
|
||||
|
||||
export const getDataSaveAs = async (params: string) => {
|
||||
try {
|
||||
@ -47,3 +102,76 @@ export const saveAs = (
|
||||
window.open(handlerUrl, "_blank");
|
||||
}
|
||||
};
|
||||
|
||||
export const constructTitle = (
|
||||
firstPart: string,
|
||||
secondPart: string,
|
||||
reverse = false,
|
||||
) => {
|
||||
return !reverse
|
||||
? `${firstPart} - ${secondPart}`
|
||||
: `${secondPart} - ${firstPart}`;
|
||||
};
|
||||
|
||||
export const checkIfFirstSymbolInStringIsRtl = (str: string | null) => {
|
||||
if (!str) return;
|
||||
|
||||
const rtlRegexp = new RegExp(
|
||||
/[\u04c7-\u0591\u05D0-\u05EA\u05F0-\u05F4\u0600-\u06FF]/,
|
||||
);
|
||||
|
||||
return rtlRegexp.test(str[0]);
|
||||
};
|
||||
|
||||
export const setDocumentTitle = (
|
||||
subTitle: string | null = null,
|
||||
fileType: string,
|
||||
documentReady: boolean,
|
||||
successAuth: boolean,
|
||||
callback?: (value: string) => void,
|
||||
) => {
|
||||
const organizationName = "ONLYOFFICE"; //TODO: Replace to API variant
|
||||
const moduleTitle = "Documents"; //TODO: Replace to API variant
|
||||
|
||||
let newSubTitle = subTitle;
|
||||
|
||||
const isSubTitleRtl = checkIfFirstSymbolInStringIsRtl(subTitle);
|
||||
|
||||
// needs to reverse filename and extension for rtl mode
|
||||
if (newSubTitle && fileType && isSubTitleRtl) {
|
||||
newSubTitle = `${fileType}.${newSubTitle.replace(`.${fileType}`, "")}`;
|
||||
}
|
||||
|
||||
let title;
|
||||
|
||||
if (newSubTitle) {
|
||||
if (successAuth && moduleTitle) {
|
||||
title = constructTitle(newSubTitle, moduleTitle, isSubTitleRtl);
|
||||
} else {
|
||||
title = constructTitle(newSubTitle, organizationName, isSubTitleRtl);
|
||||
}
|
||||
} else if (moduleTitle && organizationName) {
|
||||
title = constructTitle(moduleTitle, organizationName);
|
||||
} else {
|
||||
title = organizationName;
|
||||
}
|
||||
|
||||
if (documentReady) {
|
||||
callback?.(title);
|
||||
}
|
||||
document.title = title;
|
||||
};
|
||||
|
||||
export const getCurrentDocumentVersion = (
|
||||
fileHistory: TEditHistory[],
|
||||
historyLength: number,
|
||||
) => {
|
||||
return window.location.search.indexOf("&version=") !== -1
|
||||
? +window.location.search.split("&version=")[1]
|
||||
: fileHistory[historyLength - 1].version;
|
||||
};
|
||||
|
||||
export const getIsZoom = () =>
|
||||
typeof window !== "undefined" &&
|
||||
(window?.navigator?.userAgent?.includes("ZoomWebKit") ||
|
||||
window?.navigator?.userAgent?.includes("ZoomApps"));
|
||||
|
48
packages/doceditor/src/utils/initDesktop.ts
Normal file
48
packages/doceditor/src/utils/initDesktop.ts
Normal file
@ -0,0 +1,48 @@
|
||||
import { IInitialConfig } from "@/types";
|
||||
import {
|
||||
setEncryptionKeys,
|
||||
getEncryptionAccess,
|
||||
} from "@docspace/shared/api/files";
|
||||
import { TUser } from "@docspace/shared/api/people/types";
|
||||
import { toastr } from "@docspace/shared/components/toast";
|
||||
import { Nullable, TTranslation } from "@docspace/shared/types";
|
||||
import { regDesktop } from "@docspace/shared/utils/desktop";
|
||||
|
||||
const initDesktop = (
|
||||
cfg: IInitialConfig,
|
||||
user: TUser,
|
||||
fileId: string | number,
|
||||
t: Nullable<TTranslation>,
|
||||
) => {
|
||||
const encryptionKeys = cfg?.editorConfig?.encryptionKeys;
|
||||
regDesktop(
|
||||
user,
|
||||
!!encryptionKeys,
|
||||
encryptionKeys,
|
||||
(keys) => {
|
||||
setEncryptionKeys(keys);
|
||||
},
|
||||
true,
|
||||
(callback) => {
|
||||
getEncryptionAccess?.(fileId)
|
||||
?.then((keys) => {
|
||||
var data = {
|
||||
keys,
|
||||
};
|
||||
|
||||
callback?.(data);
|
||||
})
|
||||
.catch((error) => {
|
||||
toastr.error(
|
||||
typeof error === "string" ? error : error.message,
|
||||
"",
|
||||
0,
|
||||
true,
|
||||
);
|
||||
});
|
||||
},
|
||||
t,
|
||||
);
|
||||
};
|
||||
|
||||
export default initDesktop;
|
Loading…
Reference in New Issue
Block a user