Skip to content
23 changes: 23 additions & 0 deletions blocks/edit/prose/image-utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/**
* Rewrites an image src from an AEM preview/publish host to the DA preview host.
*
* Images stored in DA content may reference *.aem.page (preview) or *.aem.live
* (publish) URLs. These hosts require AEM authentication that the DA editor does
* not carry, causing 401 errors when the browser fetches them. The equivalent
* *.preview.da.live URL serves the same content and is accessible from the editor.
*
* @param {string} src - The original image src URL.
* @returns {string} The rewritten src, or the original if no rewrite was needed.
*/
export function rewriteImageSrcForEditor(src) {
try {
const url = new URL(src);
if (url.host.endsWith('.aem.page') || url.host.endsWith('.aem.live')) {
url.host = url.host.replace(/\.aem\.(page|live)$/, '.preview.da.live');
return url.toString();
}
} catch {
// relative or malformed src — leave unchanged
}
return src;
}
15 changes: 15 additions & 0 deletions blocks/edit/prose/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import { COLLAB_ORIGIN, DA_ORIGIN } from '../../shared/constants.js';
import { daFetch, getAuthToken } from '../../shared/utils.js';
import { getDiffClass, checkForLocNodes, addActiveView } from './diff/diff-utils.js';
import { debounce, initDaMetadata } from '../utils/helpers.js';
import { rewriteImageSrcForEditor } from './image-utils.js';

async function checkDoc(path) {
return daFetch(path, { method: 'HEAD' });
Expand Down Expand Up @@ -469,6 +470,20 @@ export default async function initProse({ path, permissions, doc, daContent, wsP
state,
dispatchTransaction,
nodeViews: {
image(node) {
const img = document.createElement('img');
img.src = rewriteImageSrcForEditor(node.attrs.src);
if (node.attrs.alt) img.alt = node.attrs.alt;
return {
dom: img,
update(updated) {
if (updated.type.name !== 'image') return false;
img.src = rewriteImageSrcForEditor(updated.attrs.src);
if (updated.attrs.alt) img.alt = updated.attrs.alt;
return true;
},
};
},
diff_added(node, view, getPos) {
const LocAddedView = getDiffClass('da-diff-added', getSchema, dispatchTransaction, { isUpstream: false });
return new LocAddedView(node, view, getPos);
Expand Down
14 changes: 12 additions & 2 deletions blocks/edit/prose/plugins/imageFocalPoint.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Plugin, PluginKey } from 'da-y-wrapper';
import { rewriteImageSrcForEditor } from '../image-utils.js';
import inlinesvg from '../../../shared/inlinesvg.js';
import { openFocalPointDialog } from './focalPointDialog.js';
import { loadLibrary } from '../../da-library/helpers/helpers.js';
Expand Down Expand Up @@ -40,7 +41,7 @@ function shouldShowFocalPoint(tableName, blocks) {
}

function updateImageAttributes(img, attrs) {
img.src = attrs.src;
img.src = rewriteImageSrcForEditor(attrs.src);
['alt', 'title', 'width', 'height'].forEach((attr) => {
if (attrs[attr]) {
img[attr] = attrs[attr];
Expand Down Expand Up @@ -150,7 +151,16 @@ export default function imageFocalPoint() {
if (isInTableCell(view.state, getPos())) {
return new ImageWithFocalPointView(node, view, getPos);
}
return null;
const img = document.createElement('img');
updateImageAttributes(img, node.attrs);
return {
dom: img,
update(updated) {
if (updated.type.name !== 'image') return false;
updateImageAttributes(img, updated.attrs);
return true;
},
};
},
},
},
Expand Down
7 changes: 4 additions & 3 deletions test/unit/blocks/edit/prose/plugins/imageFocalPoint.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ describe('imageFocalPoint Plugin', () => {
expect(icon.classList.contains('focal-point-icon-active')).to.be.true;
});

it('does not create node view for images outside table cells', () => {
it('creates a plain image node view for images outside table cells', () => {
const plugin = imageFocalPoint();
const createNodeView = plugin.props.nodeViews.image;

Expand All @@ -144,8 +144,9 @@ describe('imageFocalPoint Plugin', () => {
const mockView = { state: mockState, dom: document.createElement('div') };
const getPos = () => 10;

const nodeView = createNodeView({}, mockView, getPos);
expect(nodeView).to.be.null;
const nodeView = createNodeView({ attrs: { src: 'https://example.com/img.jpg' } }, mockView, getPos);
expect(nodeView).to.not.be.null;
expect(nodeView.dom.tagName).to.equal('IMG');
});

it('updates node view correctly', async () => {
Expand Down
Loading