mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-02-17 23:44:39 -05:00
Expand external media inliner to handle srcset images (#22130)
no issue The external media inliner currently fails to process images in a `srcset` attribute. This PR extends the regexp to detect more valid URLs, `srcset` attributes is a common example, and background image URLs in quotes is another.
This commit is contained in:
parent
0b50f330db
commit
fdd18908a2
2 changed files with 58 additions and 2 deletions
|
@ -139,9 +139,9 @@ class ExternalMediaInliner {
|
||||||
*/
|
*/
|
||||||
async inlineContent(content, domains) {
|
async inlineContent(content, domains) {
|
||||||
for (const domain of domains) {
|
for (const domain of domains) {
|
||||||
// NOTE: the src could end with a quote, apostrophe or double-backslash. backlashes are added to content
|
// NOTE: the src could end with a quote, bracket, apostrophe, double-backslash, or encoded quote. backlashes are added to content
|
||||||
// as an escape character
|
// as an escape character
|
||||||
const srcTerminationSymbols = `"|'|\\\\`;
|
const srcTerminationSymbols = `"|\\)|'| |,|<|\\\\|"`;
|
||||||
const regex = new RegExp(`(${domain}.*?)(${srcTerminationSymbols})`, 'igm');
|
const regex = new RegExp(`(${domain}.*?)(${srcTerminationSymbols})`, 'igm');
|
||||||
const matches = content.matchAll(regex);
|
const matches = content.matchAll(regex);
|
||||||
|
|
||||||
|
|
|
@ -267,6 +267,62 @@ describe('ExternalMediaInliner', function () {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('inlines srcset images in a lexical html card', async function () {
|
||||||
|
const requestMock = nock('https://example.com')
|
||||||
|
.get('/path/to/landscape-1x.jpg')
|
||||||
|
.reply(200, GIF1x1)
|
||||||
|
.get('/path/to/landscape-2x.jpg')
|
||||||
|
.reply(200, GIF1x1)
|
||||||
|
.get('/path/to/landscape-original.jpg')
|
||||||
|
.reply(200, GIF1x1);
|
||||||
|
|
||||||
|
const postStub = sinon.stub();
|
||||||
|
postStub.withArgs('mobiledoc').returns(null);
|
||||||
|
postStub.withArgs('lexical').returns(`{"root":{"children":[{"type":"html","version":1,"html":"<img srcset="https://example.com/path/to/landscape-1x.jpg, https://example.com/path/to/landscape-2x.jpg 2x" src="https://example.com/path/to/landscape-original.jpg" />"}],"direction":null,"format":"","indent":0,"type":"root","version":1}}`);
|
||||||
|
|
||||||
|
const postModelInstanceStub = {
|
||||||
|
id: 'inlined-post-with-htmlcard-id',
|
||||||
|
get: postStub
|
||||||
|
};
|
||||||
|
|
||||||
|
postModelStub = {
|
||||||
|
findPage: sinon.stub().returns({
|
||||||
|
data: [postModelInstanceStub]
|
||||||
|
}),
|
||||||
|
edit: sinon.stub().resolves()
|
||||||
|
};
|
||||||
|
|
||||||
|
sinon.stub(path, 'relative')
|
||||||
|
.withArgs('/content/images', '/content/images/unique-image.jpg')
|
||||||
|
.returns('unique-image.jpg');
|
||||||
|
const inliner = new ExternalMediaInliner({
|
||||||
|
PostModel: postModelStub,
|
||||||
|
PostMetaModel: postMetaModelStub,
|
||||||
|
TagModel: tagModelStub,
|
||||||
|
UserModel: userModelStub,
|
||||||
|
getMediaStorage: sinon.stub().withArgs('.jpg').returns({
|
||||||
|
getTargetDir: () => '/content/images',
|
||||||
|
getUniqueFileName: () => '/content/images/unique-image.jpg',
|
||||||
|
saveRaw: () => '/content/images/unique-image.jpg'
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
await inliner.inline(['https://example.com']);
|
||||||
|
|
||||||
|
assert.ok(requestMock.isDone());
|
||||||
|
assert.ok(postModelStub.edit.calledOnce);
|
||||||
|
// NOTE: The file names all being the same as a limitation in how this is stubbed. In production, each image is unique
|
||||||
|
assert.deepEqual(postModelStub.edit.args[0][0], {
|
||||||
|
lexical: `{"root":{"children":[{"type":"html","version":1,"html":"<img srcset="__GHOST_URL__/content/images/unique-image.jpg, __GHOST_URL__/content/images/unique-image.jpg 2x" src="__GHOST_URL__/content/images/unique-image.jpg" />"}],"direction":null,"format":"","indent":0,"type":"root","version":1}}`
|
||||||
|
});
|
||||||
|
assert.deepEqual(postModelStub.edit.args[0][1], {
|
||||||
|
id: 'inlined-post-with-htmlcard-id',
|
||||||
|
context: {
|
||||||
|
internal: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('inlines image in the post\'s mobiledoc & lexical content', async function () {
|
it('inlines image in the post\'s mobiledoc & lexical content', async function () {
|
||||||
const imageURL = 'https://img.stockfresh.com/files/f/image.jpg';
|
const imageURL = 'https://img.stockfresh.com/files/f/image.jpg';
|
||||||
const requestMock = nock('https://img.stockfresh.com')
|
const requestMock = nock('https://img.stockfresh.com')
|
||||||
|
|
Loading…
Add table
Reference in a new issue