2026-09-08 14:01:13 +07:00
import { onBeforeUnmount , ref } from 'vue'
import { versionDownloadPath , wordOpenUrl , type VersionFormat } from '../utils/versionDownload'
/** Shared by history and generate success. Links stay available even if the focus heuristic fires. */
export function useVersionOpen() {
const { apiJson } = useApi ( )
const openingVersionId = ref < string | null > ( null )
const downloadError = ref < string | null > ( null )
const fallbackUrl = ref < string | null > ( null )
const openNotice = ref < string | null > ( null )
let cleanup = ( ) = > { }
let generation = 0
let pendingTab : Window | null = null
2026-09-10 12:22:19 +07:00
/ * *
* ร อ ส ั ง เ ก ต ก า ร ส ล ั บ ไ ป Word ( blur / visibilitychange ) ก ี ่ ม ิ ล ล ิ ว ิ น า ท ี ก ่ อ น ส ร ุ ป ว ่ า เ ป ิ ด ไ ม ่ ส ำ เ ร ็ จ —
* ย า ว พ อ ใ ห ้ Word cold - start โ อ ก า ส เ ป ิ ด ไ ด ้ ท ั น แ ต ่ ไ ม ่ น า น จ น ผ ู ้ ใ ช ้ ง ง ( ms - word :ofe บ น macOS ต อ น Word
* ย ั ง ไ ม ่ เ ป ิ ด ค ้ า ง อ ย ู ่ ม ั ก ท ำ URL event ห ล ุ ด → เ ห ็ น ห น ้ า Recent แ ท น เ อ ก ส า ร — ข ้ อ จ ำ ก ั ด ข อ ง platform )
* /
const WORD_SWITCH_WAIT_MS = 3000
2026-09-08 14:01:13 +07:00
function resetOpen() {
generation ++
pendingTab ? . close ( )
pendingTab = null
cleanup ( )
openingVersionId . value = null
downloadError . value = null
fallbackUrl . value = null
openNotice . value = null
}
2026-09-10 12:22:19 +07:00
/ * * ใ ห ้ เ บ ร า ว ์ เ ซ อ ร ์ เ ซ ฟ U R L ล ง D o w n l o a d s ( p r e s i g n e d U R L ส ่ ง d i s p o s i t i o n : a t t a c h m e n t อ ย ู ่ แ ล ้ ว —
* ห น ้ า เ ว ็ บ อ ย ู ่ ท ี ่ เ ด ิ ม ไ ม ่ navigate ไ ป ไ ห น ) * /
function saveToDownloads ( url : string ) {
const a = document . createElement ( 'a' )
a . href = url
document . body . append ( a )
a . click ( )
a . remove ( )
}
/ * * เ ป ิ ด p r e s i g n e d d o c x U R L ใ น W o r d ผ ่ า น m s - w o r d : o f e — ถ ้ า ไ ม ่ เ ห ็ น ก า ร ส ล ั บ แ อ ป ภ า ย ใ น W O R D _ S W I T C H _ W A I T _ M S
* ถือว่าเปิดไม่สำเร็จ : ดาวน์โหลดไฟล์ให้อัตโนมัติ + แ จ ้ ง ผ ู ้ ใ ช ้ ( ก ด ซ ้ ำ ต อ น Word เ ป ิ ด อ ย ู ่ แ ล ้ ว จ ะ ส ำ เ ร ็ จ )
2026-09-10 11:49:16 +07:00
* ใ ช ้ ก ั บ ล ิ ง ก ์ ท ี ่ ถ ื อ อ ย ู ่ เ อ ง ไ ด ้ เ ล ย ( ไ ฟ ล ์ ร ่ า ง FR - 16 : response ข อ ง generate - draft ค ื อ URL แ ล ้ ว ) * /
function openDocxUrl ( url : string ) {
resetOpen ( )
fallbackUrl . value = url
let switched = false
const onBlur = ( ) = > { switched = true }
const onVisibility = ( ) = > { if ( document . hidden ) switched = true }
window . addEventListener ( 'blur' , onBlur )
document . addEventListener ( 'visibilitychange' , onVisibility )
const timer = window . setTimeout ( ( ) = > {
2026-09-10 12:22:19 +07:00
if ( ! switched ) {
openNotice . value =
'Word ไม่ได้เปิดเอกสารอัตโนมัติ (มักเกิดตอน Word เพิ่งถูกเปิดขึ้นครั้งแรก) — ดาวน์โหลดไฟล์ให้แล้วที่โฟลเดอร์ Downloads ให้เปิดจากที่นั่น หรือกดเปิดใน Word อีกครั้งเมื่อ Word เปิดอยู่แล้ว'
saveToDownloads ( url )
}
2026-09-10 11:49:16 +07:00
cleanup ( )
2026-09-10 12:22:19 +07:00
} , WORD_SWITCH_WAIT_MS )
2026-09-10 11:49:16 +07:00
cleanup = ( ) = > {
window . clearTimeout ( timer )
window . removeEventListener ( 'blur' , onBlur )
window . removeEventListener ( 'visibilitychange' , onVisibility )
}
window . location . assign ( wordOpenUrl ( url ) )
}
2026-09-08 14:01:13 +07:00
async function openVersion ( documentId : string , versionId : string , format : VersionFormat = 'docx' ) {
if ( openingVersionId . value ) return
resetOpen ( )
const current = generation
openingVersionId . value = versionId
// Reserve a tab during the user gesture, before the authenticated request loses activation.
let tab : Window | null = null
try {
tab = format === 'pdf' ? window . open ( 'about:blank' , '_blank' ) : null
if ( tab ) tab . opener = null
pendingTab = tab
const link = await apiJson < { url : string ; expiresAt : string } > ( versionDownloadPath ( documentId , versionId , format ) )
if ( current !== generation ) { tab ? . close ( ) ; return }
if ( ! link ) throw new Error ( 'ขอลิงก์เปิดไฟล์ไม่สำเร็จ' )
fallbackUrl . value = link . url
if ( format === 'pdf' ) {
if ( tab && ! tab . closed ) {
tab . location . replace ( link . url )
pendingTab = null
}
else openNotice . value = 'เบราว์เซอร์บล็อกแท็บใหม่ กรุณากดลิงก์เปิดไฟล์ด้านล่าง'
} else {
2026-09-10 11:49:16 +07:00
openDocxUrl ( link . url )
2026-09-08 14:01:13 +07:00
}
} catch ( err ) {
tab ? . close ( )
if ( pendingTab === tab ) pendingTab = null
if ( current === generation ) downloadError . value = err instanceof Error ? err . message : 'เปิดไฟล์ไม่สำเร็จ'
} finally {
if ( current === generation ) openingVersionId . value = null
}
}
onBeforeUnmount ( resetOpen )
2026-09-10 11:49:16 +07:00
return { openingVersionId , downloadError , fallbackUrl , openNotice , openVersion , openDocxUrl , resetOpen }
2026-09-08 14:01:13 +07:00
}