Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 36 additions & 22 deletions src/components/onlyoffice-web-comp/core/onlyoffice-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,11 @@ import {
type OnlyOfficeStaticResourceOptions,
} from "../const";
import type { OfficeTheme } from "../internal/editor/types";
import { getDocmentObj, setDocmentObj } from "../store/document";
import {
clearDocmentObj,
getDocmentObj,
setDocmentObj,
} from "../store/document";
import {
getCurrentLang,
getOnlyOfficeLang,
Expand Down Expand Up @@ -63,6 +67,14 @@ export type OpenDocumentInput = {
officeXmlEvent?: OfficeXmlEventConfig;
};

export type OnlyOfficeExportBlobResult = {
blob: Blob;
fileName: string;
/** true 表示未经过编辑器导出转换,而是返回当前打开的原始文件。 */
isOriginalFileFallback?: boolean;
fallbackReason?: "officeXmlSizeLimitExceeded";
};

export class OnlyOfficeManager {
readonly containerId: string;
readonly fileType: FileType;
Expand All @@ -71,8 +83,6 @@ export class OnlyOfficeManager {
private readOnly: boolean;
private theme: OfficeTheme;
private officeXmlEvent?: OfficeXmlEventConfig;
private sourceFile: File | null = null;
private sourceFileName = "";
private ready = false;

private constructor(
Expand Down Expand Up @@ -157,16 +167,17 @@ export class OnlyOfficeManager {
/** 打开/切换文档(上传、新建、重开) */
async openDocument(input: OpenDocumentInput) {
const readOnly = input.readOnly ?? this.readOnly;
this.sourceFile = input.file ?? null;
this.sourceFileName = input.fileName;

setDocmentObj({
fileName: input.fileName,
file: input.file,
isNew: input.isNew ?? !input.file,
});
setDocmentObj(
{
fileName: input.fileName,
file: input.file,
isNew: input.isNew ?? !input.file,
},
this.containerId,
);

const { fileName, file } = getDocmentObj();
const { fileName, file } = getDocmentObj(this.containerId);

await this.editor.create({
file,
Expand Down Expand Up @@ -270,7 +281,19 @@ export class OnlyOfficeManager {
}

/** 导出为 Office 文件 Blob:Editor.bin → x2t → doc.{fileType}。 */
async exportAsBlob() {
async exportAsBlob(): Promise<OnlyOfficeExportBlobResult> {
if (this.editor.isOfficeXmlSizeLimitExceeded()) {
const { file, fileName } = getDocmentObj(this.containerId);
if (file) {
return {
blob: file,
fileName: fileName || file.name,
isOriginalFileFallback: true,
fallbackReason: "officeXmlSizeLimitExceeded",
};
}
}

const binData = await this.editor.export();
const exportFileType = binData.fileType || this.fileType.toLowerCase();
const result = await convertBinToDocument(
Expand All @@ -291,16 +314,6 @@ export class OnlyOfficeManager {

/** 触发浏览器下载;内部先走 exportAsBlob 完整链路。 */
async downloadExport() {
if (this.editor.isOfficeXmlSizeLimitExceeded()) {
if (this.sourceFile) {
downloadBlob(
this.sourceFile,
this.sourceFileName || this.sourceFile.name,
);
return;
}
}

const { blob, fileName } = await this.exportAsBlob();
downloadBlob(blob, fileName);
}
Expand Down Expand Up @@ -329,6 +342,7 @@ export class OnlyOfficeManager {

destroy() {
this.editor.destroy();
clearDocmentObj(this.containerId);
this.ready = false;
}
}
Expand Down
120 changes: 85 additions & 35 deletions src/components/onlyoffice-web-comp/store/document.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,47 +17,84 @@ export type SetOnlyOfficeDocumentStateInput = Omit<
fileName: string;
};

let documentState: OnlyOfficeDocumentState = {
isNew: true,
fileName: "New Document.docx",
fileType: "docx",
};
const DEFAULT_DOCUMENT_SCOPE = "__default__";

function createDefaultDocumentState(): OnlyOfficeDocumentState {
return {
isNew: true,
fileName: "New Document.docx",
fileType: "docx",
};
}

export function setDocmentObj(state: SetOnlyOfficeDocumentStateInput) {
documentState = {
function normalizeDocumentState(
state: SetOnlyOfficeDocumentStateInput,
): OnlyOfficeDocumentState {
return {
...state,
isNew: state.isNew ?? !state.file,
fileType: state.fileType || getFileExt(state.fileName) || "docx",
};
}

export function getDocmentObj() {
return documentState;
const documentStates = new Map<string, OnlyOfficeDocumentState>();

documentStates.set(DEFAULT_DOCUMENT_SCOPE, createDefaultDocumentState());

function getScopeId(scopeId?: string) {
return scopeId || DEFAULT_DOCUMENT_SCOPE;
}

export function clearDocmentObj() {
documentState = {
isNew: true,
fileName: "New Document.docx",
fileType: "docx",
};
export function setDocmentObj(
state: SetOnlyOfficeDocumentStateInput,
scopeId?: string,
) {
documentStates.set(getScopeId(scopeId), normalizeDocumentState(state));
}

export function setNewDocument(fileType = "docx") {
setDocmentObj({
isNew: true,
fileName: `New Document.${fileType}`,
fileType,
});
export function getDocmentObj(scopeId?: string) {
const key = getScopeId(scopeId);
let state = documentStates.get(key);
if (!state) {
state = createDefaultDocumentState();
documentStates.set(key, state);
}
return state;
}
export function clearDocmentObj(scopeId?: string) {
if (scopeId) {
documentStates.delete(scopeId);
return;
}

export function setDocumentFile(file: File, fileName = file.name) {
setDocmentObj({
isNew: false,
file,
fileName,
fileType: getFileExt(fileName) || getFileExt(file.name) || "docx",
});
documentStates.set(DEFAULT_DOCUMENT_SCOPE, createDefaultDocumentState());
}

export function setNewDocument(fileType = "docx", scopeId?: string) {
setDocmentObj(
{
isNew: true,
fileName: `New Document.${fileType}`,
fileType,
},
scopeId,
);
}

export function setDocumentFile(
file: File,
fileName = file.name,
scopeId?: string,
) {
setDocmentObj(
{
isNew: false,
file,
fileName,
fileType: getFileExt(fileName) || getFileExt(file.name) || "docx",
},
scopeId,
);
}

export function setDocumentUrl(
Expand All @@ -71,14 +108,27 @@ export function setDocumentUrl(
fileName?: string;
loader?: (url: string) => Promise<ArrayBuffer>;
} = {},
scopeId?: string,
) {
const name = fileName || decodeURIComponent(url.split("/").pop() || "Document");

setDocmentObj({
isNew: false,
url,
loader,
fileName: name,
fileType: fileType || getFileExt(name) || "docx",
});
setDocmentObj(
{
isNew: false,
url,
loader,
fileName: name,
fileType: fileType || getFileExt(name) || "docx",
},
scopeId,
);
}

export function clearAllDocmentObjs() {
documentStates.clear();
documentStates.set(DEFAULT_DOCUMENT_SCOPE, createDefaultDocumentState());
}

export function getAllDocmentObjs() {
return new Map(documentStates);
}
Loading