87 lines
5.3 KiB
TypeScript
87 lines
5.3 KiB
TypeScript
|
|
/* global Word, Office */
|
||
|
|
|
||
|
|
/**
|
||
|
|
* FR-17 / FR-18 — จุดเดียวที่คุยกับ document-level API ของ Word
|
||
|
|
* (native save / อ่าน dirty / ปิดเอกสาร) แยกจาก versionFlow เพื่อให้
|
||
|
|
* autoSaveService กับปุ่ม [บันทึก] ใช้ร่วมได้โดยไม่ต้องพ่วง flow versioning
|
||
|
|
* พอร์ตดิบจาก D:\word-addin-poc\addin\src\services\documentService.ts
|
||
|
|
*/
|
||
|
|
|
||
|
|
export enum DocumentCloseMode {
|
||
|
|
/** บันทึกการแก้ไขก่อนปิด */
|
||
|
|
Save = "Save",
|
||
|
|
/** ปิดโดยไม่บันทึก — ไว้ใช้ระดับ service เท่านั้น (UI ปัจจุบันไม่มีปุ่มไหนใช้) */
|
||
|
|
SkipSave = "SkipSave",
|
||
|
|
}
|
||
|
|
|
||
|
|
/** native save ตาม FR-2 ขั้นตอนที่ 4 — ใช้ร่วมทั้ง versionFlow และ autoSaveService
|
||
|
|
* เรียกแบบไม่ส่ง saveBehavior: ปลอดภัยทุกรุ่น runtime — รุ่นเก่า (npm 1.1.110) ไม่มี
|
||
|
|
* enum Word.SaveBehavior และรับ save() แบบไม่มี argument, รุ่นใหม่ param เป็น optional
|
||
|
|
* ที่ default เดียวกัน (behavior = save เงียบ ๆ) */
|
||
|
|
export async function saveDocument(): Promise<void> {
|
||
|
|
await Word.run(async (context) => {
|
||
|
|
context.document.save();
|
||
|
|
await context.sync();
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
/** FR-3 — มีการแก้ไขที่ยังไม่ถูกบันทึกลงไฟล์ local หรือไม่ */
|
||
|
|
export async function isDocumentDirty(): Promise<boolean> {
|
||
|
|
return Word.run(async (context) => {
|
||
|
|
context.document.load("saved");
|
||
|
|
await context.sync();
|
||
|
|
return !context.document.saved;
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
/** save แล้วเช็คว่า Word เห็นไฟล์สะอาดจริง — บางสถานะ (เช่น หลังเขียน custom properties /
|
||
|
|
* custom XML part ของ flow versioning) Word ยังรายงาน saved=false แม้ save ผ่านแล้ว
|
||
|
|
* จึง save ซ้ำแบบมีขอบเขต (รวมสูงสุด 3 รอบ) — ไม่งั้น periodic tick ของ auto-save
|
||
|
|
* เห็น dirty ตอนไม่มีใครแก้อะไร แล้ว banner FR-3 ("มีการแก้ไขที่ยังไม่เป็น version")
|
||
|
|
* โผล่ผิด ๆ หลังจบ flow */
|
||
|
|
export async function saveDocumentVerified(): Promise<void> {
|
||
|
|
await saveDocument();
|
||
|
|
for (let attempt = 0; attempt < 2; attempt += 1) {
|
||
|
|
if (!(await isDocumentDirty())) return;
|
||
|
|
await saveDocument();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* FR-18 — `document.close()` ต้องการ WordApi 1.5 **และใช้ไม่ได้บน Word on the web**
|
||
|
|
* (requirement-set table ระบุรองรับ แต่หน้าเอกสารของ method เขียนไว้ว่า "isn't
|
||
|
|
* supported in Word on the web") จึงต้องเช็ค platform คู่กันเสมอ —
|
||
|
|
* UI ใช้ซ่อนปุ่ม close ทุกแบบ, service ใช้ guard ก่อนเรียกจริง
|
||
|
|
* (เรียกนอก Word — เช่น SSR หรือ browser ธรรมดา — throw ถูก catch คืน false เสมอ)
|
||
|
|
*/
|
||
|
|
export function canCloseDocument(): boolean {
|
||
|
|
try {
|
||
|
|
return (
|
||
|
|
Office.context.requirements.isSetSupported("WordApi", "1.5") &&
|
||
|
|
Office.context.platform !== Office.PlatformType.OfficeOnline
|
||
|
|
);
|
||
|
|
} catch {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/** FR-18 — ปิดเอกสารปัจจุบัน (task pane จะปิดตามเอกสาร) */
|
||
|
|
export async function closeDocument(mode: DocumentCloseMode = DocumentCloseMode.Save): Promise<void> {
|
||
|
|
if (!canCloseDocument()) {
|
||
|
|
throw new Error(
|
||
|
|
"เวอร์ชัน Word นี้ไม่รองรับการปิดเอกสารจาก add-in (รองรับเฉพาะ Word Desktop ที่ใช้ WordApi 1.5 ได้)"
|
||
|
|
);
|
||
|
|
}
|
||
|
|
await Word.run(async (context) => {
|
||
|
|
// ส่งค่า underlying ของ enum เป็น string ตรง ๆ ไม่อ่าน Word.CloseBehavior.* —
|
||
|
|
// runtime self-host อาจเป็นรุ่นเก่ากว่า @types (กรณี npm 1.1.110 เดิม: ไม่มี enum นี้เลย
|
||
|
|
// อ่านแล้ว TypeError "reading 'save'"; ปัจจุบัน fetch ฉบับ CDN ล่าสุดมี enum แล้วแต่ค่า
|
||
|
|
// string ทำงานเหมือนกันทุกรุ่น — cast กัน @types ที่พิมพ์ parameter เป็น enum object)
|
||
|
|
context.document.close(
|
||
|
|
(mode === DocumentCloseMode.Save ? "Save" : "SkipSave") as Word.CloseBehavior
|
||
|
|
);
|
||
|
|
// ห้ามเรียก context.sync() หลัง close() — เอกสารปิดกลาง batch ทำให้ sync ถูก abort
|
||
|
|
// (ตัวอย่างทางการของ Word เรียก close เฉยๆ แล้วพึ่ง implicit sync ตอน run() จบ)
|
||
|
|
});
|
||
|
|
}
|