add-in: auto-open taskpane phase 1 + final save after versioning + tracking id = fid
- manifest: TaskpaneId -> Office.AutoShowTaskpaneWithDocument (auto-open marker), bump 1.0.0.4 - metadataService.enableAutoOpenTaskpane: tag doc setting (idempotent, best-effort) called from detect() after sign-in - versionFlow: final saveDocumentVerified at end of both versioning flows (bug: stamped docx never persisted -> reopen showed untracked) - tracking id now uses ticket fid (TRACKING_ID_SOURCE="fid", rollback by switching to "guid"), resolveTrackingId + authService.getCurrentFid - WordAddinGate: restore history.pushState/replaceState that office.js nullifies in taskpane (fixes Next App Router crash) Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
parent
02894f2705
commit
9fecaa7bca
8 changed files with 256 additions and 6 deletions
|
|
@ -212,6 +212,10 @@ const TaskpaneApp: React.FC<{ demo?: "untracked" | "tracking" }> = ({ demo }) =>
|
|||
}
|
||||
setUsername(authService.getUsername() ?? null);
|
||||
|
||||
// auto-open (2026-11-05) — sign-in ผ่าน = ไฟล์ e-Court: tag ให้ taskpane เด้งเองครั้งถัดไป
|
||||
// ที่เปิดไฟล์นี้ · fire-and-forget (service กลืน error ทั้งหมด — ไฟล์ทั่วไปไม่มาทางนี้อยู่แล้ว)
|
||||
void metadataService.enableAutoOpenTaskpane();
|
||||
|
||||
const tracked = properties.savedByAddIn === metadataService.ADDIN_SIGNATURE_GUID;
|
||||
const id = tracked ? properties.documentTrackingId : undefined;
|
||||
if (!id) {
|
||||
|
|
|
|||
|
|
@ -31,6 +31,33 @@ const ONREADY_FALLBACK_MS = 5_000;
|
|||
/** เพดานรวมหลัง inject script — ครบแล้วยังไม่มี Office = ไปหน้า error (มีปุ่มลองใหม่) */
|
||||
const ONREADY_HARD_CAP_MS = 60_000;
|
||||
|
||||
/**
|
||||
* office.js **ลบ `history.pushState`/`replaceState` ทิ้ง** ใน taskpane (set เป็น null —
|
||||
* กัน add-in พา host ไปที่อื่น: office-js#429) แต่ App Router ของ Next ต้องใช้ History API
|
||||
* ตอน mount ไม่งั้นพัง "window.history.replaceState is not a function" — เก็บตัวจริงไว้
|
||||
* ก่อนฉีด script แล้วคืนคืนหลัง office.js โหลด/พร้อม (workaround มาตรฐานของ SPA ใน
|
||||
* add-in — taskpane เป็น iframe ของตัวเอง Next ใช้ history เฉพาะ SPA state ภายใน)
|
||||
*/
|
||||
const nativeHistory: { pushState?: History["pushState"]; replaceState?: History["replaceState"] } =
|
||||
typeof window === "undefined"
|
||||
? {}
|
||||
: {
|
||||
pushState: typeof window.history.pushState === "function" ? window.history.pushState.bind(window.history) : undefined,
|
||||
replaceState:
|
||||
typeof window.history.replaceState === "function" ? window.history.replaceState.bind(window.history) : undefined,
|
||||
};
|
||||
|
||||
/** คืน History API ที่ office.js ลบทิ้ง — idempotent (มีอยู่แล้ว = ไม่แตะ) */
|
||||
function restoreHistoryApi(): void {
|
||||
if (typeof window === "undefined") return;
|
||||
if (typeof window.history.pushState !== "function" && nativeHistory.pushState) {
|
||||
window.history.pushState = nativeHistory.pushState;
|
||||
}
|
||||
if (typeof window.history.replaceState !== "function" && nativeHistory.replaceState) {
|
||||
window.history.replaceState = nativeHistory.replaceState;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* โหลด office.js ครั้งเดียวต่อ page เป็น singleton promise ระดับ module —
|
||||
* ห้ามฉีด <script> ซ้ำ: React StrictMode รัน effect สองรอบใน dev และ guard
|
||||
|
|
@ -45,7 +72,11 @@ function ensureOfficeJs(): Promise<boolean> {
|
|||
if (!officeReadyPromise) {
|
||||
officeReadyPromise = new Promise<boolean>((resolve) => {
|
||||
if (typeof Office !== "undefined") {
|
||||
void Office.onReady(() => resolve(true));
|
||||
restoreHistoryApi(); // office.js evaluate ไปแล้ว — คืนก่อนให้ router ใช้ต่อได้
|
||||
void Office.onReady(() => {
|
||||
restoreHistoryApi(); // host handshake อาจลบซ้ำตอน initialize
|
||||
resolve(true);
|
||||
});
|
||||
return;
|
||||
}
|
||||
const script = document.createElement("script");
|
||||
|
|
@ -56,6 +87,7 @@ function ensureOfficeJs(): Promise<boolean> {
|
|||
// Office โผล่แล้ว (script evaluate แล้ว) = proceed ได้เลย ไม่รอ onReady —
|
||||
// กัน webview ที่โหลดสำเร็จแต่ callback เงียบ (เจตนาเดิมของ fallback)
|
||||
if (typeof Office !== "undefined") {
|
||||
restoreHistoryApi(); // office.js evaluate แล้วอาจลบ history ทิ้ง — คืนก่อน proceed
|
||||
resolve(true);
|
||||
return;
|
||||
}
|
||||
|
|
@ -74,8 +106,10 @@ function ensureOfficeJs(): Promise<boolean> {
|
|||
const onReady = () => {
|
||||
// เคลียร์ timer เฉพาะเมื่อ callback ของ Office.onReady ยิงจริง — ถ้าเคลียร์ตั้งแต่ onload
|
||||
// แล้ว onReady เงียบ fallback จะตายไปก่อนทำหน้าที่ (ค้าง loading ตลอดไป)
|
||||
restoreHistoryApi(); // script evaluate แล้ว — office.js ลบ history ตรงนี้ คืนก่อน router ใช้
|
||||
void Office.onReady(() => {
|
||||
clearTimeout(fallbackTimer);
|
||||
restoreHistoryApi(); // handshake ของ host อาจลบซ้ำ — คืนอีกรอบก่อน mount TaskpaneApp
|
||||
resolve(true);
|
||||
});
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue