diff --git a/mindspace-long-image.mjs b/mindspace-long-image.mjs index 61d4623..f887764 100644 --- a/mindspace-long-image.mjs +++ b/mindspace-long-image.mjs @@ -9,12 +9,25 @@ const DEFAULT_VIEWPORT_HEIGHT = 720; const MAX_LONG_IMAGE_HEIGHT = 20000; export const LONG_IMAGE_EXPORT_STYLE = ` [data-mindspace-public-share], +[data-mindspace-public-share-dialog], +[data-mindspace-public-share-dialog-panel], .publication-share-fab, .publication-share-sheet { display: none !important; + visibility: hidden !important; + opacity: 0 !important; + pointer-events: none !important; } `; +export const LONG_IMAGE_EXPORT_SELECTORS = Object.freeze([ + '[data-mindspace-public-share]', + '[data-mindspace-public-share-dialog]', + '[data-mindspace-public-share-dialog-panel]', + '.publication-share-fab', + '.publication-share-sheet', +]); + export function isLongImageDownloadRequest(query) { const value = String(query?.download ?? query?.export ?? '').trim().toLowerCase(); return value === 'long-image' || value === 'long_image' || value === 'png'; @@ -53,6 +66,23 @@ async function launchChromium(chromium) { } } +export async function hideLongImageExportChrome(page) { + await page.addStyleTag?.({ + content: LONG_IMAGE_EXPORT_STYLE, + }).catch(() => null); + await page.evaluate?.((selectors) => { + for (const selector of selectors) { + for (const element of document.querySelectorAll(selector)) { + element.setAttribute('data-memind-long-image-hidden', '1'); + element.style.setProperty('display', 'none', 'important'); + element.style.setProperty('visibility', 'hidden', 'important'); + element.style.setProperty('opacity', '0', 'important'); + element.style.setProperty('pointer-events', 'none', 'important'); + } + } + }, LONG_IMAGE_EXPORT_SELECTORS).catch(() => null); +} + export async function renderLongImage({ htmlPath = null, url = null, @@ -84,6 +114,7 @@ export async function renderLongImage({ width: clampDimension(size.width, DEFAULT_VIEWPORT_WIDTH, 2400), height: Math.min(clampDimension(size.height, DEFAULT_VIEWPORT_HEIGHT, MAX_LONG_IMAGE_HEIGHT), 2400), }); + await hideLongImageExportChrome(page); await fsPromises.mkdir(path.dirname(destination), { recursive: true }); await page.screenshot({ path: destination, diff --git a/mindspace-long-image.test.mjs b/mindspace-long-image.test.mjs index 503f7b8..0895606 100644 --- a/mindspace-long-image.test.mjs +++ b/mindspace-long-image.test.mjs @@ -1,7 +1,9 @@ import assert from 'node:assert/strict'; import test from 'node:test'; import { + hideLongImageExportChrome, isLongImageDownloadRequest, + LONG_IMAGE_EXPORT_SELECTORS, LONG_IMAGE_EXPORT_STYLE, } from './mindspace-long-image.mjs'; @@ -13,7 +15,25 @@ test('recognizes supported long-image download query values', () => { test('long-image capture style hides platform page actions', () => { assert.match(LONG_IMAGE_EXPORT_STYLE, /\[data-mindspace-public-share\]/); + assert.match(LONG_IMAGE_EXPORT_STYLE, /\[data-mindspace-public-share-dialog\]/); assert.match(LONG_IMAGE_EXPORT_STYLE, /\.publication-share-fab/); assert.match(LONG_IMAGE_EXPORT_STYLE, /\.publication-share-sheet/); assert.match(LONG_IMAGE_EXPORT_STYLE, /display:\s*none\s*!important/); + assert.ok(LONG_IMAGE_EXPORT_SELECTORS.includes('[data-mindspace-public-share]')); +}); + +test('long-image capture actively hides injected platform chrome before screenshot', async () => { + const calls = []; + const page = { + async addStyleTag(options) { + calls.push(['style', options.content]); + }, + async evaluate(_fn, selectors) { + calls.push(['evaluate', selectors]); + }, + }; + await hideLongImageExportChrome(page); + assert.deepEqual(calls[0][0], 'style'); + assert.match(calls[0][1], /\[data-mindspace-public-share\]/); + assert.deepEqual(calls[1], ['evaluate', LONG_IMAGE_EXPORT_SELECTORS]); });