mirror of
https://github.com/freeCodeCamp/freeCodeCamp.git
synced 2026-05-28 18:26:54 +00:00
feat(curriculum): add HTML video player project to FSD cert (#62866)
Co-authored-by: Jessica Wilkins <67210629+jdwilkin4@users.noreply.github.com> Co-authored-by: Ilenia <26656284+ilenia-magoni@users.noreply.github.com> Co-authored-by: Dario <105294544+Dario-DC@users.noreply.github.com> Co-authored-by: Ilenia M <nethleen@gmail.com> Co-authored-by: majestic-owl448 <26656284+majestic-owl448@users.noreply.github.com>
This commit is contained in:
@@ -7816,6 +7816,13 @@
|
||||
"In these lectures, you will learn how to work with the <code>audio</code> and <code>video</code> elements."
|
||||
]
|
||||
},
|
||||
"workshop-html-video-player": {
|
||||
"title": "Build an HTML Video Player",
|
||||
"intro": [
|
||||
"In this workshop, you'll use HTML to create a basic video player.",
|
||||
"This project will cover the <code>video</code> element, the video player setup, and more."
|
||||
]
|
||||
},
|
||||
"lab-html-audio-and-video-player": {
|
||||
"title": "Build an HTML Audio and Video Player",
|
||||
"intro": [
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
---
|
||||
title: Introduction to the Build an HTML Video Player
|
||||
block: workshop-html-video-player
|
||||
superBlock: responsive-web-design-v9
|
||||
---
|
||||
|
||||
## Introduction to the Build an HTML Video Player
|
||||
|
||||
In this workshop, you'll use HTML to create a basic video player. This project will cover the `video` element, the video player setup, and more.
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
---
|
||||
id: 68f18724d71db1dda8d6fec7
|
||||
title: Step 1
|
||||
challengeType: 0
|
||||
dashedName: step-1
|
||||
demoType: onLoad
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
In this workshop, you will build an HTML video player. The HTML boilerplate has been provided for you.
|
||||
|
||||
Create an `h1` element and give it the text `Working with the HTML Video Element`.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should have an `h1` element.
|
||||
|
||||
```js
|
||||
assert.exists(document.querySelector('h1'));
|
||||
```
|
||||
|
||||
Your `h1` element should contain the text `Working with the HTML Video Element`.
|
||||
|
||||
```js
|
||||
const h1 = document.querySelector('h1');
|
||||
assert.strictEqual(h1?.textContent.trim(), 'Working with the HTML Video Element');
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Working with the HTML Video Element</title>
|
||||
</head>
|
||||
<body>
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
---
|
||||
id: 68f1eb9ad0a7575e4dbc31d5
|
||||
title: Step 2
|
||||
challengeType: 0
|
||||
dashedName: step-2
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Next, create a `video` element below the `h1`. Over the next few steps, you will add the necessary attributes to make the video player functional.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should have a `video` element.
|
||||
|
||||
```js
|
||||
assert.exists(document.querySelector('video'));
|
||||
```
|
||||
|
||||
The new `video` element should be below the `h1`.
|
||||
|
||||
```js
|
||||
assert.exists(document.querySelector('h1 + video'));
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Working with the HTML Video Element</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Working with the HTML Video Element</h1>
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
---
|
||||
id: 68f1f371fefd448b4f70b898
|
||||
title: Step 3
|
||||
challengeType: 0
|
||||
dashedName: step-3
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
In a previous lesson, you learned about different attributes available to the `video` element. The `width` attribute determines the width of the video in pixels.
|
||||
|
||||
Add the `width` attribute to the `video` element with a value of `640`.
|
||||
|
||||
# --hints--
|
||||
|
||||
Your `video` element should have the attribute `width` with the value `640`.
|
||||
|
||||
```js
|
||||
const video = document.querySelector('video');
|
||||
assert.strictEqual(video?.getAttribute('width'), '640');
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Working with the HTML Video Element</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Working with the HTML Video Element</h1>
|
||||
--fcc-editable-region--
|
||||
<video>
|
||||
--fcc-editable-region--
|
||||
</video>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
---
|
||||
id: 68f1f57723debf9383c75947
|
||||
title: Step 4
|
||||
challengeType: 0
|
||||
dashedName: step-4
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
The `loop` attribute will restart the video once playback is completed. Think of an internet meme that repeats playback. Omitting the `loop` attribute will make the video playback once.
|
||||
|
||||
The `loop` attribute is a boolean attribute and does not need a value.
|
||||
|
||||
Add the `loop` attribute to the `video` element.
|
||||
|
||||
# --hints--
|
||||
|
||||
Your `video` element should have the `loop` attribute.
|
||||
|
||||
```js
|
||||
const video = document.querySelector('video');
|
||||
assert.isTrue(video?.hasAttribute('loop'));
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Working with the HTML Video Element</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Working with the HTML Video Element</h1>
|
||||
--fcc-editable-region--
|
||||
<video width="640">
|
||||
--fcc-editable-region--
|
||||
</video>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
---
|
||||
id: 68f1f6f97af9749a42260a43
|
||||
title: Step 5
|
||||
challengeType: 0
|
||||
dashedName: step-5
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
The `controls` attribute provides playback controls including playback, rewind, and volume control for the `video` element.
|
||||
|
||||
The `controls` attribute is a boolean attribute and does not need a value.
|
||||
|
||||
Add the `controls` attribute to the `video` element.
|
||||
|
||||
Now you should see the video element displayed on the page.
|
||||
|
||||
# --hints--
|
||||
|
||||
Your `video` element should have the `controls` attribute.
|
||||
|
||||
```js
|
||||
const video = document.querySelector('video');
|
||||
assert.isTrue(video?.hasAttribute('controls'));
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Working with the HTML Video Element</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Working with the HTML Video Element</h1>
|
||||
--fcc-editable-region--
|
||||
<video width="640" loop>
|
||||
--fcc-editable-region--
|
||||
</video>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
---
|
||||
id: 68f1f8c248306da204655117
|
||||
title: Step 6
|
||||
challengeType: 0
|
||||
dashedName: step-6
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
The `muted` attribute will silence audio on initial playback. If you have `controls` enabled, the user will be able to unmute audio. Omitting the `muted` attribute will play audio on initial playback.
|
||||
|
||||
The `muted` attribute is a boolean attribute and does not need a value.
|
||||
|
||||
Add the `muted` attribute to the `video` element.
|
||||
|
||||
# --hints--
|
||||
|
||||
Your `video` element should have the `muted` attribute.
|
||||
|
||||
```js
|
||||
const video = document.querySelector('video');
|
||||
assert.isTrue(video?.hasAttribute('muted'));
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Working with the HTML Video Element</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Working with the HTML Video Element</h1>
|
||||
--fcc-editable-region--
|
||||
<video width="640" loop controls>
|
||||
--fcc-editable-region--
|
||||
</video>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
---
|
||||
id: 68f1f993460f06a64c033061
|
||||
title: Step 7
|
||||
challengeType: 0
|
||||
dashedName: step-7
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
The `poster` attribute is a thumbnail image of the video. Think of the videos you watch on YouTube. It's displayed while the video is downloading. If the attribute is omitted, the first video frame is shown during the download phase.
|
||||
|
||||
Now, add the `poster` attribute with the value `https://cdn.freecodecamp.org/curriculum/labs/past-event2.jpg` to your `video` element.
|
||||
|
||||
# --hints--
|
||||
|
||||
Your `video` element should have the `poster` attribute with the value `https://cdn.freecodecamp.org/curriculum/labs/past-event2.jpg`.
|
||||
|
||||
```js
|
||||
const video = document.querySelector('video');
|
||||
assert.strictEqual(video?.getAttribute('poster'), 'https://cdn.freecodecamp.org/curriculum/labs/past-event2.jpg');
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Working with the HTML Video Element</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Working with the HTML Video Element</h1>
|
||||
--fcc-editable-region--
|
||||
<video
|
||||
width="640"
|
||||
loop
|
||||
controls
|
||||
muted
|
||||
>
|
||||
--fcc-editable-region--
|
||||
</video>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
---
|
||||
id: 68f1fac259a4afabb478b960
|
||||
title: Step 8
|
||||
challengeType: 0
|
||||
dashedName: step-8
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
You might have noticed you didn't link to the actual video. You will do that in the next phase. When it comes to video file types, there are differences in browser support. To accommodate this, you can use `source` elements inside the `video` element and the browser will select the first compatible `source`.
|
||||
|
||||
Here is an example of a `source` element:
|
||||
|
||||
```html
|
||||
<video controls width="250">
|
||||
<source src="src-url-goes-here" type="video-type-goes-here" />
|
||||
</video>
|
||||
```
|
||||
|
||||
The `source` element is a void element so it does not have a closing tag.
|
||||
|
||||
Add a `source` element inside of your `video` element.
|
||||
|
||||
|
||||
# --hints--
|
||||
|
||||
You should have a `source` element inside of your `video` element.
|
||||
|
||||
```js
|
||||
assert.exists(document.querySelector('video > source'));
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Working with the HTML Video Element</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Working with the HTML Video Element</h1>
|
||||
<video
|
||||
width="640"
|
||||
loop
|
||||
controls
|
||||
muted
|
||||
poster="https://cdn.freecodecamp.org/curriculum/labs/past-event2.jpg"
|
||||
>
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
</video>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
---
|
||||
id: 68f268880219c2485bd71d2a
|
||||
title: Step 9
|
||||
challengeType: 0
|
||||
dashedName: step-9
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
To specify the media resource for the video, you will need to add the `src` attribute to the `source` element.
|
||||
|
||||
Add the `src` attribute with the value `https://cdn.freecodecamp.org/curriculum/labs/what-is-the-map-method-and-how-does-it-work.mp4`.
|
||||
|
||||
# --hints--
|
||||
|
||||
Your `video` element should have a `src` attribute.
|
||||
|
||||
```js
|
||||
const source = document.querySelector('source');
|
||||
assert.isTrue(source?.hasAttribute('src'));
|
||||
```
|
||||
|
||||
Your `source` element should have a `src` attribute with the value `https://cdn.freecodecamp.org/curriculum/labs/what-is-the-map-method-and-how-does-it-work.mp4`.
|
||||
|
||||
```js
|
||||
const source = document.querySelector('source');
|
||||
assert.strictEqual(source?.getAttribute('src'),
|
||||
'https://cdn.freecodecamp.org/curriculum/labs/what-is-the-map-method-and-how-does-it-work.mp4');
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Working with the HTML Video Element</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Working with the HTML Video Element</h1>
|
||||
<video
|
||||
width="640"
|
||||
loop
|
||||
controls
|
||||
muted
|
||||
poster="https://cdn.freecodecamp.org/curriculum/labs/past-event2.jpg"
|
||||
>
|
||||
--fcc-editable-region--
|
||||
<source>
|
||||
--fcc-editable-region--
|
||||
</video>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
---
|
||||
id: 68f26a5f79e97c5032c10642
|
||||
title: Step 10
|
||||
challengeType: 0
|
||||
dashedName: step-10
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
You have used a video file with an `mp4` file extension, and you need to tell the browser that so it knows how to read the file.
|
||||
|
||||
You will use the `type` attribute to specify the `video/mp4` MIME type.
|
||||
|
||||
MIME (Multipurpose Internet Mail Extensions) is a standard to describe documents in other forms besides ASCII text, for example, audio, video, and images.
|
||||
|
||||
MP4, formally known as MPEG-4 Part 14, is a digital multimedia container format. It is widely used for storing video and audio, but it can also include other data types like subtitles and still images. MP4 files are designed for streaming over the Internet and are compatible with many devices and platforms.
|
||||
|
||||
Now, add the `type` attribute and the value `video/mp4`.
|
||||
|
||||
# --hints--
|
||||
|
||||
Your `source` element should have a `type` attribute.
|
||||
|
||||
```js
|
||||
const source = document.querySelector('source');
|
||||
assert.isTrue(source?.hasAttribute('type'));
|
||||
```
|
||||
|
||||
Your `source` element should have a `type` attribute with the value `video/mp4`.
|
||||
|
||||
```js
|
||||
const source = document.querySelector('source');
|
||||
assert.strictEqual(source?.getAttribute('type'), 'video/mp4');
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Working with the HTML Video Element</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Working with the HTML Video Element</h1>
|
||||
<video
|
||||
width="640"
|
||||
loop
|
||||
controls
|
||||
muted
|
||||
poster="https://cdn.freecodecamp.org/curriculum/labs/past-event2.jpg"
|
||||
>
|
||||
--fcc-editable-region--
|
||||
<source
|
||||
src="https://cdn.freecodecamp.org/curriculum/labs/what-is-the-map-method-and-how-does-it-work.mp4"
|
||||
|
||||
>
|
||||
--fcc-editable-region--
|
||||
</video>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
---
|
||||
id: 68f26d52b13e0f5b6e2d2e09
|
||||
title: Step 11
|
||||
challengeType: 0
|
||||
dashedName: step-11
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Another common MIME type is the `video/webm` MIME type.
|
||||
|
||||
WebM is an open-source audiovisual media file format developed by Google, primarily designed for web-based media content. It supports video codecs like VP8, VP9, and AV1, and audio codecs such as Vorbis and Opus, making it a popular choice for HTML5 video and audio elements.
|
||||
|
||||
Below your first `source` element, add another `source` element and give it a `src` attribute with the value `https://cdn.freecodecamp.org/curriculum/labs/mapmethod.webm` and a `type` attribute with the value `video/webm`.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should have a second `source` element.
|
||||
|
||||
```js
|
||||
assert.exists(document.querySelector('video > source:nth-of-type(2)'));
|
||||
```
|
||||
|
||||
Your second `source` element should have a `src` attribute.
|
||||
|
||||
```js
|
||||
const source = document.querySelector('source:nth-of-type(2)');
|
||||
assert.isTrue(source?.hasAttribute('src'));
|
||||
```
|
||||
|
||||
Your second `source` element should have a `src` attribute with a value of `https://cdn.freecodecamp.org/curriculum/labs/mapmethod.webm`.
|
||||
|
||||
```js
|
||||
const source = document.querySelector('source:nth-of-type(2)');
|
||||
assert.strictEqual(source?.getAttribute('src'), 'https://cdn.freecodecamp.org/curriculum/labs/mapmethod.webm');
|
||||
```
|
||||
|
||||
Your second `source` element should have a `type` attribute.
|
||||
|
||||
```js
|
||||
const source = document.querySelector('source:nth-of-type(2)');
|
||||
assert.isTrue(source?.hasAttribute('type'));
|
||||
```
|
||||
|
||||
Your second `source` element should have a `type` attribute with a value of `video/webm`.
|
||||
|
||||
```js
|
||||
const source = document.querySelector('source:nth-of-type(2)');
|
||||
assert.strictEqual(source?.getAttribute('type'), 'video/webm');
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Working with the HTML Video Element</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Working with the HTML Video Element</h1>
|
||||
<video
|
||||
width="640"
|
||||
loop
|
||||
controls
|
||||
muted
|
||||
poster="https://cdn.freecodecamp.org/curriculum/labs/past-event2.jpg"
|
||||
>
|
||||
<source
|
||||
src="https://cdn.freecodecamp.org/curriculum/labs/what-is-the-map-method-and-how-does-it-work.mp4"
|
||||
type="video/mp4"
|
||||
>
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
</video>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
+87
@@ -0,0 +1,87 @@
|
||||
---
|
||||
id: 68f2701b2160c765f23b60f8
|
||||
title: Step 12
|
||||
challengeType: 0
|
||||
dashedName: step-12
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Another common MIME type is the `video/ogg` MIME type.
|
||||
|
||||
Ogg is a digital multimedia container format designed to provide for efficient streaming and manipulation of digital multimedia. It is maintained by the Xiph.Org Foundation and is free and open, unrestricted by software patents. Its name is derived from "ogging", jargon from the computer game Netrek.
|
||||
|
||||
Below your second `source` element, add a third `source` element and give it a `src` attribute with the value `https://cdn.freecodecamp.org/curriculum/labs/mapmethod.ogg` and a `type` attribute with the value `video/ogg`.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should have a third `source` element.
|
||||
|
||||
```js
|
||||
assert.exists(document.querySelector('video > source:nth-of-type(3)'));
|
||||
```
|
||||
|
||||
Your third `source` element should have a `src` attribute.
|
||||
|
||||
```js
|
||||
const source = document.querySelector('source:nth-of-type(3)');
|
||||
assert.isTrue(source?.hasAttribute('src'));
|
||||
```
|
||||
|
||||
Your third `source` element should have a `src` attribute with a value of `https://cdn.freecodecamp.org/curriculum/labs/mapmethod.ogg`.
|
||||
|
||||
```js
|
||||
const source = document.querySelector('source:nth-of-type(3)');
|
||||
assert.strictEqual(source?.getAttribute('src'), 'https://cdn.freecodecamp.org/curriculum/labs/mapmethod.ogg');
|
||||
```
|
||||
|
||||
Your third `source` element should have a `type` attribute.
|
||||
|
||||
```js
|
||||
const source = document.querySelector('source:nth-of-type(3)');
|
||||
assert.isTrue(source?.hasAttribute('type'));
|
||||
```
|
||||
|
||||
Your third `source` element should have a `type` attribute with a value of `video/ogg`.
|
||||
|
||||
```js
|
||||
const source = document.querySelector('source:nth-of-type(3)');
|
||||
assert.strictEqual(source?.getAttribute('type'), 'video/ogg');
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Working with the HTML Video Element</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Working with the HTML Video Element</h1>
|
||||
<video
|
||||
width="640"
|
||||
loop
|
||||
controls
|
||||
muted
|
||||
poster="https://cdn.freecodecamp.org/curriculum/labs/past-event2.jpg"
|
||||
>
|
||||
<source
|
||||
src="https://cdn.freecodecamp.org/curriculum/labs/what-is-the-map-method-and-how-does-it-work.mp4"
|
||||
type="video/mp4"
|
||||
>
|
||||
<source
|
||||
src="https://cdn.freecodecamp.org/curriculum/labs/mapmethod.webm"
|
||||
type="video/webm"
|
||||
>
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
</video>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
+133
@@ -0,0 +1,133 @@
|
||||
---
|
||||
id: 68f27139bddf9f6bf2821acf
|
||||
title: Step 13
|
||||
challengeType: 0
|
||||
dashedName: step-13
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
The last `source` element you will add will be for the `video/quicktime` MIME type.
|
||||
|
||||
QuickTime is an extensible multimedia architecture created by Apple, which supports playing, streaming, encoding, and transcoding a variety of digital media formats. Not as popular as the MP4 format, you may need it for legacy application support.
|
||||
|
||||
Below your third `source` element, add a fourth `source` element and give it a `src` attribute with the value `https://cdn.freecodecamp.org/curriculum/labs/mapmethod.mov` and `type` attribute with the value `video/quicktime`.
|
||||
|
||||
Congratulations! You completed the HTML Video Player Workshop.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should have a fourth `source` element.
|
||||
|
||||
```js
|
||||
assert.exists(document.querySelector('video > source:nth-of-type(4)'));
|
||||
```
|
||||
|
||||
Your fourth `source` element should have a `src` attribute.
|
||||
|
||||
```js
|
||||
const source = document.querySelector('source:nth-of-type(4)');
|
||||
assert.isTrue(source?.hasAttribute('src'));
|
||||
```
|
||||
|
||||
Your fourth `source` element should have a `src` attribute with a value of `https://cdn.freecodecamp.org/curriculum/labs/mapmethod.mov`.
|
||||
|
||||
```js
|
||||
const source = document.querySelector('source:nth-of-type(4)');
|
||||
assert.strictEqual(source?.getAttribute('src'), 'https://cdn.freecodecamp.org/curriculum/labs/mapmethod.mov');
|
||||
```
|
||||
|
||||
Your fourth `source` element should have a `type` attribute.
|
||||
|
||||
```js
|
||||
const source = document.querySelector('source:nth-of-type(4)');
|
||||
assert.isTrue(source?.hasAttribute('type'));
|
||||
```
|
||||
|
||||
Your fourth `source` element should have a `type` attribute with a value of `video/quicktime`.
|
||||
|
||||
```js
|
||||
const source = document.querySelector('source:nth-of-type(4)');
|
||||
assert.strictEqual(source?.getAttribute('type'), 'video/quicktime');
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Working with the HTML Video Element</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Working with the HTML Video Element</h1>
|
||||
<video
|
||||
width="640"
|
||||
loop
|
||||
controls
|
||||
muted
|
||||
poster="https://cdn.freecodecamp.org/curriculum/labs/past-event2.jpg"
|
||||
>
|
||||
<source
|
||||
src="https://cdn.freecodecamp.org/curriculum/labs/what-is-the-map-method-and-how-does-it-work.mp4"
|
||||
type="video/mp4"
|
||||
>
|
||||
<source
|
||||
src="https://cdn.freecodecamp.org/curriculum/labs/mapmethod.webm"
|
||||
type="video/webm"
|
||||
>
|
||||
<source
|
||||
src="https://cdn.freecodecamp.org/curriculum/labs/mapmethod.ogg"
|
||||
type="video/ogg"
|
||||
>
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
</video>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Working with the HTML Video Element</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Working with the HTML Video Element</h1>
|
||||
<video
|
||||
width="640"
|
||||
controls
|
||||
loop
|
||||
muted
|
||||
poster="https://cdn.freecodecamp.org/curriculum/labs/past-event2.jpg"
|
||||
>
|
||||
<source
|
||||
src="https://cdn.freecodecamp.org/curriculum/labs/what-is-the-map-method-and-how-does-it-work.mp4"
|
||||
type="video/mp4"
|
||||
>
|
||||
<source
|
||||
src="https://cdn.freecodecamp.org/curriculum/labs/mapmethod.webm"
|
||||
type="video/webm"
|
||||
>
|
||||
<source
|
||||
src="https://cdn.freecodecamp.org/curriculum/labs/mapmethod.ogg"
|
||||
type="video/ogg"
|
||||
>
|
||||
<source
|
||||
src="https://cdn.freecodecamp.org/curriculum/labs/mapmethod.mov"
|
||||
type="video/quicktime"
|
||||
>
|
||||
</video>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"name": "Build an HTML Video Player",
|
||||
"isUpcomingChange": false,
|
||||
"dashedName": "workshop-html-video-player",
|
||||
"helpCategory": "HTML-CSS",
|
||||
"blockLayout": "challenge-grid",
|
||||
"challengeOrder": [
|
||||
{ "id": "68f18724d71db1dda8d6fec7", "title": "Step 1" },
|
||||
{ "id": "68f1eb9ad0a7575e4dbc31d5", "title": "Step 2" },
|
||||
{ "id": "68f1f371fefd448b4f70b898", "title": "Step 3" },
|
||||
{ "id": "68f1f57723debf9383c75947", "title": "Step 4" },
|
||||
{ "id": "68f1f6f97af9749a42260a43", "title": "Step 5" },
|
||||
{ "id": "68f1f8c248306da204655117", "title": "Step 6" },
|
||||
{ "id": "68f1f993460f06a64c033061", "title": "Step 7" },
|
||||
{ "id": "68f1fac259a4afabb478b960", "title": "Step 8" },
|
||||
{ "id": "68f268880219c2485bd71d2a", "title": "Step 9" },
|
||||
{ "id": "68f26a5f79e97c5032c10642", "title": "Step 10" },
|
||||
{ "id": "68f26d52b13e0f5b6e2d2e09", "title": "Step 11" },
|
||||
{ "id": "68f2701b2160c765f23b60f8", "title": "Step 12" },
|
||||
{ "id": "68f27139bddf9f6bf2821acf", "title": "Step 13" }
|
||||
],
|
||||
"blockLabel": "workshop",
|
||||
"usesMultifileEditor": true,
|
||||
"hasEditableBoundaries": true
|
||||
}
|
||||
@@ -18,6 +18,7 @@
|
||||
"lecture-understanding-how-html-affects-seo",
|
||||
"lab-travel-agency-page",
|
||||
"lecture-working-with-audio-and-video-elements",
|
||||
"workshop-html-video-player",
|
||||
"lab-html-audio-and-video-player",
|
||||
"lecture-working-with-images-and-svgs",
|
||||
"workshop-build-a-heart-icon",
|
||||
|
||||
Reference in New Issue
Block a user