Skip to content

Commit 4ceb0f8

Browse files
janmonschkepieh
authored andcommitted
feat(gatsby-remark-copy-linked-files): add support for video elements with src attribute (#10395)
This adds support for video elements that only have a `src` attribute. ```html <video src="myvideo.mp4"></video> ```
1 parent a0506d5 commit 4ceb0f8

File tree

2 files changed

+58
-104
lines changed

2 files changed

+58
-104
lines changed

packages/gatsby-remark-copy-linked-files/src/__tests__/index.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,18 @@ describe(`gatsby-remark-copy-linked-files`, () => {
170170
expect(fsExtra.copy).toHaveBeenCalled()
171171
})
172172

173+
it(`can copy HTML videos from video elements with the src attribute`, async () => {
174+
const path = `videos/sample-video.mp4`
175+
176+
const markdownAST = remark.parse(
177+
`<video controls="controls" autoplay="true" src="${path}">\n<p>Your browser does not support the video element.</p>\n</video>`
178+
)
179+
180+
await plugin({ files: getFiles(path), markdownAST, markdownNode, getNode })
181+
182+
expect(fsExtra.copy).toHaveBeenCalled()
183+
})
184+
173185
it(`can copy HTML videos when some siblings are in ignore extensions`, async () => {
174186
const path = `videos/sample-video.mp4`
175187
const path1 = `images/sample-image.jpg`

packages/gatsby-remark-copy-linked-files/src/index.js

Lines changed: 46 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -206,127 +206,69 @@ module.exports = (
206206
visit(markdownAST, `html`, node => {
207207
const $ = cheerio.load(node.value)
208208

209-
// Handle Images
210-
const imageRefs = []
211-
$(`img`).each(function() {
212-
try {
213-
if (isRelativeUrl($(this).attr(`src`))) {
214-
imageRefs.push($(this))
215-
}
216-
} catch (err) {
217-
// Ignore
218-
}
219-
})
220-
221-
for (let thisImg of imageRefs) {
209+
function processUrl({ url }) {
222210
try {
223-
const ext = thisImg
224-
.attr(`src`)
225-
.split(`.`)
226-
.pop()
227-
if (!options.ignoreFileExtensions.includes(ext)) {
228-
generateImagesAndUpdateNode(thisImg, node)
229-
}
230-
} catch (err) {
231-
// Ignore
232-
}
233-
}
234-
235-
// Handle video tags.
236-
const videoRefs = []
237-
$(`video source`).each(function() {
238-
try {
239-
if (isRelativeUrl($(this).attr(`src`))) {
240-
videoRefs.push($(this))
241-
}
242-
} catch (err) {
243-
// Ignore
244-
}
245-
})
246-
247-
for (let thisVideo of videoRefs) {
248-
try {
249-
const ext = thisVideo
250-
.attr(`src`)
251-
.split(`.`)
252-
.pop()
211+
const ext = url.split(`.`).pop()
253212
if (!options.ignoreFileExtensions.includes(ext)) {
254213
// The link object will be modified to the new location so we'll
255214
// use that data to update our ref
256-
const link = { url: thisVideo.attr(`src`) }
215+
const link = { url }
257216
visitor(link)
258-
node.value = node.value.replace(
259-
new RegExp(thisVideo.attr(`src`), `g`),
260-
link.url
261-
)
217+
node.value = node.value.replace(new RegExp(url, `g`), link.url)
262218
}
263219
} catch (err) {
264220
// Ignore
265221
}
266222
}
267223

268-
// Handle audio tags.
269-
const audioRefs = []
270-
$(`audio source`).each(function() {
271-
try {
272-
if (isRelativeUrl($(this).attr(`src`))) {
273-
audioRefs.push($(this))
274-
}
275-
} catch (err) {
276-
// Ignore
277-
}
278-
})
279-
280-
for (let thisAudio of audioRefs) {
281-
try {
282-
const ext = thisAudio
283-
.attr(`src`)
284-
.split(`.`)
285-
.pop()
286-
if (!options.ignoreFileExtensions.includes(ext)) {
287-
const link = { url: thisAudio.attr(`src`) }
288-
visitor(link)
289-
node.value = node.value.replace(
290-
new RegExp(thisAudio.attr(`src`), `g`),
291-
link.url
292-
)
293-
}
294-
} catch (err) {
295-
// Ignore
296-
}
224+
// extracts all elements that have the provided url attribute
225+
function extractUrlAttributeAndElement(selection, attribute) {
226+
return (
227+
selection
228+
// extract the elements that have the attribute
229+
.map(function() {
230+
const element = $(this)
231+
const url = $(this).attr(attribute)
232+
if (url && isRelativeUrl(url)) {
233+
return { url, element }
234+
}
235+
return undefined
236+
})
237+
// cheerio object -> array
238+
.toArray()
239+
// filter out empty or undefined values
240+
.filter(Boolean)
241+
)
297242
}
298243

299-
// Handle a tags.
300-
const aRefs = []
301-
$(`a`).each(function() {
302-
try {
303-
if (isRelativeUrl($(this).attr(`href`))) {
304-
aRefs.push($(this))
244+
// Handle Images
245+
extractUrlAttributeAndElement($(`img[src]`), `src`).forEach(
246+
({ url, element }) => {
247+
try {
248+
const ext = url.split(`.`).pop()
249+
if (!options.ignoreFileExtensions.includes(ext)) {
250+
generateImagesAndUpdateNode(element, node)
251+
}
252+
} catch (err) {
253+
// Ignore
305254
}
306-
} catch (err) {
307-
// Ignore
308255
}
309-
})
256+
)
310257

311-
for (let thisATag of aRefs) {
312-
try {
313-
const ext = thisATag
314-
.attr(`href`)
315-
.split(`.`)
316-
.pop()
317-
if (!options.ignoreFileExtensions.includes(ext)) {
318-
const link = { url: thisATag.attr(`href`) }
319-
visitor(link)
258+
// Handle video tags.
259+
extractUrlAttributeAndElement(
260+
$(`video source[src], video[src]`),
261+
`src`
262+
).forEach(processUrl)
320263

321-
node.value = node.value.replace(
322-
new RegExp(thisATag.attr(`href`), `g`),
323-
link.url
324-
)
325-
}
326-
} catch (err) {
327-
// Ignore
328-
}
329-
}
264+
// Handle audio tags.
265+
extractUrlAttributeAndElement(
266+
$(`audio source[src], audio[src]`),
267+
`src`
268+
).forEach(processUrl)
269+
270+
// Handle a tags.
271+
extractUrlAttributeAndElement($(`a[href]`), `href`).forEach(processUrl)
330272

331273
return
332274
})

0 commit comments

Comments
 (0)