openpencil/src/app/document/io/browser.ts
2026-09-05 11:25:33 +03:00

65 lines
1.9 KiB
TypeScript

import type { ViewportSize } from '@/app/document/io/types'
export function resolveBrowserFileURL(path: string): URL {
const url = new URL(path, window.location.href)
url.hash = ''
return url
}
export function yieldToUI(): Promise<void> {
return new Promise((resolve) => {
requestAnimationFrame(() => resolve())
})
}
type ViewportEditor = {
zoomToFit: () => void
}
export function createDocumentViewportActions(editor: ViewportEditor, viewportSize: ViewportSize) {
function setViewportSize(width: number, height: number) {
viewportSize.width = width
viewportSize.height = height
}
async function fitCurrentPageToViewport() {
await yieldToUI()
editor.zoomToFit()
}
return { setViewportSize, fitCurrentPageToViewport }
}
// The File System Access pickers (showSaveFilePicker/showOpenFilePicker) and
// window.prompt are blocked by browsers inside cross-origin sub-frames
// (Chrome: "Cross origin sub frames aren't allowed to show a file picker").
// Detect that context so callers can fall back to a plain download / file
// input instead of surfacing the picker error.
export function isCrossOriginSubFrame(): boolean {
const top = window.top
if (!top || top === window) return false
try {
// Same-origin sub-frame: the top window is reachable and pickers are allowed.
void top.location.href
return false
} catch {
// Cross-origin sub-frame: top navigation is blocked, pickers are not allowed.
return true
}
}
export function downloadBlob(data: Uint8Array, filename: string, mime: string) {
const blob = new Blob([data.buffer as ArrayBuffer], { type: mime })
const url = URL.createObjectURL(blob)
const a = document.createElement('a')
a.href = url
a.download = filename
a.style.display = 'none'
document.body.appendChild(a)
a.click()
setTimeout(() => {
document.body.removeChild(a)
URL.revokeObjectURL(url)
}, 100)
}