PosterDialog prints by default instead of downloading, like PosterWall

The poster dialog had only a download path: its Render button saved a file, the
same trap PosterWall's old default was (gospel's Driver-lens audit, card 7).
A new action prop defaults to 'print': a PNG poster opens the print dialog in
place (printImageBlob, sized to the chosen page), a PDF opens in the browser's
viewer, and a blocked print frame or popup falls back to the file. 'download'
stays an explicit opt-in.
This commit is contained in:
Doxa Maps 2026-09-28 04:46:06 +00:00
parent 47cfc6ed34
commit cc6e7cb6c4

View file

@ -119,6 +119,7 @@ import { defaultPosterSpec, posterDefaults } from '../../constants/posterDefault
// shell (contain:layout on .vtl-content). See library/utils/viewportScrim.js.
import { useViewportScrim } from '../../utils/viewportScrim.js';
import { tStatic } from '../../i18n/index.js';
import { printImageBlob } from '../../composables/printInPlace.js';
// This dialog's chrome, read out of the catalogue. tStatic and not useI18n: these components mount
// inside custom elements that install no i18n plugin, and an unguarded useI18n() throws on the way
@ -127,6 +128,13 @@ import { tStatic } from '../../i18n/index.js';
const T = (key, en) => tStatic(key) || en;
const props = defineProps({
/**
* What the Render button does. 'print' (default, Driver rule 2026-09-28: an export-poster button opens
* the PRINT DIALOG with a preview, never a direct download) prints the rendered poster in place; a PDF
* opens in the browser's viewer, where it can be printed or saved. 'download' saves the file, and a
* consumer that opts in must say why in a `posterAction-download:` comment (check:poster-action-print).
*/
action: { type: String, default: 'print' }, // 'print' | 'download'
/** Boolean v-model: dialog visibility. */
modelValue: { type: Boolean, default: false },
/** Function returning the live Mapbox map instance. */
@ -202,7 +210,17 @@ async function onRender() {
const blob = await poster.render(spec.value, format.value);
const ext = (format.value === 'pdf') ? 'pdf' : 'png';
const name = (titleText.value || 'poster').replace(/\W+/g, '-').toLowerCase();
_download(blob, `${name}.${ext}`);
if (props.action === 'download') _download(blob, `${name}.${ext}`);
else if (ext === 'png') {
const s = getPosterSize(sizeId.value);
const opened = printImageBlob(blob, { widthIn: s?.inches?.w || 8.5, heightIn: s?.inches?.h || 11, title: titleText.value || 'poster', alt: titleText.value || '' });
if (!opened) _download(blob, `${name}.${ext}`); // the host blocked the print frame: a file beats nothing
} else {
const url = URL.createObjectURL(blob);
const w = window.open(url, '_blank', 'noopener');
if (!w) _download(blob, `${name}.${ext}`);
setTimeout(() => URL.revokeObjectURL(url), 60000);
}
emit('rendered', { blob, format: format.value, spec: spec.value });
} catch (err) {
// eslint-disable-next-line no-console