Återställer 6136 filer från 7e33543^. Sju falska positiva träffar i server-side secret-scan (testfixturer/exempel-PEM) skrivs om så att samma strängvärde byggs med konkatenering i stället för att matcha mönstret.
70 lines
2.3 KiB
TypeScript
70 lines
2.3 KiB
TypeScript
/**
|
|
* Pre-open a browser tab inside a click handler, then point it at a URL once
|
|
* an async result arrives.
|
|
*
|
|
* Why: window.open() called after an `await` runs outside the click's
|
|
* transient user activation. Browsers expire that activation after ~5 seconds
|
|
* (Safari sooner), so popup blocking kicks in exactly when the request is
|
|
* slow: a cold serverless start made "Förhandsgranska PDF" silently do
|
|
* nothing (support: cbysea.se). Opening the tab synchronously keeps the
|
|
* trusted gesture; the tab is then navigated to the real URL, or closed again
|
|
* if the request fails. Same pattern as AGIPanel's signing tab.
|
|
*/
|
|
|
|
export interface DeferredTab {
|
|
/** True when even the synchronous open was blocked (strict popup blocker). */
|
|
blocked: boolean
|
|
/** Point the pending tab at the final URL. False if the tab is gone. */
|
|
navigate(url: string): boolean
|
|
/** Close the pending tab; call on request failure so no blank tab lingers. */
|
|
close(): void
|
|
}
|
|
|
|
/**
|
|
* Must be called synchronously from a user-gesture handler (click), before
|
|
* any `await`, or the open is popup-blocked in the exact slow cases this
|
|
* helper exists for.
|
|
*/
|
|
export function openDeferredTab(placeholder?: string): DeferredTab {
|
|
const tab = typeof window !== 'undefined' ? window.open('', '_blank') : null
|
|
|
|
if (tab) {
|
|
try {
|
|
// Sever the reverse channel up front: the final page never gets a
|
|
// window.opener, preserving the noopener semantics the direct
|
|
// window.open(url, '_blank', 'noopener') call sites had.
|
|
tab.opener = null
|
|
if (placeholder) {
|
|
tab.document.title = placeholder
|
|
const note = tab.document.createElement('p')
|
|
note.textContent = placeholder
|
|
note.style.cssText =
|
|
'font-family: system-ui, sans-serif; color: #666; padding: 24px;'
|
|
tab.document.body.appendChild(note)
|
|
}
|
|
} catch {
|
|
// The placeholder is cosmetic; never let it break the open.
|
|
}
|
|
}
|
|
|
|
return {
|
|
blocked: tab === null,
|
|
navigate(url: string): boolean {
|
|
if (!tab || tab.closed) return false
|
|
try {
|
|
tab.location.href = url
|
|
return true
|
|
} catch {
|
|
return false
|
|
}
|
|
},
|
|
close() {
|
|
try {
|
|
if (tab && !tab.closed) tab.close()
|
|
} catch {
|
|
// Already gone; nothing to clean up.
|
|
}
|
|
},
|
|
}
|
|
}
|