Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(gatsby-remark-images): don’t add links if image is already linked #6982

Merged
merged 3 commits into from
Aug 6, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion packages/gatsby-remark-images/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
"is-relative-url": "^2.0.0",
"lodash": "^4.17.4",
"slash": "^1.0.0",
"unist-util-select": "^1.5.0"
"unist-util-select": "^1.5.0",
"unist-util-visit-parents": "^2.0.1"
},
"devDependencies": {
"@babel/cli": "7.0.0-beta.52",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,75 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`it handles goofy nesting properly 1`] = `
"
<span
class=\\"gatsby-resp-image-wrapper\\"
style=\\"position: relative; display: block; ; max-width: 300px; margin-left: auto; margin-right: auto;\\"
>
<span
class=\\"gatsby-resp-image-background-image\\"
style=\\"padding-bottom: 133.33333333333331%; position: relative; bottom: 0; left: 0; background-image: url('url('data:image/png;base64, iVBORw)'); background-size: cover; display: block;\\"
>
<img
class=\\"gatsby-resp-image-image\\"
style=\\"width: 100%; height: 100%; margin: 0; vertical-align: middle; position: absolute; top: 0; left: 0; box-shadow: inset 0px 0px 0px 400px white;\\"
alt=\\"test\\"
title=\\"\\"
src=\\"not-a-real-dir/images/this-image-already-has-a-link.jpeg\\"
srcset=\\"not-a-real-dir/images/this-image-already-has-a-link.jpeg, not-a-real-dir/images/this-image-already-has-a-link.jpeg\\"
sizes=\\"(max-width: 650px) 100vw, 650px\\"
/>
</span>
</span>
"
`;

exports[`it leaves images that are already linked alone 1`] = `
"
<span
class=\\"gatsby-resp-image-wrapper\\"
style=\\"position: relative; display: block; ; max-width: 300px; margin-left: auto; margin-right: auto;\\"
>
<span
class=\\"gatsby-resp-image-background-image\\"
style=\\"padding-bottom: 133.33333333333331%; position: relative; bottom: 0; left: 0; background-image: url('url('data:image/png;base64, iVBORw)'); background-size: cover; display: block;\\"
>
<img
class=\\"gatsby-resp-image-image\\"
style=\\"width: 100%; height: 100%; margin: 0; vertical-align: middle; position: absolute; top: 0; left: 0; box-shadow: inset 0px 0px 0px 400px white;\\"
alt=\\"img\\"
title=\\"\\"
src=\\"not-a-real-dir/image/my-image.jpg\\"
srcset=\\"not-a-real-dir/image/my-image.jpg, not-a-real-dir/image/my-image.jpg\\"
sizes=\\"(max-width: 650px) 100vw, 650px\\"
/>
</span>
</span>
"
`;

exports[`it leaves linked HTML img tags alone 1`] = `
"<a href=\\"https://example.org\\">

<span class=\\"gatsby-resp-image-wrapper\\" style=\\"position: relative; display: block; ; max-width: 300px; margin-left: auto; margin-right: auto;\\">
<span class=\\"gatsby-resp-image-background-image\\" style=\\"padding-bottom: 133.33333333333331%; position: relative; bottom: 0; left: 0; background-image: url(&apos;url(&apos;data:image/png;base64, iVBORw)&apos;); background-size: cover; display: block;\\">
<img class=\\"gatsby-resp-image-image\\" style=\\"width: 100%; height: 100%; margin: 0; vertical-align: middle; position: absolute; top: 0; left: 0; box-shadow: inset 0px 0px 0px 400px white;\\" alt=\\"this image already has a link\\" title=\\"\\" src=\\"not-a-real-dir/images/this-image-already-has-a-link.jpeg\\" srcset=\\"not-a-real-dir/images/this-image-already-has-a-link.jpeg, not-a-real-dir/images/this-image-already-has-a-link.jpeg\\" sizes=\\"(max-width: 650px) 100vw, 650px\\">
</span>
</span>

</a>"
`;

exports[`it leaves single-line linked HTML img tags alone 1`] = `
"
<span class=\\"gatsby-resp-image-wrapper\\" style=\\"position: relative; display: block; ; max-width: 300px; margin-left: auto; margin-right: auto;\\">
<span class=\\"gatsby-resp-image-background-image\\" style=\\"padding-bottom: 133.33333333333331%; position: relative; bottom: 0; left: 0; background-image: url(&apos;url(&apos;data:image/png;base64, iVBORw)&apos;); background-size: cover; display: block;\\">
<img class=\\"gatsby-resp-image-image\\" style=\\"width: 100%; height: 100%; margin: 0; vertical-align: middle; position: absolute; top: 0; left: 0; box-shadow: inset 0px 0px 0px 400px white;\\" alt=\\"this image already has a link\\" title=\\"\\" src=\\"not-a-real-dir/images/this-image-already-has-a-link.jpeg\\" srcset=\\"not-a-real-dir/images/this-image-already-has-a-link.jpeg, not-a-real-dir/images/this-image-already-has-a-link.jpeg\\" sizes=\\"(max-width: 650px) 100vw, 650px\\">
</span>
</span>
"
`;

exports[`it transforms HTML img tags 1`] = `
"
<a class=\\"gatsby-resp-image-link\\" href=\\"not-a-real-dir/image/my-image.jpeg\\" style=\\"display: block\\" target=\\"_blank\\" rel=\\"noopener\\">
Expand Down
61 changes: 61 additions & 0 deletions packages/gatsby-remark-images/src/__tests__/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -146,3 +146,64 @@ test(`it leaves non-relative HTML img tags alone`, async () => {
const nodes = await plugin(createPluginOptions(content, imagePath))
expect(nodes[0].value).toBe(content)
})

test(`it leaves images that are already linked alone`, async () => {
const imagePath = `image/my-image.jpg`
const content = `
[![img](./${imagePath})](https://google.com)
`

const nodes = await plugin(createPluginOptions(content, imagePath))
const node = nodes.pop()

expect(node.type).toBe(`html`)
expect(node.value).toMatchSnapshot()
expect(node.value).not.toMatch(`<html>`)
})

test(`it leaves linked HTML img tags alone`, async () => {
const imagePath = `images/this-image-already-has-a-link.jpeg`

const content = `
<a href="https://example.org">
<img src="./${imagePath}">
</a>
`.trim()

const nodes = await plugin(createPluginOptions(content, imagePath))
const node = nodes.pop()

expect(node.type).toBe(`html`)
expect(node.value).toMatchSnapshot()
expect(node.value).not.toMatch(`<html>`)
})

test(`it leaves single-line linked HTML img tags alone`, async () => {
const imagePath = `images/this-image-already-has-a-link.jpeg`

const content = `
<a href="https://example.org"><img src="./${imagePath}"></a>
`.trim()

const nodes = await plugin(createPluginOptions(content, imagePath))
const node = nodes.pop()

expect(node.type).toBe(`html`)
expect(node.value).toMatchSnapshot()
expect(node.value).not.toMatch(`<html>`)
})

test(`it handles goofy nesting properly`, async () => {
const imagePath = `images/this-image-already-has-a-link.jpeg`

const content = `
<a href="https://google.com">**![test](./${imagePath})**</a>
`.trim()

const nodes = await plugin(createPluginOptions(content, imagePath))
const node = nodes.pop()

expect(node.type).toBe(`html`)
expect(node.value).toMatchSnapshot()
expect(node.value).not.toMatch(`<html>`)
})
47 changes: 36 additions & 11 deletions packages/gatsby-remark-images/src/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const select = require(`unist-util-select`)
// const select = require(`unist-util-select`)
const visitWithParents = require(`unist-util-visit-parents`)
const path = require(`path`)
const isRelativeUrl = require(`is-relative-url`)
const _ = require(`lodash`)
Expand Down Expand Up @@ -29,15 +30,34 @@ module.exports = (

const options = _.defaults(pluginOptions, defaults)

const findParentLinks = ({ children }) =>
children.some(
node =>
(node.type === `html` && !!node.value.match(/<a /)) ||
node.type === `link`
)

// This will allow the use of html image tags
// const rawHtmlNodes = select(markdownAST, `html`)
let rawHtmlNodes = []
visitWithParents(markdownAST, `html`, (node, ancestors) => {
const inLink = ancestors.some(findParentLinks)

rawHtmlNodes.push({ node, inLink })
})

// This will only work for markdown syntax image tags
const markdownImageNodes = select(markdownAST, `image`)
let markdownImageNodes = []

visitWithParents(markdownAST, `image`, (node, ancestors) => {
const inLink = ancestors.some(findParentLinks)

// This will also allow the use of html image tags
const rawHtmlNodes = select(markdownAST, `html`)
markdownImageNodes.push({ node, inLink })
})

// Takes a node and generates the needed images and then returns
// the needed HTML replacement for the image
const generateImagesAndUpdateNode = async function(node, resolve) {
const generateImagesAndUpdateNode = async function(node, resolve, inLink) {
// Check if this markdownNode has a File parent. This plugin
// won't work if the image isn't hosted locally.
const parentNode = getNode(markdownNode.parent)
Expand Down Expand Up @@ -138,7 +158,7 @@ module.exports = (
<img
class="${imageClass}"
style="${imageStyle}"
src="${fallbackSrc}"
src="${fallbackSrc}"
alt="${node.alt ? node.alt : defaultAlt}"
title="${node.title ? node.title : ``}"
src="${fallbackSrc}"
Expand All @@ -165,7 +185,7 @@ module.exports = (
`

// Make linking to original image optional.
if (options.linkImagesToOriginal) {
if (!inLink && options.linkImagesToOriginal) {
rawHTML = `
<a
class="gatsby-resp-image-link"
Expand Down Expand Up @@ -196,7 +216,7 @@ module.exports = (
return Promise.all(
// Simple because there is no nesting in markdown
markdownImageNodes.map(
node =>
({ node, inLink }) =>
new Promise(async (resolve, reject) => {
const fileType = node.url.slice(-3)

Expand All @@ -207,7 +227,11 @@ module.exports = (
fileType !== `gif` &&
fileType !== `svg`
) {
const rawHTML = await generateImagesAndUpdateNode(node, resolve)
const rawHTML = await generateImagesAndUpdateNode(
node,
resolve,
inLink
)

if (rawHTML) {
// Replace the image node with an inline HTML node.
Expand All @@ -226,7 +250,7 @@ module.exports = (
Promise.all(
// Complex because HTML nodes can contain multiple images
rawHtmlNodes.map(
node =>
({ node, inLink }) =>
new Promise(async (resolve, reject) => {
if (!node.value) {
return resolve()
Expand Down Expand Up @@ -265,7 +289,8 @@ module.exports = (
) {
const rawHTML = await generateImagesAndUpdateNode(
formattedImgTag,
resolve
resolve,
inLink
)

if (rawHTML) {
Expand Down