พอร์ต taskpane ของ Word add-in "e-Court Documents Versioning" จาก D:\word-addin-poc มาเป็น sibling app ที่ route /docedit/wordaddin: - wordaddin/ (client-only zone): services พอร์ตดิบทั้งชุด (authService/versioningService เป็น mock รอ backend จริง) + models + config - components/wordaddin/: WordAddinGate ฉีด office.js self-host (singleton กัน StrictMode double-inject + fallback timer ครอบเคส onReady เงียบ) และ TaskpaneApp state machine แปลง JSX เป็น Genesis design system - scripts/fetch-office-js.mjs (postinstall ตัวที่สาม): ดาวน์โหลด Office.js runtime ล่าสุดจาก CDN Microsoft ไป public/wordaddin/office-js/ (gitignore สร้างใหม่ได้ — npm @microsoft/office-js ตกรุ่นไม่มี Document.close) - middleware/basePath/root page: เปิด /wordaddin เป็น public (auth แยกจาก แอป note), root /docedit redirect ไป taskpane ยกเว้นลิงก์ e-Court N8 (?fileUrl=&fileId=&typeId=) ที่ยังส่งต่อ /note ตามเดิม - docker/web.Dockerfile รัน fetch-office-js ตอน build + npm scripts dev:https สำหรับ sideload ตาม docs/WORDADDIN-DEV.md Co-Authored-By: Claude Code <noreply@anthropic.com>
86 lines
5.3 KiB
TypeScript
86 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() จบ)
|
|
});
|
|
}
|