diff --git a/express/code/blocks/color-extract/color-extract.js b/express/code/blocks/color-extract/color-extract.js index e5fcf92a3..92752fd68 100644 --- a/express/code/blocks/color-extract/color-extract.js +++ b/express/code/blocks/color-extract/color-extract.js @@ -818,6 +818,7 @@ function renderColorVariant(block, rows, config, strings = {}) { history.clear(); currentCanvas = null; currentSrc = null; + sessionStorage.removeItem('color-extract-image-src'); popstateAc.abort(); block.querySelectorAll('.color-extract-suggestion.is-selected').forEach((el) => { el.classList.remove('is-selected'); @@ -828,6 +829,7 @@ function renderColorVariant(block, rows, config, strings = {}) { async function onImageReady(image, src) { window.history.pushState({ colorExtract: 'results' }, ''); currentSrc = src; + try { sessionStorage.setItem('color-extract-image-src', src); } catch { /* quota exceeded — image won't be restored after sign-in */ } edit.setBackground(src); history.clear(); @@ -980,7 +982,21 @@ function renderColorVariant(block, rows, config, strings = {}) { const paletteName = getResolvedPaletteName(); controller.setState({ swatches: colors.map((hex) => ({ hex })), baseColorIndex: 0 }); if (paletteName) controller.setMetadata({ name: paletteName }); - edit.bgWrapper.replaceWith(dropzone.container); + + const storedSrc = sessionStorage.getItem('color-extract-image-src'); + sessionStorage.removeItem('color-extract-image-src'); + if (storedSrc) { + const img = new Image(); + img.onload = async () => { + currentSrc = storedSrc; + edit.setBackground(storedSrc); + currentCanvas = drawImageToCanvas(img); + await setupMarkers(currentCanvas); + }; + img.src = storedSrc; + } else { + edit.bgWrapper.replaceWith(dropzone.container); + } block.classList.add('has-image'); window.history.replaceState({ colorExtract: 'results' }, ''); floatingToolbar.mount(); @@ -1269,6 +1285,7 @@ async function renderGradientVariant(block, rows, config, strings = {}) { history.clear(); currentCanvas = null; currentSrc = null; + sessionStorage.removeItem('color-extract-image-src'); popstateAc.abort(); gradientEditor.setGradient(initialGradient); block.querySelectorAll('.color-extract-suggestion.is-selected').forEach((el) => { @@ -1280,6 +1297,7 @@ async function renderGradientVariant(block, rows, config, strings = {}) { async function onImageReady(image, src) { window.history.pushState({ colorExtract: 'results' }, ''); currentSrc = src; + try { sessionStorage.setItem('color-extract-image-src', src); } catch { /* quota exceeded — image won't be restored after sign-in */ } edit.setBackground(src); history.clear(); @@ -1448,7 +1466,21 @@ async function renderGradientVariant(block, rows, config, strings = {}) { const gradientData = { type: 'linear', angle: 90, colorStops }; gradientEditor.setGradient(gradientData); syncSwatchesFromGradient(gradientData); - edit.bgWrapper.replaceWith(dropzone.container); + + const storedSrc = sessionStorage.getItem('color-extract-image-src'); + sessionStorage.removeItem('color-extract-image-src'); + if (storedSrc) { + const img = new Image(); + img.onload = async () => { + currentSrc = storedSrc; + edit.setBackground(storedSrc); + currentCanvas = drawImageToCanvas(img); + await setupMarkers(currentCanvas); + }; + img.src = storedSrc; + } else { + edit.bgWrapper.replaceWith(dropzone.container); + } block.classList.add('has-image'); window.history.replaceState({ colorExtract: 'results' }, ''); floatingToolbar.mount(); diff --git a/test/blocks/color-extract/color-extract.test.js b/test/blocks/color-extract/color-extract.test.js index e13f1fb8c..3198af386 100644 --- a/test/blocks/color-extract/color-extract.test.js +++ b/test/blocks/color-extract/color-extract.test.js @@ -128,3 +128,68 @@ describe('Color Extract — gradient variant', () => { expect(suggestions.length).to.equal(2); }); }); + +describe('Color Extract — sign-in image restoration', () => { + const IMAGE_SRC_KEY = 'color-extract-image-src'; + // Use a URL that triggers onerror (not onload) so the async setupMarkers + // dynamic import is never reached in the test environment. + const FAKE_SRC = './nonexistent-test-image.png'; + const PARAM_NAME = 'color-palette'; + + before(() => { + window.isTestEnv = true; + }); + + afterEach(() => { + sessionStorage.removeItem(IMAGE_SRC_KEY); + window.history.replaceState({}, '', window.location.pathname); + }); + + it('palette: keeps bgWrapper in DOM when image src is stored and color-palette param present', async () => { + sessionStorage.setItem(IMAGE_SRC_KEY, FAKE_SRC); + window.history.replaceState({}, '', `${window.location.pathname}?${PARAM_NAME}=FF0000,00FF00`); + document.body.innerHTML = basic; + const block = document.querySelector('.color-extract'); + await decorate(block); + + expect(sessionStorage.getItem(IMAGE_SRC_KEY)).to.be.null; + expect(block.classList.contains('has-image')).to.be.true; + // bgWrapper should remain in the DOM (not replaced by the dropzone) + expect(block.querySelector('.color-extract-edit-bg')).to.exist; + }); + + it('palette: replaces bgWrapper with dropzone when no image stored and color-palette param present', async () => { + sessionStorage.removeItem(IMAGE_SRC_KEY); + window.history.replaceState({}, '', `${window.location.pathname}?${PARAM_NAME}=FF0000,00FF00`); + document.body.innerHTML = basic; + const block = document.querySelector('.color-extract'); + await decorate(block); + + expect(block.classList.contains('has-image')).to.be.true; + // bgWrapper replaced by dropzone — edit-bg should be gone + expect(block.querySelector('.color-extract-edit-bg')).to.not.exist; + }); + + it('gradient: keeps bgWrapper in DOM when image src is stored and color-palette param present', async () => { + sessionStorage.setItem(IMAGE_SRC_KEY, FAKE_SRC); + window.history.replaceState({}, '', `${window.location.pathname}?${PARAM_NAME}=FF0000,00FF00`); + document.body.innerHTML = gradient; + const block = document.querySelector('.color-extract'); + await decorate(block); + + expect(sessionStorage.getItem(IMAGE_SRC_KEY)).to.be.null; + expect(block.classList.contains('has-image')).to.be.true; + expect(block.querySelector('.color-extract-edit-bg')).to.exist; + }); + + it('gradient: replaces bgWrapper with dropzone when no image stored and color-palette param present', async () => { + sessionStorage.removeItem(IMAGE_SRC_KEY); + window.history.replaceState({}, '', `${window.location.pathname}?${PARAM_NAME}=FF0000,00FF00`); + document.body.innerHTML = gradient; + const block = document.querySelector('.color-extract'); + await decorate(block); + + expect(block.classList.contains('has-image')).to.be.true; + expect(block.querySelector('.color-extract-edit-bg')).to.not.exist; + }); +});