eCourt-note/wordaddin/services/documentService.ts

87 lines
5.3 KiB
TypeScript
Raw Normal View History

2026-10-16 12:07:25 +07:00
/* 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() จบ)
});
}