diff --git a/curriculum/challenges/01-responsive-web-design/applied-accessibility/Add a Text Alternative to Images for Visually Impaired Accessibility.md b/curriculum/challenges/01-responsive-web-design/applied-accessibility/Add a Text Alternative to Images for Visually Impaired Accessibility.md new file mode 100644 index 0000000000..bccbd7a12c --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/applied-accessibility/Add a Text Alternative to Images for Visually Impaired Accessibility.md @@ -0,0 +1,54 @@ +--- +id: 587d774c367417b2b2512a9c +title: Add a Text Alternative to Images for Visually Impaired Accessibility +challengeType: 0 +videoUrl: 'https://scrimba.com/c/cPp7VfD' +guideUrl: 'https://guide.freecodecamp.org/certificates/add-alt-text-to-an-image-for-accessibility' +--- + +## Description +
+It's likely you've seen an alt attribute on an img tag in other challenges. Alt text describes the content of the image and provides a text-alternative. This helps in case the image fails to load or can't be seen by a user. It's also used by search engines to understand what an image contains to include it in search results. Here's an example: +<img src="importantLogo.jpeg" alt="Company logo"> +People with visual impairments rely on screen readers to convert web content to an audio interface. They won't get information if it's only presented visually. For images, screen readers can access the alt attribute and read its contents to deliver key information. +Good alt text is short but descriptive, and meant to briefly convey the meaning of the image. You should always include an alt attribute on your image. Per HTML5 specification, this is now considered mandatory. +
+ +## Instructions +
+Camper Cat happens to be both a coding ninja and an actual ninja, and is building a website to share his knowledge. The profile picture he wants to use shows his skills, and should be appreciated by all site visitors. Add an alt attribute in the img tag, that explains Camper Cat is doing karate. (The image src doesn't link to an actual file, so you should see the alt text in the display.) +
+ +## Tests +
+ +```yml +- text: 'Your img tag should have an alt attribute, and it should not be empty.' + testString: 'assert($("img").attr("alt"), "Your img tag should have an alt attribute, and it should not be empty.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + +``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/applied-accessibility/Add an Accessible Date Picker.md b/curriculum/challenges/01-responsive-web-design/applied-accessibility/Add an Accessible Date Picker.md new file mode 100644 index 0000000000..cdb79b713b --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/applied-accessibility/Add an Accessible Date Picker.md @@ -0,0 +1,82 @@ +--- +id: 587d778b367417b2b2512aa8 +title: Add an Accessible Date Picker +challengeType: 0 +videoUrl: 'https://scrimba.com/c/cD9DJHr' +--- + +## Description +
+Forms often include the input field, which can be used to create several different form controls. The type attribute on this element indicates what kind of input will be created. +You may have noticed the text and submit input types in prior challenges, and HTML5 introduced an option to specify a date field. Depending on browser support, a date picker shows up in the input field when it's in focus, which makes filling in a form easier for all users. +For older browsers, the type will default to text, so it helps to show users the expected date format in the label or as placeholder text just in case. +Here's an example: +
<label for="input1">Enter a date:</label>
<input type="date" id="input1" name="input1">
+
+ +## Instructions +
+Camper Cat is setting up a Mortal Kombat tournament and wants to ask his competitors to see what date works best. Add an input tag with a type attribute of "date", an id attribute of "pickdate", and a name attribute of "date". +
+ +## Tests +
+ +```yml +- text: Your code should add one input tag for the date selector field. + testString: 'assert($("input").length == 2, "Your code should add one input tag for the date selector field.");' +- text: Your input tag should have a type attribute with a value of date. + testString: 'assert($("input").attr("type") == "date", "Your input tag should have a type attribute with a value of date.");' +- text: Your input tag should have an id attribute with a value of pickdate. + testString: 'assert($("input").attr("id") == "pickdate", "Your input tag should have an id attribute with a value of pickdate.");' +- text: Your input tag should have a name attribute with a value of date. + testString: 'assert($("input").attr("name") == "date", "Your input tag should have a name attribute with a value of date.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + +
+

Tournaments

+
+
+
+

Mortal Kombat Tournament Survey

+
+

Tell us the best date for the competition

+ + + + + + + + + +
+
+
+ + +``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/applied-accessibility/Avoid Colorblindness Issues by Carefully Choosing Colors that Convey Information.md b/curriculum/challenges/01-responsive-web-design/applied-accessibility/Avoid Colorblindness Issues by Carefully Choosing Colors that Convey Information.md new file mode 100644 index 0000000000..d0f698a8fa --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/applied-accessibility/Avoid Colorblindness Issues by Carefully Choosing Colors that Convey Information.md @@ -0,0 +1,67 @@ +--- +id: 587d778f367417b2b2512aad +title: Avoid Colorblindness Issues by Carefully Choosing Colors that Convey Information +challengeType: 0 +videoUrl: 'https://scrimba.com/c/c437as3' +--- + +## Description +
+There are various forms of colorblindness. These can range from a reduced sensitivity to a certain wavelength of light to the inability to see color at all. The most common form is a reduced sensitivity to detect greens. +For example, if two similar green colors are the foreground and background color of your content, a colorblind user may not be able to distinguish them. Close colors can be thought of as neighbors on the color wheel, and those combinations should be avoided when conveying important information. +Note
Some online color picking tools include visual simulations of how colors appear for different types of colorblindness. These are great resources in addition to online contrast checking calculators. +
+ +## Instructions +
+Camper Cat is testing different styles for an important button, but the yellow (#FFFF33) background-color and the green (#33FF33) text color are neighboring hues on the color wheel and virtually indistinguishable for some colorblind users. (Their similar lightness also fails the contrast ratio check). Change the text color to a dark blue (#003366) to solve both problems. +
+ +## Tests +
+ +```yml +- text: Your code should change the text color for the button to the dark blue. + testString: 'assert($("button").css("color") == "rgb(0, 51, 102)", "Your code should change the text color for the button to the dark blue.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + + + + +
+

Danger!

+
+ + +``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/applied-accessibility/Avoid Colorblindness Issues by Using Sufficient Contrast.md b/curriculum/challenges/01-responsive-web-design/applied-accessibility/Avoid Colorblindness Issues by Using Sufficient Contrast.md new file mode 100644 index 0000000000..aa98e76344 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/applied-accessibility/Avoid Colorblindness Issues by Using Sufficient Contrast.md @@ -0,0 +1,74 @@ +--- +id: 587d778f367417b2b2512aac +title: Avoid Colorblindness Issues by Using Sufficient Contrast +challengeType: 0 +videoUrl: 'https://scrimba.com/c/cmzMEUw' +--- + +## Description +
+Color is a large part of visual design, but its use introduces two accessibility issues. First, color alone should not be used as the only way to convey important information because screen reader users won't see it. Second, foreground and background colors need sufficient contrast so colorblind users can distinguish them. +Previous challenges covered having text alternatives to address the first issue. The last challenge introduced contrast checking tools to help with the second. The WCAG-recommended contrast ratio of 4.5:1 applies for color use as well as gray-scale combinations. +Colorblind users have trouble distinguishing some colors from others - usually in hue but sometimes lightness as well. You may recall the contrast ratio is calculated using the relative luminance (or lightness) values of the foreground and background colors. +In practice, the 4.5:1 ratio can be reached by darkening the darker color and lightening the lighter one with the aid of a color contrast checker. Darker colors on the color wheel are considered to be blues, violets, magentas, and reds, whereas lighter colors are oranges, yellows, greens, and blue-greens. +
+ +## Instructions +
+Camper Cat is experimenting with using color for his blog text and background, but his current combination of a greenish background-color with maroon text color has a 2.5:1 contrast ratio. You can easily adjust the lightness of the colors since he declared them using the CSS hsl() property (which stands for hue, saturation, lightness) by changing the third argument. Increase the background-color lightness value from 35% to 55%, and decrease the color lightness value from 20% to 15%. This improves the contrast to 5.9:1. +
+ +## Tests +
+ +```yml +- text: Your code should only change the lightness value for the text color property to a value of 15%. + testString: 'assert(code.match(/color:\s*?hsl\(0,\s*?55%,\s*?15%\)/gi), "Your code should only change the lightness value for the text color property to a value of 15%.");' +- text: Your code should only change the lightness value for the background-color property to a value of 55%. + testString: 'assert(code.match(/background-color:\s*?hsl\(120,\s*?25%,\s*?55%\)/gi), "Your code should only change the lightness value for the background-color property to a value of 55%.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + + + + +
+

Deep Thoughts with Master Camper Cat

+
+
+

A Word on the Recent Catnip Doping Scandal

+

The influence that catnip has on feline behavior is well-documented, and its use as an herbal supplement in competitive ninja circles remains controversial. Once again, the debate to ban the substance is brought to the public's attention after the high-profile win of Kittytron, a long-time proponent and user of the green stuff, at the Claw of Fury tournament.

+

As I've stated in the past, I firmly believe a true ninja's skills must come from within, with no external influences. My own catnip use shall continue as purely recreational.

+
+ +``` + +
+ + + +
+ +## Solution +
+ + +```js +var code = "body {color: hsl(0, 55%, 15%); background-color: hsl(120, 25%, 55%);}" +``` + +
diff --git a/curriculum/challenges/01-responsive-web-design/applied-accessibility/Give Links Meaning by Using Descriptive Link Text.md b/curriculum/challenges/01-responsive-web-design/applied-accessibility/Give Links Meaning by Using Descriptive Link Text.md new file mode 100644 index 0000000000..417b15393f --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/applied-accessibility/Give Links Meaning by Using Descriptive Link Text.md @@ -0,0 +1,61 @@ +--- +id: 587d778f367417b2b2512aae +title: Give Links Meaning by Using Descriptive Link Text +challengeType: 0 +videoUrl: 'https://scrimba.com/c/c437DcV' +--- + +## Description +
+Screen reader users have different options for what type of content their device reads. This includes skipping to (or over) landmark elements, jumping to the main content, or getting a page summary from the headings. Another option is to only hear the links available on a page. +Screen readers do this by reading the link text, or what's between the anchor (a) tags. Having a list of "click here" or "read more" links isn't helpful. Instead, you should use brief but descriptive text within the a tags to provide more meaning for these users. +
+ +## Instructions +
+The link text that Camper Cat is using is not very descriptive without the surrounding context. Move the anchor (a) tags so they wrap around the text "information about batteries" instead of "Click here". +
+ +## Tests +
+ +```yml +- text: Your code should move the anchor a tags from around the words "Click here" to wrap around the words "information about batteries". + testString: 'assert($("a").text().match(/^(information about batteries)$/g), "Your code should move the anchor a tags from around the words "Click here" to wrap around the words "information about batteries".");' +- text: Make sure your a element has a closing tag. + testString: 'assert(code.match(/<\/a>/g) && code.match(/<\/a>/g).length === code.match(//g).length, "Make sure your a element has a closing tag.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + +
+

Deep Thoughts with Master Camper Cat

+
+
+ +``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/applied-accessibility/Improve Accessibility of Audio Content with the audio Element.md b/curriculum/challenges/01-responsive-web-design/applied-accessibility/Improve Accessibility of Audio Content with the audio Element.md new file mode 100644 index 0000000000..79a0086e36 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/applied-accessibility/Improve Accessibility of Audio Content with the audio Element.md @@ -0,0 +1,77 @@ +--- +id: 587d7789367417b2b2512aa4 +title: Improve Accessibility of Audio Content with the audio Element +challengeType: 0 +videoUrl: 'https://scrimba.com/c/cVJVkcZ' +--- + +## Description +
+HTML5's audio element gives semantic meaning when it wraps sound or audio stream content in your markup. Audio content also needs a text alternative to be accessible to people who are deaf or hard of hearing. This can be done with nearby text on the page or a link to a transcript. +The audio tag supports the controls attribute. This shows the browser default play, pause, and other controls, and supports keyboard functionality. This is a boolean attribute, meaning it doesn't need a value, its presence on the tag turns the setting on. +Here's an example: +
<audio id="meowClip" controls>
  <source src="audio/meow.mp3" type="audio/mpeg" />
  <source src="audio/meow.ogg" type="audio/ogg" />
</audio>
+Note
Multimedia content usually has both visual and auditory components. It needs synchronized captions and a transcript so users with visual and/or auditory impairments can access it. Generally, a web developer is not responsible for creating the captions or transcript, but needs to know to include them. +
+ +## Instructions +
+Time to take a break from Camper Cat and meet fellow camper Zersiax (@zersiax), a champion of accessibility and a screen reader user. To hear a clip of his screen reader in action, add an audio element after the p. Include the controls attribute. Then place a source tag inside the audio tags with the src attribute set to "https://s3.amazonaws.com/freecodecamp/screen-reader.mp3" and type attribute set to "audio/mpeg". +Note
The audio clip may sound fast and be difficult to understand, but that is a normal speed for screen reader users. +
+ +## Tests +
+ +```yml +- text: Your code should have one audio tag. + testString: 'assert($("audio").length === 1, "Your code should have one audio tag.");' +- text: Make sure your audio element has a closing tag. + testString: 'assert(code.match(/<\/audio>/g).length === 1 && code.match(/[\s\S]*<\/audio>/g), "Make sure your audio element has a closing tag.");' +- text: The audio tag should have the controls attribute. + testString: 'assert($("audio").attr("controls"), "The audio tag should have the controls attribute.");' +- text: Your code should have one source tag. + testString: 'assert($("source").length === 1, "Your code should have one source tag.");' +- text: Your source tag should be inside the audio tags. + testString: 'assert($("audio").children("source").length === 1, "Your source tag should be inside the audio tags.");' +- text: The value for the src attribute on the source tag should match the link in the instructions exactly. + testString: 'assert($("source").attr("src") === "https://s3.amazonaws.com/freecodecamp/screen-reader.mp3", "The value for the src attribute on the source tag should match the link in the instructions exactly.");' +- text: Your code should include a type attribute on the source tag with a value of audio/mpeg. + testString: 'assert($("source").attr("type") === "audio/mpeg", "Your code should include a type attribute on the source tag with a value of audio/mpeg.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + +
+

Real Coding Ninjas

+
+
+

A sound clip of Zersiax's screen reader in action.

+ + + +
+ +``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/applied-accessibility/Improve Chart Accessibility with the figure Element.md b/curriculum/challenges/01-responsive-web-design/applied-accessibility/Improve Chart Accessibility with the figure Element.md new file mode 100644 index 0000000000..cb7b3a2213 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/applied-accessibility/Improve Chart Accessibility with the figure Element.md @@ -0,0 +1,103 @@ +--- +id: 587d778a367417b2b2512aa5 +title: Improve Chart Accessibility with the figure Element +challengeType: 0 +videoUrl: 'https://scrimba.com/c/cGJMqtE' +--- + +## Description +
+HTML5 introduced the figure element, along with the related figcaption. Used together, these items wrap a visual representation (like an image, diagram, or chart) along with its caption. This gives a two-fold accessibility boost by both semantically grouping related content, and providing a text alternative that explains the figure. +For data visualizations like charts, the caption can be used to briefly note the trends or conclusions for users with visual impairments. Another challenge covers how to move a table version of the chart's data off-screen (using CSS) for screen reader users. +Here's an example - note that the figcaption goes inside the figure tags and can be combined with other elements: +
<figure>
  <img src="roundhouseDestruction.jpeg" alt="Photo of Camper Cat executing a roundhouse kick">
  <br>
  <figcaption>
    Master Camper Cat demonstrates proper form of a roundhouse kick.
  </figcaption>
</figure>
+
+ +## Instructions +
+Camper Cat is hard at work creating a stacked bar chart showing the amount of time per week to spend training in stealth, combat, and weapons. Help him structure his page better by changing the div tag he used to a figure tag, and the p tag that surrounds the caption to a figcaption tag. +
+ +## Tests +
+ +```yml +- text: Your code should have one figure tag. + testString: 'assert($("figure").length == 1, "Your code should have one figure tag.");' +- text: Your code should have one figcaption tag. + testString: 'assert($("figcaption").length == 1, "Your code should have one figcaption tag.");' +- text: Your code should not have any div tags. + testString: 'assert($("div").length == 0, "Your code should not have any div tags.");' +- text: Your code should not have any p tags. + testString: 'assert($("p").length == 0, "Your code should not have any p tags.");' +- text: The figcaption should be a child of the figure tag. + testString: 'assert($("figure").children("figcaption").length == 1, "The figcaption should be a child of the figure tag.");' +- text: Make sure your figure element has a closing tag. + testString: 'assert(code.match(/<\/figure>/g) && code.match(/<\/figure>/g).length === code.match(/
/g).length, "Make sure your figure element has a closing tag.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + +
+

Training

+ +
+
+
+ + +
+ +
+

Breakdown per week of time to spend training in stealth, combat, and weapons.

+
+ + +
+
+

Stealth & Agility Training

+

Climb foliage quickly using a minimum spanning tree approach

+

No training is NP-complete without parkour

+
+
+

Combat Training

+

Dispatch multiple enemies with multithreaded tactics

+

Goodbye world: 5 proven ways to knock out an opponent

+
+
+

Weapons Training

+

Swords: the best tool to literally divide and conquer

+

Breadth-first or depth-first in multi-weapon training?

+
+
+ + +``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/applied-accessibility/Improve Form Field Accessibility with the label Element.md b/curriculum/challenges/01-responsive-web-design/applied-accessibility/Improve Form Field Accessibility with the label Element.md new file mode 100644 index 0000000000..58781b4524 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/applied-accessibility/Improve Form Field Accessibility with the label Element.md @@ -0,0 +1,87 @@ +--- +id: 587d778a367417b2b2512aa6 +title: Improve Form Field Accessibility with the label Element +challengeType: 0 +videoUrl: 'https://scrimba.com/c/cGJMMAN' +--- + +## Description +
+Improving accessibility with semantic HTML markup applies to using both appropriate tag names as well as attributes. The next several challenges cover some important scenarios using attributes in forms. +The label tag wraps the text for a specific form control item, usually the name or label for a choice. This ties meaning to the item and makes the form more readable. The for attribute on a label tag explicitly associates that label with the form control and is used by screen readers. +You learned about radio buttons and their labels in a lesson in the Basic HTML section. In that lesson, we wrapped the radio button input element inside a label element along with the label text in order to make the text clickable. Another way to achieve this is by using the for attribute as explained in this lesson. +The value of the for attribute must be the same as the value of the id attribute of the form control. Here's an example: +
<form>
  <label for="name">Name:</label>
  <input type="text" id="name" name="name">
</form>
+
+ +## Instructions +
+Camper Cat expects a lot of interest in his thoughtful blog posts, and wants to include an email sign up form. Add a for attribute on the email label that matches the id on its input field. +
+ +## Tests +
+ +```yml +- text: Your code should have a for attribute on the label tag that is not empty. + testString: 'assert($("label").attr("for"), "Your code should have a for attribute on the label tag that is not empty.");' +- text: Your for attribute value should match the id value on the email input. + testString: 'assert($("label").attr("for") == "email", "Your for attribute value should match the id value on the email input.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + +
+

Deep Thoughts with Master Camper Cat

+
+
+
+

Sign up to receive Camper Cat's blog posts by email here!

+ + + + + + + +
+
+
+

The Garfield Files: Lasagna as Training Fuel?

+

The internet is littered with varying opinions on nutritional paradigms, from catnip paleo to hairball cleanses. But let's turn our attention to an often overlooked fitness fuel, and examine the protein-carb-NOM trifecta that is lasagna...

+
+ +
+

Defeating your Foe: the Red Dot is Ours!

+

Felines the world over have been waging war on the most persistent of foes. This red nemesis combines both cunning stealth and lightening speed. But chin up, fellow fighters, our time for victory may soon be near...

+
+ +
+

Is Chuck Norris a Cat Person?

+

Chuck Norris is widely regarded as the premier martial artist on the planet, and it's a complete coincidence anyone who disagrees with this fact mysteriously disappears soon after. But the real question is, is he a cat person?...

+
+ + +``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/applied-accessibility/Improve Readability with High Contrast Text.md b/curriculum/challenges/01-responsive-web-design/applied-accessibility/Improve Readability with High Contrast Text.md new file mode 100644 index 0000000000..b52705f7f7 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/applied-accessibility/Improve Readability with High Contrast Text.md @@ -0,0 +1,70 @@ +--- +id: 587d778e367417b2b2512aab +title: Improve Readability with High Contrast Text +challengeType: 0 +videoUrl: 'https://scrimba.com/c/cKb3nCq' +--- + +## Description +
+Low contrast between the foreground and background colors can make text difficult to read. Sufficient contrast improves the readability of your content, but what exactly does "sufficient" mean? +The Web Content Accessibility Guidelines (WCAG) recommend at least a 4.5 to 1 contrast ratio for normal text. The ratio is calculated by comparing the relative luminance values of two colors. This ranges from 1:1 for the same color, or no contrast, to 21:1 for white against black, the strongest contrast. There are many contrast checking tools available online that calculate this ratio for you. +
+ +## Instructions +
+Camper Cat's choice of light gray text on a white background for his recent blog post has a 1.5:1 contrast ratio, making it hard to read. Change the color of the text from the current gray (#D3D3D3) to a darker gray (#636363) to improve the contrast ratio to 6:1. +
+ +## Tests +
+ +```yml +- text: Your code should change the text color for the body to the darker gray. + testString: 'assert($("body").css("color") == "rgb(99, 99, 99)", "Your code should change the text color for the body to the darker gray.");' +- text: Your code should not change the background-color for the body. + testString: 'assert($("body").css("background-color") == "rgb(255, 255, 255)", "Your code should not change the background-color for the body.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + + + + +
+

Deep Thoughts with Master Camper Cat

+
+
+

A Word on the Recent Catnip Doping Scandal

+

The influence that catnip has on feline behavior is well-documented, and its use as an herbal supplement in competitive ninja circles remains controversial. Once again, the debate to ban the substance is brought to the public's attention after the high-profile win of Kittytron, a long-time proponent and user of the green stuff, at the Claw of Fury tournament.

+

As I've stated in the past, I firmly believe a true ninja's skills must come from within, with no external influences. My own catnip use shall continue as purely recreational.

+
+ +``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/applied-accessibility/Jump Straight to the Content Using the main Element.md b/curriculum/challenges/01-responsive-web-design/applied-accessibility/Jump Straight to the Content Using the main Element.md new file mode 100644 index 0000000000..0215cddabc --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/applied-accessibility/Jump Straight to the Content Using the main Element.md @@ -0,0 +1,61 @@ +--- +id: 587d774e367417b2b2512a9f +title: Jump Straight to the Content Using the main Element +challengeType: 0 +videoUrl: 'https://scrimba.com/c/cPp7zuE' +--- + +## Description +
+HTML5 introduced a number of new elements that give developers more options while also incorporating accessibility features. These tags include main, header, footer, nav, article, and section, among others. +By default, a browser renders these elements similarly to the humble div. However, using them where appropriate gives additional meaning in your markup. The tag name alone can indicate the type of information it contains, which adds semantic meaning to that content. Assistive technologies can access this information to provide better page summary or navigation options to their users. +The main element is used to wrap (you guessed it) the main content, and there should be only one per page. It's meant to surround the information that's related to the central topic of your page. It's not meant to include items that repeat across pages, like navigation links or banners. +The main tag also has an embedded landmark feature that assistive technology can use to quickly navigate to the main content. If you've ever seen a "Jump to Main Content" link at the top of a page, using a main tag automatically gives assistive devices that functionality. +
+ +## Instructions +
+Camper Cat has some big ideas for his ninja weapons page. Help him set up his markup by adding opening and closing main tags between the header and footer (covered in other challenges). Keep the main tags empty for now. +
+ +## Tests +
+ +```yml +- text: Your code should have one main tag. + testString: 'assert($("main").length == 1, "Your code should have one main tag.");' +- text: The main tags should be between the closing header tag and the opening footer tag. + testString: 'assert(code.match(/<\/header>\s*?
\s*?<\/main>/gi), "The main tags should be between the closing header tag and the opening footer tag.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html +
+

Weapons of the Ninja

+
+ + + + +``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/applied-accessibility/Know When Alt Text Should be Left Blank.md b/curriculum/challenges/01-responsive-web-design/applied-accessibility/Know When Alt Text Should be Left Blank.md new file mode 100644 index 0000000000..d8b97a4f63 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/applied-accessibility/Know When Alt Text Should be Left Blank.md @@ -0,0 +1,67 @@ +--- +id: 587d774c367417b2b2512a9d +title: Know When Alt Text Should be Left Blank +challengeType: 0 +videoUrl: 'https://scrimba.com/c/cM9P4t2' +--- + +## Description +
+In the last challenge, you learned that including an alt attribute on img tags is mandatory. However, sometimes images are grouped with a caption already describing them, or are used for decoration only. In these cases alt text may seem redundant or unnecessary. +In situations when an image is already explained with text content, or does not add meaning to a page, the img still needs an alt attribute, but it can be set to an empty string. Here's an example: +<img src="visualDecoration.jpeg" alt=""> +Background images usually fall under the 'decorative' label as well. However, they are typically applied with CSS rules, and therefore not part of the markup screen readers process. +Note
For images with a caption, you may still want to include alt text, since it helps search engines catalog the content of the image. +
+ +## Instructions +
+Camper Cat has coded a skeleton page for the blog part of his website. He's planning to add a visual break between his two articles with a decorative image of a samurai sword. Add an alt attribute to the img tag and set it to an empty string. (Note that the image src doesn't link to an actual file - don't worry that there are no swords showing in the display.) +
+ +## Tests +
+ +```yml +- text: Your img tag should have an alt attribute. + testString: 'assert(!($("img").attr("alt") == undefined), "Your img tag should have an alt attribute.");' +- text: The alt attribute should be set to an empty string. + testString: 'assert($("img").attr("alt") == "", "The alt attribute should be set to an empty string.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html +

Deep Thoughts with Master Camper Cat

+
+

Defeating your Foe: the Red Dot is Ours!

+

To Come...

+
+ + + +
+

Is Chuck Norris a Cat Person?

+

To Come...

+
+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/applied-accessibility/Make Elements Only Visible to a Screen Reader by Using Custom CSS.md b/curriculum/challenges/01-responsive-web-design/applied-accessibility/Make Elements Only Visible to a Screen Reader by Using Custom CSS.md new file mode 100644 index 0000000000..348b6f3eb9 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/applied-accessibility/Make Elements Only Visible to a Screen Reader by Using Custom CSS.md @@ -0,0 +1,147 @@ +--- +id: 587d778d367417b2b2512aaa +title: Make Elements Only Visible to a Screen Reader by Using Custom CSS +challengeType: 0 +videoUrl: 'https://scrimba.com/c/c8azdfM' +--- + +## Description +
+Have you noticed that all of the applied accessibility challenges so far haven't used any CSS? This is to show the importance of a logical document outline, and using semantically meaningful tags around your content before introducing the visual design aspect. +However, CSS's magic can also improve accessibility on your page when you want to visually hide content meant only for screen readers. This happens when information is in a visual format (like a chart), but screen reader users need an alternative presentation (like a table) to access the data. CSS is used to position the screen reader-only elements off the visual area of the browser window. +Here's an example of the CSS rules that accomplish this: +
.sr-only {
  position: absolute;
  left: -10000px;
  width: 1px;
  height: 1px;
  top: auto;
  overflow: hidden;
}
+Note
The following CSS approaches will NOT do the same thing: + +
+ +## Instructions +
+Camper Cat created a really cool stacked bar chart for his training page, and put the data into a table for his visually impaired users. The table already has an sr-only class, but the CSS rules aren't filled in yet. Give the position an absolute value, the left a -10000px value, and the width and height both 1px values. +
+ +## Tests +
+ +```yml +- text: Your code should set the position property of the sr-only class to a value of absolute. + testString: 'assert($(".sr-only").css("position") == "absolute", "Your code should set the position property of the sr-only class to a value of absolute.");' +- text: Your code should set the left property of the sr-only class to a value of -10000px. + testString: 'assert($(".sr-only").css("left") == "-10000px", "Your code should set the left property of the sr-only class to a value of -10000px.");' +- text: Your code should set the width property of the sr-only class to a value of 1 pixel. + testString: 'assert(code.match(/width:\s*?1px/gi), "Your code should set the width property of the sr-only class to a value of 1 pixel.");' +- text: Your code should set the height property of the sr-only class to a value of 1 pixel. + testString: 'assert(code.match(/height:\s*?1px/gi), "Your code should set the height property of the sr-only class to a value of 1 pixel.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + + + + +
+

Training

+ +
+
+

Master Camper Cat's Beginner Three Week Training Program

+
+ +

[Stacked bar chart]

+
+
Breakdown per week of time to spend training in stealth, combat, and weapons.
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Hours of Weekly Training in Stealth, Combat, and Weapons
Stealth & AgilityCombatWeaponsTotal
Week One35210
Week Two45312
Week Three46313
+
+
+

Stealth & Agility Training

+

Climb foliage quickly using a minimum spanning tree approach

+

No training is NP-complete without parkour

+
+
+

Combat Training

+

Dispatch multiple enemies with multithreaded tactics

+

Goodbye, world: 5 proven ways to knock out an opponent

+
+
+

Weapons Training

+

Swords: the best tool to literally divide and conquer

+

Breadth-first or depth-first in multi-weapon training?

+
+ + +``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/applied-accessibility/Make Links Navigatable with HTML Access Keys.md b/curriculum/challenges/01-responsive-web-design/applied-accessibility/Make Links Navigatable with HTML Access Keys.md new file mode 100644 index 0000000000..19fb8deab2 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/applied-accessibility/Make Links Navigatable with HTML Access Keys.md @@ -0,0 +1,80 @@ +--- +id: 587d7790367417b2b2512aaf +title: Make Links Navigatable with HTML Access Keys +challengeType: 0 +videoUrl: 'https://scrimba.com/c/cQvmaTp' +--- + +## Description +
+HTML offers the accesskey attribute to specify a shortcut key to activate or bring focus to an element. This can make navigation more efficient for keyboard-only users. +HTML5 allows this attribute to be used on any element, but it's particularly useful when it's used with interactive ones. This includes links, buttons, and form controls. +Here's an example: +<button accesskey="b">Important Button</button> +
+ +## Instructions +
+Camper Cat wants the links around the two blog article titles to have keyboard shortcuts so his site's users can quickly navigate to the full story. Add an accesskey attribute to both links and set the first one to "g" (for Garfield) and the second one to "c" (for Chuck Norris). +
+ +## Tests +
+ +```yml +- text: Your code should add an accesskey attribute to the a tag with the id of "first". + testString: 'assert($("#first").attr("accesskey"), "Your code should add an accesskey attribute to the a tag with the id of "first".");' +- text: Your code should add an accesskey attribute to the a tag with the id of "second". + testString: 'assert($("#second").attr("accesskey"), "Your code should add an accesskey attribute to the a tag with the id of "second".");' +- text: Your code should set the accesskey attribute on the a tag with the id of "first" to "g". Note that case matters. + testString: 'assert($("#first").attr("accesskey") == "g", "Your code should set the accesskey attribute on the a tag with the id of "first" to "g". Note that case matters.");' +- text: Your code should set the accesskey attribute on the a tag with the id of "second" to "c". Note that case matters. + testString: 'assert($("#second").attr("accesskey") == "c", "Your code should set the accesskey attribute on the a tag with the id of "second" to "c". Note that case matters.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + +
+

Deep Thoughts with Master Camper Cat

+
+
+ + +

The Garfield Files: Lasagna as Training Fuel?

+ + +

The internet is littered with varying opinions on nutritional paradigms, from catnip paleo to hairball cleanses. But let's turn our attention to an often overlooked fitness fuel, and examine the protein-carb-NOM trifecta that is lasagna...

+
+
+ + +

Is Chuck Norris a Cat Person?

+ + +

Chuck Norris is widely regarded as the premier martial artist on the planet, and it's a complete coincidence anyone who disagrees with this fact mysteriously disappears soon after. But the real question is, is he a cat person?...

+
+ + +``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/applied-accessibility/Make Screen Reader Navigation Easier with the footer Landmark.md b/curriculum/challenges/01-responsive-web-design/applied-accessibility/Make Screen Reader Navigation Easier with the footer Landmark.md new file mode 100644 index 0000000000..b4c584fe0a --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/applied-accessibility/Make Screen Reader Navigation Easier with the footer Landmark.md @@ -0,0 +1,87 @@ +--- +id: 587d7788367417b2b2512aa3 +title: Make Screen Reader Navigation Easier with the footer Landmark +challengeType: 0 +videoUrl: 'https://scrimba.com/c/crVrDh8' +--- + +## Description +
+Similar to header and nav, the footer element has a built-in landmark feature that allows assistive devices to quickly navigate to it. It's primarily used to contain copyright information or links to related documents that usually sit at the bottom of a page. +
+ +## Instructions +
+Camper Cat's training page is making good progress. Change the div he used to wrap his copyright information at the bottom of the page to a footer element. +
+ +## Tests +
+ +```yml +- text: Your code should have one footer tag. + testString: 'assert($("footer").length == 1, "Your code should have one footer tag.");' +- text: Your code should not have any div tags. + testString: 'assert($("div").length == 0, "Your code should not have any div tags.");' +- text: Your code should have an opening and closing footer tag. + testString: 'assert(code.match(/
+ +## Challenge Seed +
+ +
+ +```html + +
+

Training

+ +
+
+
+

Stealth & Agility Training

+

Climb foliage quickly using a minimum spanning tree approach

+

No training is NP-complete without parkour

+
+
+

Combat Training

+

Dispatch multiple enemies with multithreaded tactics

+

Goodbye world: 5 proven ways to knock out an opponent

+
+
+

Weapons Training

+

Swords: the best tool to literally divide and conquer

+

Breadth-first or depth-first in multi-weapon training?

+
+
+ + +
© 2018 Camper Cat
+ + + +``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/applied-accessibility/Make Screen Reader Navigation Easier with the header Landmark.md b/curriculum/challenges/01-responsive-web-design/applied-accessibility/Make Screen Reader Navigation Easier with the header Landmark.md new file mode 100644 index 0000000000..04820697a8 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/applied-accessibility/Make Screen Reader Navigation Easier with the header Landmark.md @@ -0,0 +1,82 @@ +--- +id: 587d7787367417b2b2512aa1 +title: Make Screen Reader Navigation Easier with the header Landmark +challengeType: 0 +videoUrl: 'https://scrimba.com/c/czVwWSv' +--- + +## Description +
+The next HTML5 element that adds semantic meaning and improves accessibility is the header tag. It's used to wrap introductory information or navigation links for its parent tag, and works well around content that's repeated at the top on multiple pages. +header shares the embedded landmark feature you saw with main, allowing assistive technologies to quickly navigate to that content. +Note
header is meant for use in the body tag of your HTML document. This is different than the head element, which contains the page's title, meta information, etc. +
+ +## Instructions +
+Camper Cat is writing some great articles about ninja training, and wants to add a page for them to his site. Change the top div that currently contains the h1 to a header tag instead. +
+ +## Tests +
+ +```yml +- text: Your code should have one header tag. + testString: 'assert($("header").length == 1, "Your code should have one header tag.");' +- text: Your header tags should wrap around the h1. + testString: 'assert($("header").children("h1").length == 1, "Your header tags should wrap around the h1.");' +- text: Your code should not have any div tags. + testString: 'assert($("div").length == 0, "Your code should not have any div tags.");' +- text: Make sure your header element has a closing tag. + testString: 'assert(code.match(/<\/header>/g) && code.match(/<\/header>/g).length === code.match(/
/g).length, "Make sure your header element has a closing tag.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + + +
+

Training with Camper Cat

+
+ + +
+
+

Stealth & Agility Training

+

Climb foliage quickly using a minimum spanning tree approach

+

No training is NP-complete without parkour

+
+
+

Combat Training

+

Dispatch multiple enemies with multithreaded tactics

+

Goodbye world: 5 proven ways to knock out an opponent

+
+
+

Weapons Training

+

Swords: the best tool to literally divide and conquer

+

Breadth-first or depth-first in multi-weapon training?

+
+
+ +``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/applied-accessibility/Make Screen Reader Navigation Easier with the nav Landmark.md b/curriculum/challenges/01-responsive-web-design/applied-accessibility/Make Screen Reader Navigation Easier with the nav Landmark.md new file mode 100644 index 0000000000..f1dd5caa7c --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/applied-accessibility/Make Screen Reader Navigation Easier with the nav Landmark.md @@ -0,0 +1,87 @@ +--- +id: 587d7788367417b2b2512aa2 +title: Make Screen Reader Navigation Easier with the nav Landmark +challengeType: 0 +videoUrl: 'https://scrimba.com/c/cB76vtv' +--- + +## Description +
+The nav element is another HTML5 item with the embedded landmark feature for easy screen reader navigation. This tag is meant to wrap around the main navigation links in your page. +If there are repeated site links at the bottom of the page, it isn't necessary to markup those with a nav tag as well. Using a footer (covered in the next challenge) is sufficient. +
+ +## Instructions +
+Camper Cat included navigation links at the top of his training page, but wrapped them in a div. Change the div to a nav tag to improve the accessibility on his page. +
+ +## Tests +
+ +```yml +- text: Your code should have one nav tag. + testString: 'assert($("nav").length == 1, "Your code should have one nav tag.");' +- text: Your nav tags should wrap around the ul and its list items. + testString: 'assert($("nav").children("ul").length == 1, "Your nav tags should wrap around the ul and its list items.");' +- text: Your code should not have any div tags. + testString: 'assert($("div").length == 0, "Your code should not have any div tags.");' +- text: Make sure your nav element has a closing tag. + testString: 'assert(code.match(/<\/nav>/g) && code.match(/<\/nav>/g).length === code.match(/
+ +## Challenge Seed +
+ +
+ +```html + +
+

Training with Camper Cat

+ +
+ +
+ +
+
+
+

Stealth & Agility Training

+

Climb foliage quickly using a minimum spanning tree approach

+

No training is NP-complete without parkour

+
+
+

Combat Training

+

Dispatch multiple enemies with multithreaded tactics

+

Goodbye world: 5 proven ways to knock out an opponent

+
+
+

Weapons Training

+

Swords: the best tool to literally divide and conquer

+

Breadth-first or depth-first in multi-weapon training?

+
+
+ +``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/applied-accessibility/Standardize Times with the HTML5 datetime Attribute.md b/curriculum/challenges/01-responsive-web-design/applied-accessibility/Standardize Times with the HTML5 datetime Attribute.md new file mode 100644 index 0000000000..0d052361f4 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/applied-accessibility/Standardize Times with the HTML5 datetime Attribute.md @@ -0,0 +1,88 @@ +--- +id: 587d778c367417b2b2512aa9 +title: Standardize Times with the HTML5 datetime Attribute +challengeType: 0 +videoUrl: 'https://scrimba.com/c/cmzMgtz' +--- + +## Description +
+Continuing with the date theme, HTML5 also introduced the time element along with a datetime attribute to standardize times. This is an inline element that can wrap a date or time on a page. A valid format of that date is held by the datetime attribute. This is the value accessed by assistive devices. It helps avoid confusion by stating a standardized version of a time, even if it's written in an informal or colloquial manner in the text. +Here's an example: +<p>Master Camper Cat officiated the cage match between Goro and Scorpion <time datetime="2013-02-13">last Wednesday</time>, which ended in a draw.</p> +
+ +## Instructions +
+Camper Cat's Mortal Kombat survey results are in! Wrap a time tag around the text "Thursday, September 15<sup>th</sup>" and add a datetime attribute to it set to "2016-09-15". +
+ +## Tests +
+ +```yml +- text: 'Your time tags should wrap around the text "Thursday, September 15<sup>th</sup>".' + testString: 'assert($("time").text().match(/Thursday, September 15th/g), "Your time tags should wrap around the text "Thursday, September 15<sup>th</sup>".");' +- text: Your time tag should have a datetime attribute that is not empty. + testString: 'assert($("time").attr("datetime"), "Your time tag should have a datetime attribute that is not empty.");' +- text: Your datetime attribute should be set to a value of 2016-09-15. + testString: 'assert($("time").attr("datetime") === "2016-09-15", "Your datetime attribute should be set to a value of 2016-09-15.");' +- text: Make sure your time element has a closing tag. + testString: 'assert(code.match(/<\/time>/g) && code.match(/<\/time>/g).length === 4, "Make sure your time element has a closing tag.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + +
+

Tournaments

+
+
+

Mortal Kombat Tournament Survey Results

+ + + +

Thank you to everyone for responding to Master Camper Cat's survey. The best day to host the vaunted Mortal Kombat tournament is Thursday, September 15th. May the best ninja win!

+ + + +
+

Comments:

+
+

Posted by: Sub-Zero on

+

Johnny Cage better be there, I'll finish him!

+
+
+

Posted by: Doge on

+

Wow, much combat, so mortal.

+
+
+

Posted by: The Grim Reaper on

+

Looks like I'll be busy that day.

+
+
+
+ + +``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/applied-accessibility/Use Headings to Show Hierarchical Relationships of Content.md b/curriculum/challenges/01-responsive-web-design/applied-accessibility/Use Headings to Show Hierarchical Relationships of Content.md new file mode 100644 index 0000000000..6bb11d2a3c --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/applied-accessibility/Use Headings to Show Hierarchical Relationships of Content.md @@ -0,0 +1,70 @@ +--- +id: 587d774d367417b2b2512a9e +title: Use Headings to Show Hierarchical Relationships of Content +challengeType: 0 +videoUrl: 'https://scrimba.com/c/cqVEktm' +--- + +## Description +
+Headings (h1 through h6 elements) are workhorse tags that help provide structure and labeling to your content. Screen readers can be set to read only the headings on a page so the user gets a summary. This means it is important for the heading tags in your markup to have semantic meaning and relate to each other, not be picked merely for their size values. +Semantic meaning means that the tag you use around content indicates the type of information it contains. +If you were writing a paper with an introduction, a body, and a conclusion, it wouldn't make much sense to put the conclusion as a subsection of the body in your outline. It should be its own section. Similarly, the heading tags in a webpage need to go in order and indicate the hierarchical relationships of your content. +Headings with equal (or higher) rank start new implied sections, headings with lower rank start subsections of the previous one. +As an example, a page with an h2 element followed by several subsections labeled with h4 tags would confuse a screen reader user. With six choices, it's tempting to use a tag because it looks better in a browser, but you can use CSS to edit the relative sizing. +One final point, each page should always have one (and only one) h1 element, which is the main subject of your content. This and the other headings are used in part by search engines to understand the topic of the page. +
+ +## Instructions +
+Camper Cat wants a page on his site dedicated to becoming a ninja. Help him fix the headings so his markup gives semantic meaning to the content, and shows the proper parent-child relationships of his sections. Change all the h5 tags to the proper heading level to indicate they are subsections of the h2 ones. +
+ +## Tests +
+ +```yml +- text: Your code should have six h3 tags. + testString: 'assert($("h3").length === 6, "Your code should have six h3 tags.");' +- text: Your code should not have any h5 tags. + testString: 'assert($("h5").length === 0, "Your code should not have any h5 tags.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html +

How to Become a Ninja

+
+

Learn the Art of Moving Stealthily

+
How to Hide in Plain Sight
+
How to Climb a Wall
+ +

Learn the Art of Battle

+
How to Strengthen your Body
+
How to Fight like a Ninja
+ +

Learn the Art of Living with Honor

+
How to Breathe Properly
+
How to Simplify your Life
+
+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/applied-accessibility/Use tabindex to Add Keyboard Focus to an Element.md b/curriculum/challenges/01-responsive-web-design/applied-accessibility/Use tabindex to Add Keyboard Focus to an Element.md new file mode 100644 index 0000000000..ddbca5717f --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/applied-accessibility/Use tabindex to Add Keyboard Focus to an Element.md @@ -0,0 +1,101 @@ +--- +id: 587d7790367417b2b2512ab0 +title: Use tabindex to Add Keyboard Focus to an Element +challengeType: 0 +videoUrl: 'https://scrimba.com/c/cmzMDHW' +--- + +## Description +
+The HTML tabindex attribute has three distinct functions relating to an element's keyboard focus. When it's on a tag, it indicates that element can be focused on. The value (an integer that's positive, negative, or zero) determines the behavior. +Certain elements, such as links and form controls, automatically receive keyboard focus when a user tabs through a page. It's in the same order as the elements come in the HTML source markup. This same functionality can be given to other elements, such as div, span, and p, by placing a tabindex="0" attribute on them. Here's an example: +<div tabindex="0">I need keyboard focus!</div> +Note
A negative tabindex value (typically -1) indicates that an element is focusable, but is not reachable by the keyboard. This method is generally used to bring focus to content programmatically (like when a div used for a pop-up window is activated), and is beyond the scope of these challenges. +
+ +## Instructions +
+Camper Cat created a new survey to collect information about his users. He knows input fields automatically get keyboard focus, but he wants to make sure his keyboard users pause at the instructions while tabbing through the items. Add a tabindex attribute to the p tag and set its value to "0". Bonus - using tabindex also enables the CSS pseudo-class :focus to work on the p tag. +
+ +## Tests +
+ +```yml +- text: Your code should add a tabindex attribute to the p tag that holds the form instructions. + testString: 'assert($("p").attr("tabindex"), "Your code should add a tabindex attribute to the p tag that holds the form instructions.");' +- text: Your code should set the tabindex attribute on the p tag to a value of 0. + testString: 'assert($("p").attr("tabindex") == "0", "Your code should set the tabindex attribute on the p tag to a value of 0.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + + + + +
+

Ninja Survey

+
+
+
+ + +

Instructions: Fill in ALL your information then click Submit

+ + + +
+
+ What level ninja are you? + +
+ +
+ + +
+
+
+ Select your favorite weapons: + +
+ +
+ +
+ + +
+
+ +

+
+ + +``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/applied-accessibility/Use tabindex to Specify the Order of Keyboard Focus for Several Elements.md b/curriculum/challenges/01-responsive-web-design/applied-accessibility/Use tabindex to Specify the Order of Keyboard Focus for Several Elements.md new file mode 100644 index 0000000000..0ec47359e4 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/applied-accessibility/Use tabindex to Specify the Order of Keyboard Focus for Several Elements.md @@ -0,0 +1,91 @@ +--- +id: 587d7790367417b2b2512ab1 +title: Use tabindex to Specify the Order of Keyboard Focus for Several Elements +challengeType: 0 +videoUrl: 'https://scrimba.com/c/cmzRRcb' +--- + +## Description +
+The tabindex attribute also specifies the exact tab order of elements. This is achieved when the value of the attribute is set to a positive number of 1 or higher. +Setting a tabindex="1" will bring keyboard focus to that element first. Then it cycles through the sequence of specified tabindex values (2, 3, etc.), before moving to default and tabindex="0" items. +It's important to note that when the tab order is set this way, it overrides the default order (which uses the HTML source). This may confuse users who are expecting to start navigation from the top of the page. This technique may be necessary in some circumstances, but in terms of accessibility, take care before applying it. +Here's an example: +<div tabindex="1">I get keyboard focus, and I get it first!</div> +<div tabindex="2">I get keyboard focus, and I get it second!</div> +
+ +## Instructions +
+Camper Cat has a search field on his Inspirational Quotes page that he plans to position in the upper right corner with CSS. He wants the search input and submit input form controls to be the first two items in the tab order. Add a tabindex attribute set to "1" to the search input, and a tabindex attribute set to "2" to the submit input. +
+ +## Tests +
+ +```yml +- text: Your code should add a tabindex attribute to the search input tag. + testString: 'assert($("#search").attr("tabindex"), "Your code should add a tabindex attribute to the search input tag.");' +- text: Your code should add a tabindex attribute to the submit input tag. + testString: 'assert($("#submit").attr("tabindex"), "Your code should add a tabindex attribute to the submit input tag.");' +- text: Your code should set the tabindex attribute on the search input tag to a value of 1. + testString: 'assert($("#search").attr("tabindex") == "1", "Your code should set the tabindex attribute on the search input tag to a value of 1.");' +- text: Your code should set the tabindex attribute on the submit input tag to a value of 2. + testString: 'assert($("#submit").attr("tabindex") == "2", "Your code should set the tabindex attribute on the submit input tag to a value of 2.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + +
+

Even Deeper Thoughts with Master Camper Cat

+ +
+
+ + + + + + + +
+

Inspirational Quotes

+
+

“There's no Theory of Evolution, just a list of creatures I've allowed to live.”
+ - Chuck Norris

+
+
+

“Wise men say forgiveness is divine, but never pay full price for late pizza.”
+ - TMNT

+
+ + +``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/applied-accessibility/Wrap Content in the article Element.md b/curriculum/challenges/01-responsive-web-design/applied-accessibility/Wrap Content in the article Element.md new file mode 100644 index 0000000000..e49b93151a --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/applied-accessibility/Wrap Content in the article Element.md @@ -0,0 +1,76 @@ +--- +id: 587d774e367417b2b2512aa0 +title: Wrap Content in the article Element +challengeType: 0 +videoUrl: 'https://scrimba.com/c/cPp79S3' +--- + +## Description +
+article is another one of the new HTML5 elements that adds semantic meaning to your markup. Article is a sectioning element, and is used to wrap independent, self-contained content. The tag works well with blog entries, forum posts, or news articles. +Determining whether content can stand alone is usually a judgement call, but there are a couple simple tests you can use. Ask yourself if you removed all surrounding context, would that content still make sense? Similarly for text, would the content hold up if it were in an RSS feed? +Remember that folks using assistive technologies rely on organized, semantically meaningful markup to better understand your work. +Note about section and div
The section element is also new with HTML5, and has a slightly different semantic meaning than article. An article is for standalone content, and a section is for grouping thematically related content. They can be used within each other, as needed. For example, if a book is the article, then each chapter is a section. When there's no relationship between groups of content, then use a div. +
<div> - groups content
<section> - groups related content
<article> - groups independent, self-contained content
+
+ +## Instructions +
+Camper Cat used article tags to wrap the posts on his blog page, but he forgot to use them around the top one. Change the div tag to use an article tag instead. +
+ +## Tests +
+ +```yml +- text: Your code should have three article tags. + testString: 'assert($("article").length == 3, "Your code should have three article tags.");' +- text: Your code should not have any div tags. + testString: 'assert($("div").length == 0, "Your code should not have any div tags.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html +

Deep Thoughts with Master Camper Cat

+
+
+

The Garfield Files: Lasagna as Training Fuel?

+

The internet is littered with varying opinions on nutritional paradigms, from catnip paleo to hairball cleanses. But let's turn our attention to an often overlooked fitness fuel, and examine the protein-carb-NOM trifecta that is lasagna...

+
+ + + +
+

Defeating your Foe: the Red Dot is Ours!

+

Felines the world over have been waging war on the most persistent of foes. This red nemesis combines both cunning stealth and lightening speed. But chin up, fellow fighters, our time for victory may soon be near...

+
+ + + +
+

Is Chuck Norris a Cat Person?

+

Chuck Norris is widely regarded as the premier martial artist on the planet, and it's a complete coincidence anyone who disagrees with this fact mysteriously disappears soon after. But the real question is, is he a cat person?...

+
+
+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/applied-accessibility/Wrap Radio Buttons in a fieldset Element for Better Accessibility.md b/curriculum/challenges/01-responsive-web-design/applied-accessibility/Wrap Radio Buttons in a fieldset Element for Better Accessibility.md new file mode 100644 index 0000000000..26a3a0b460 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/applied-accessibility/Wrap Radio Buttons in a fieldset Element for Better Accessibility.md @@ -0,0 +1,104 @@ +--- +id: 587d778b367417b2b2512aa7 +title: Wrap Radio Buttons in a fieldset Element for Better Accessibility +challengeType: 0 +videoUrl: 'https://scrimba.com/c/cVJVefw' +--- + +## Description +
+The next form topic covers accessibility of radio buttons. Each choice is given a label with a for attribute tying to the id of the corresponding item as covered in the last challenge. Since radio buttons often come in a group where the user must choose one, there's a way to semantically show the choices are part of a set. +The fieldset tag surrounds the entire grouping of radio buttons to achieve this. It often uses a legend tag to provide a description for the grouping, which is read by screen readers for each choice in the fieldset element. +The fieldset wrapper and legend tag are not necessary when the choices are self-explanatory, like a gender selection. Using a label with the for attribute for each radio button is sufficient. +Here's an example: +
<form>
  <fieldset>
    <legend>Choose one of these three items:</legend>
    <input id="one" type="radio" name="items" value="one">
    <label for="one">Choice One</label><br>
    <input id="two" type="radio" name="items" value="two">
    <label for="two">Choice Two</label><br>
    <input id="three" type="radio" name="items" value="three">
    <label for="three">Choice Three</label>
  </fieldset>
</form>
+
+ +## Instructions +
+Camper Cat wants information about the ninja level of his users when they sign up for his email list. He's added a set of radio buttons, and learned from our last lesson to use label tags with for attributes for each choice. Go Camper Cat! However, his code still needs some help. Change the div tag surrounding the radio buttons to a fieldset tag, and change the p tag inside it to a legend. +
+ +## Tests +
+ +```yml +- text: Your code should have a fieldset tag around the radio button set. + testString: 'assert($("fieldset").length == 1, "Your code should have a fieldset tag around the radio button set.");' +- text: Make sure your fieldset element has a closing tag. + testString: 'assert(code.match(/<\/fieldset>/g) && code.match(/<\/fieldset>/g).length === code.match(/
/g).length, "Make sure your fieldset element has a closing tag.");' +- text: Your code should have a legend tag around the text asking what level ninja a user is. + testString: 'assert($("legend").length == 1, "Your code should have a legend tag around the text asking what level ninja a user is.");' +- text: Your code should not have any div tags. + testString: 'assert($("div").length == 0, "Your code should not have any div tags.");' +- text: Your code should no longer have a p tag around the text asking what level ninja a user is. + testString: 'assert($("p").length == 4, "Your code should no longer have a p tag around the text asking what level ninja a user is.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + +
+

Deep Thoughts with Master Camper Cat

+
+
+
+

Sign up to receive Camper Cat's blog posts by email here!

+ + + + + +
+

What level ninja are you?

+ +
+ +
+ + +
+ + + + +
+
+
+

The Garfield Files: Lasagna as Training Fuel?

+

The internet is littered with varying opinions on nutritional paradigms, from catnip paleo to hairball cleanses. But let's turn our attention to an often overlooked fitness fuel, and examine the protein-carb-NOM trifecta that is lasagna...

+
+ +
+

Defeating your Foe: the Red Dot is Ours!

+

Felines the world over have been waging war on the most persistent of foes. This red nemesis combines both cunning stealth and lightening speed. But chin up, fellow fighters, our time for victory may soon be near...

+
+ +
+

Is Chuck Norris a Cat Person?

+

Chuck Norris is widely regarded as the premier martial artist on the planet, and it's a complete coincidence anyone who disagrees with this fact mysteriously disappears soon after. But the real question is, is he a cat person?...

+
+ + +``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/applied-accessibility/meta.json b/curriculum/challenges/01-responsive-web-design/applied-accessibility/meta.json new file mode 100644 index 0000000000..3909bc971e --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/applied-accessibility/meta.json @@ -0,0 +1,8 @@ +{ + "name": "Applied Accessibility", + "dashedName": "applied-accessibility", + "order": 3, + "time": "5 hours", + "superBlock": "responsive-web-design", + "superOrder": 1 +} \ No newline at end of file diff --git a/curriculum/challenges/01-responsive-web-design/applied-visual-design/Add a box-shadow to a Card-like Element.md b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Add a box-shadow to a Card-like Element.md new file mode 100644 index 0000000000..ad98bc71f0 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Add a box-shadow to a Card-like Element.md @@ -0,0 +1,100 @@ +--- +id: 587d781b367417b2b2512abe +title: Add a box-shadow to a Card-like Element +challengeType: 0 +videoUrl: 'https://scrimba.com/c/cvVZdUd' +--- + +## Description +
+The box-shadow property applies one or more shadows to an element. +The box-shadow property takes values for offset-x (how far to push the shadow horizontally from the element), offset-y (how far to push the shadow vertically from the element), blur-radius, spread-radius and a color value, in that order. The blur-radius and spread-radius values are optional. +Here's an example of the CSS to create multiple shadows with some blur, at mostly-transparent black colors: +
box-shadow: 0 10px 20px rgba(0,0,0,0.19), 0 6px 6px rgba(0,0,0,0.23);
+
+ +## Instructions +
+The element now has an id of thumbnail. With this selector, use the example CSS values above to place a box-shadow on the card. +
+ +## Tests +
+ +```yml +- text: Your code should add a box-shadow property for the thumbnail id. + testString: 'assert(code.match(/#thumbnail\s*?{\s*?box-shadow/g), "Your code should add a box-shadow property for the thumbnail id.");' +- text: You should use the given CSS for the box-shadow value. + testString: 'assert(code.match(/box-shadow:\s*?0\s+?10px\s+?20px\s+?rgba\(\s*?0\s*?,\s*?0\s*?,\s*?0\s*?,\s*?0?\.19\),\s*?0\s+?6px\s+?6px\s+?rgba\(\s*?0\s*?,\s*?0\s*?,\s*?0\s*?,\s*?0?\.23\)/gi), "You should use the given CSS for the box-shadow value.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + +
+
+
+

Alphabet

+
+

Google was founded by Larry Page and Sergey Brin while they were Ph.D. students at Stanford University.

+
+ +
+
+``` + +
+ + + +
+ +## Solution +
+ + +```js +var code = "#thumbnail {box-shadow: 0 10px 20px rgba(0,0,0,0.19), 0 6px 6px rgba(0,0,0,0.23);}" +``` + +
diff --git a/curriculum/challenges/01-responsive-web-design/applied-visual-design/Adjust the Color of Various Elements to Complementary Colors.md b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Adjust the Color of Various Elements to Complementary Colors.md new file mode 100644 index 0000000000..dcd1f11cfa --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Adjust the Color of Various Elements to Complementary Colors.md @@ -0,0 +1,93 @@ +--- +id: 587d78a4367417b2b2512ad3 +title: Adjust the Color of Various Elements to Complementary Colors +challengeType: 0 +videoUrl: 'https://scrimba.com/c/cWmPpud' +--- + +## Description +
+The Complementary Colors challenge showed that opposite colors on the color wheel can make each other appear more vibrant when placed side-by-side. However, the strong visual contrast can be jarring if it's overused on a website, and can sometimes make text harder to read if it's placed on a complementary-colored background. In practice, one of the colors is usually dominant and the complement is used to bring visual attention to certain content on the page. +
+ +## Instructions +
+This page will use a shade of teal (#09A7A1) as the dominant color, and its orange (#FF790E) complement to visually highlight the sign-up buttons. Change the background-color of both the header and footer from black to the teal color. Then change the h2 text color to teal as well. Finally, change the background-color of the button to the orange color. +
+ +## Tests +
+ +```yml +- text: 'The header element should have a background-color of #09A7A1.' + testString: 'assert($("header").css("background-color") == "rgb(9, 167, 161)", "The header element should have a background-color of #09A7A1.");' +- text: 'The footer element should have a background-color of #09A7A1.' + testString: 'assert($("footer").css("background-color") == "rgb(9, 167, 161)", "The footer element should have a background-color of #09A7A1.");' +- text: 'The h2 element should have a color of #09A7A1.' + testString: 'assert($("h2").css("color") == "rgb(9, 167, 161)", "The h2 element should have a color of #09A7A1.");' +- text: 'The button element should have a background-color of #FF790E.' + testString: 'assert($("button").css("background-color") == "rgb(255, 121, 14)", "The button element should have a background-color of #FF790E.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + +
+

Cooking with FCC!

+
+
+
+

Machine Learning in the Kitchen

+

Join this two day workshop that walks through how to implement cutting-edge snack-getting algorithms with a command line interface. Coding usually involves writing exact instructions, but sometimes you need your computer to execute flexible commands, like fetch Pringles.

+ +
+
+

Bisection Vegetable Chopping

+

This week-long retreat will level-up your coding ninja skills to actual ninja skills. No longer is the humble bisection search limited to sorted arrays or coding interview questions, applying its concepts in the kitchen will have you chopping carrots in O(log n) time before you know it.

+ +
+
+
+ +``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/applied-visual-design/Adjust the Height of an Element Using the height Property.md b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Adjust the Height of an Element Using the height Property.md new file mode 100644 index 0000000000..55972a8597 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Adjust the Height of an Element Using the height Property.md @@ -0,0 +1,85 @@ +--- +id: 587d7791367417b2b2512ab5 +title: Adjust the Height of an Element Using the height Property +challengeType: 0 +videoUrl: 'https://scrimba.com/c/cEDaDTN' +--- + +## Description +
+You can specify the height of an element using the height property in CSS, similar to the width property. Here's an example that changes the height of an image to 20px: +
img {
  height: 20px;
}
+
+ +## Instructions +
+Add a height property to the h4 tag and set it to 25px. +
+ +## Tests +
+ +```yml +- text: Your code should change the h4 height property to a value of 25 pixels. + testString: 'assert($("h4").css("height") == "25px", "Your code should change the h4 height property to a value of 25 pixels.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + +
+
+
+

Google

+

Google was founded by Larry Page and Sergey Brin while they were Ph.D. students at Stanford University.

+
+ +
+
+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/applied-visual-design/Adjust the Hover State of an Anchor Tag.md b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Adjust the Hover State of an Anchor Tag.md new file mode 100644 index 0000000000..e4446b55cf --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Adjust the Hover State of an Anchor Tag.md @@ -0,0 +1,62 @@ +--- +id: 587d781d367417b2b2512ac8 +title: Adjust the Hover State of an Anchor Tag +challengeType: 0 +videoUrl: 'https://scrimba.com/c/cakRGcm' +--- + +## Description +
+This challenge will touch on the usage of pseudo-classes. A pseudo-class is a keyword that can be added to selectors, in order to select a specific state of the element. +For example, the styling of an anchor tag can be changed for its hover state using the :hover pseudo-class selector. Here's the CSS to change the color of the anchor tag to red during its hover state: +
a:hover {
  color: red;
}
+
+ +## Instructions +
+The code editor has a CSS rule to style all a tags black. Add a rule so that when the user hovers over the a tag, the color is blue. +
+ +## Tests +
+ +```yml +- text: 'The anchor tag color should remain black, only add CSS rules for the :hover state.' + testString: 'assert($("a").css("color") == "rgb(0, 0, 0)", "The anchor tag color should remain black, only add CSS rules for the :hover state.");' +- text: The anchor tag should have a color of blue on hover. + testString: 'assert(code.match(/a:hover\s*?{\s*?color:\s*?blue;\s*?}/gi), "The anchor tag should have a color of blue on hover.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + +CatPhotoApp +``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/applied-visual-design/Adjust the Hue of a Color.md b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Adjust the Hue of a Color.md new file mode 100644 index 0000000000..b283978e4a --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Adjust the Hue of a Color.md @@ -0,0 +1,91 @@ +--- +id: 587d78a4367417b2b2512ad4 +title: Adjust the Hue of a Color +challengeType: 0 +videoUrl: 'https://scrimba.com/c/cPp38TZ' +--- + +## Description +
+Colors have several characteristics including hue, saturation, and lightness. CSS3 introduced the hsl() property as an alternative way to pick a color by directly stating these characteristics. +Hue is what people generally think of as 'color'. If you picture a spectrum of colors starting with red on the left, moving through green in the middle, and blue on right, the hue is where a color fits along this line. In hsl(), hue uses a color wheel concept instead of the spectrum, where the angle of the color on the circle is given as a value between 0 and 360. +Saturation is the amount of gray in a color. A fully saturated color has no gray in it, and a minimally saturated color is almost completely gray. This is given as a percentage with 100% being fully saturated. +Lightness is the amount of white or black in a color. A percentage is given ranging from 0% (black) to 100% (white), where 50% is the normal color. +Here are a few examples of using hsl() with fully-saturated, normal lightness colors: +
ColorHSL
redhsl(0, 100%, 50%)
yellowhsl(60, 100%, 50%)
greenhsl(120, 100%, 50%)
cyanhsl(180, 100%, 50%)
bluehsl(240, 100%, 50%)
magentahsl(300, 100%, 50%)
+
+ +## Instructions +
+Change the background-color of each div element based on the class names (green, cyan, or blue) using hsl(). All three should have full saturation and normal lightness. +
+ +## Tests +
+ +```yml +- text: Your code should use the hsl() property to declare the color green. + testString: 'assert(code.match(/\.green\s*?{\s*?background-color:\s*?hsl/gi), "Your code should use the hsl() property to declare the color green.");' +- text: Your code should use the hsl() property to declare the color cyan. + testString: 'assert(code.match(/\.cyan\s*?{\s*?background-color:\s*?hsl/gi), "Your code should use the hsl() property to declare the color cyan.");' +- text: Your code should use the hsl() property to declare the color blue. + testString: 'assert(code.match(/\.blue\s*?{\s*?background-color:\s*?hsl/gi), "Your code should use the hsl() property to declare the color blue.");' +- text: The div element with class green should have a background-color of green. + testString: 'assert($(".green").css("background-color") == "rgb(0, 255, 0)", "The div element with class green should have a background-color of green.");' +- text: The div element with class cyan should have a background-color of cyan. + testString: 'assert($(".cyan").css("background-color") == "rgb(0, 255, 255)", "The div element with class cyan should have a background-color of cyan.");' +- text: The div element with class blue should have a background-color of blue. + testString: 'assert($(".blue").css("background-color") == "rgb(0, 0, 255)", "The div element with class blue should have a background-color of blue.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + + +
+
+
+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/applied-visual-design/Adjust the Size of a Header Versus a Paragraph Tag.md b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Adjust the Size of a Header Versus a Paragraph Tag.md new file mode 100644 index 0000000000..4706c18ab0 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Adjust the Size of a Header Versus a Paragraph Tag.md @@ -0,0 +1,90 @@ +--- +id: 587d781b367417b2b2512abd +title: Adjust the Size of a Header Versus a Paragraph Tag +challengeType: 0 +videoUrl: 'https://scrimba.com/c/c3bRPTz' +--- + +## Description +
+The font size of header tags (h1 through h6) should generally be larger than the font size of paragraph tags. This makes it easier for the user to visually understand the layout and level of importance of everything on the page. You use the font-size property to adjust the size of the text in an element. +
+ +## Instructions +
+To make the heading significantly larger than the paragraph, change the font-size of the h4 tag to 27 pixels. +
+ +## Tests +
+ +```yml +- text: Your code should add a font-size property to the h4 element set to 27 pixels. + testString: 'assert($("h4").css("font-size") == "27px", "Your code should add a font-size property to the h4 element set to 27 pixels.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + +
+
+
+

Alphabet

+
+

Google was founded by Larry Page and Sergey Brin while they were Ph.D. students at Stanford University.

+
+ +
+
+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/applied-visual-design/Adjust the Tone of a Color.md b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Adjust the Tone of a Color.md new file mode 100644 index 0000000000..2412d3b5cb --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Adjust the Tone of a Color.md @@ -0,0 +1,92 @@ +--- +id: 587d78a4367417b2b2512ad5 +title: Adjust the Tone of a Color +challengeType: 0 +videoUrl: 'https://scrimba.com/c/cEDJvT7' +--- + +## Description +
+The hsl() option in CSS also makes it easy to adjust the tone of a color. Mixing white with a pure hue creates a tint of that color, and adding black will make a shade. Alternatively, a tone is produced by adding gray or by both tinting and shading. Recall that the 's' and 'l' of hsl() stand for saturation and lightness, respectively. The saturation percent changes the amount of gray and the lightness percent determines how much white or black is in the color. This is useful when you have a base hue you like, but need different variations of it. +
+ +## Instructions +
+The navigation bar on this site currently inherits its background-color from the header element. Starting with that color as a base, add a background-color to the nav element so it uses the same cyan hue, but has 80% saturation and 25% lightness values to change its tone and shade. +
+ +## Tests +
+ +```yml +- text: The nav element should have a background-color of the adjusted cyan tone using the hsl() property. + testString: 'assert(code.match(/nav\s*?{\s*?background-color:\s*?hsl\(180,\s*?80%,\s*?25%\)/gi), "The nav element should have a background-color of the adjusted cyan tone using the hsl() property.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + + +
+

Cooking with FCC!

+ +
+``` + +
+ + + +
+ +## Solution +
+ + +```js +var code = "nav {background-color: hsl(180, 80%, 25%);}" +``` + +
diff --git a/curriculum/challenges/01-responsive-web-design/applied-visual-design/Adjust the Width of an Element Using the width Property.md b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Adjust the Width of an Element Using the width Property.md new file mode 100644 index 0000000000..3d411ff706 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Adjust the Width of an Element Using the width Property.md @@ -0,0 +1,86 @@ +--- +id: 587d7791367417b2b2512ab4 +title: Adjust the Width of an Element Using the width Property +challengeType: 0 +videoUrl: 'https://scrimba.com/c/cvVLPtN' +--- + +## Description +
+You can specify the width of an element using the width property in CSS. Values can be given in relative length units (such as em), absolute length units (such as px), or as a percentage of its containing parent element. Here's an example that changes the width of an image to 220px: +
img {
  width: 220px;
}
+
+ +## Instructions +
+Add a width property to the entire card and set it to an absolute value of 245px. Use the fullCard class to select the element. +
+ +## Tests +
+ +```yml +- text: Your code should change the width property of the card to 245 pixels by using the fullCard class selector. + testString: 'assert(code.match(/.fullCard\s*{[\s\S][^}]*\n*^\s*width\s*:\s*245px\s*;/gm), "Your code should change the width property of the card to 245 pixels by using the fullCard class selector.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + +
+
+
+

Google

+

Google was founded by Larry Page and Sergey Brin while they were Ph.D. students at Stanford University.

+
+ +
+
+``` + +
+ + + +
+ +## Solution +
+ + +```js +var code = ".fullCard {\nwidth: 245px; border: 1px solid #ccc; border-radius: 5px; margin: 10px 5px; padding: 4px;}" +``` + +
diff --git a/curriculum/challenges/01-responsive-web-design/applied-visual-design/Adjust the background-color Property of Text.md b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Adjust the background-color Property of Text.md new file mode 100644 index 0000000000..c064cdcfd4 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Adjust the background-color Property of Text.md @@ -0,0 +1,98 @@ +--- +id: 587d781b367417b2b2512abc +title: Adjust the background-color Property of Text +challengeType: 0 +videoUrl: 'https://scrimba.com/c/cEDqwA6' +--- + +## Description +
+Instead of adjusting your overall background or the color of the text to make the foreground easily readable, you can add a background-color to the element holding the text you want to emphasize. This challenge uses rgba() instead of hex codes or normal rgb(). +
rgba stands for:
  r = red
  g = green
  b = blue
  a = alpha/level of opacity
+The RGB values can range from 0 to 255. The alpha value can range from 1, which is fully opaque or a solid color, to 0, which is fully transparent or clear. rgba() is great to use in this case, as it allows you to adjust the opacity. This means you don't have to completely block out the background. +You'll use background-color: rgba(45, 45, 45, 0.1) for this challenge. It produces a dark gray color that is nearly transparent given the low opacity value of 0.1. +
+ +## Instructions +
+To make the text stand out more, adjust the background-color of the h4 element to the given rgba() value. +Also for the h4, remove the height property and add padding of 10px. +
+ +## Tests +
+ +```yml +- text: 'Your code should add a background-color property to the h4 element set to rgba(45, 45, 45, 0.1).' + testString: 'assert(code.match(/background-color:\s*?rgba\(\s*?45\s*?,\s*?45\s*?,\s*?45\s*?,\s*?0?\.1\s*?\)/gi), "Your code should add a background-color property to the h4 element set to rgba(45, 45, 45, 0.1).");' +- text: Your code should add a padding property to the h4 element and set it to 10 pixels. + testString: 'assert($("h4").css("padding-top") == "10px" && $("h4").css("padding-right") == "10px" && $("h4").css("padding-bottom") == "10px" && $("h4").css("padding-left") == "10px", "Your code should add a padding property to the h4 element and set it to 10 pixels.");' +- text: The height property on the h4 element should be removed. + testString: 'assert(!($("h4").css("height") == "25px"), "The height property on the h4 element should be removed.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + +
+
+
+

Alphabet

+
+

Google was founded by Larry Page and Sergey Brin while they were Ph.D. students at Stanford University.

+
+ +
+
+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/applied-visual-design/Animate Elements Continually Using an Infinite Animation Count.md b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Animate Elements Continually Using an Infinite Animation Count.md new file mode 100644 index 0000000000..c68b23b7e5 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Animate Elements Continually Using an Infinite Animation Count.md @@ -0,0 +1,84 @@ +--- +id: 587d78a8367417b2b2512ae3 +title: Animate Elements Continually Using an Infinite Animation Count +challengeType: 0 +videoUrl: 'https://scrimba.com/c/cVJDVfq' +--- + +## Description +
+The previous challenges covered how to use some of the animation properties and the @keyframes rule. Another animation property is the animation-iteration-count, which allows you to control how many times you would like to loop through the animation. Here's an example: +animation-iteration-count: 3; +In this case the animation will stop after running 3 times, but it's possible to make the animation run continuously by setting that value to infinite. +
+ +## Instructions +
+To keep the ball bouncing on the right on a continuous loop, change the animation-iteration-count property to infinite. +
+ +## Tests +
+ +```yml +- text: The animation-iteration-count property should have a value of infinite. + testString: 'assert($("#ball").css("animation-iteration-count") == "infinite", "The animation-iteration-count property should have a value of infinite.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + +
+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/applied-visual-design/Animate Elements at Variable Rates.md b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Animate Elements at Variable Rates.md new file mode 100644 index 0000000000..6095b94255 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Animate Elements at Variable Rates.md @@ -0,0 +1,104 @@ +--- +id: 587d78a8367417b2b2512ae5 +title: Animate Elements at Variable Rates +challengeType: 0 +videoUrl: 'https://scrimba.com/c/cZ89WA4' +--- + +## Description +
+There are a variety of ways to alter the animation rates of similarly animated elements. So far, this has been achieved by applying an animation-iteration-count property and setting @keyframes rules. +To illustrate, the animation on the right consists of two "stars" that each decrease in size and opacity at the 20% mark in the @keyframes rule, which creates the twinkle animation. You can change the @keyframes rule for one of the elements so the stars twinkle at different rates. +
+ +## Instructions +
+Alter the animation rate for the element with the class name of star-1 by changing its @keyframes rule to 50%. +
+ +## Tests +
+ +```yml +- text: The @keyframes rule for the star-1 class should be 50%. + testString: 'assert(code.match(/twinkle-1\s*?{\s*?50%/g), "The @keyframes rule for the star-1 class should be 50%.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + + +
+
+
+``` + +
+ + + +
+ +## Solution +
+ + +```js +var code = "@keyframes twinkle-1 {50% {transform: scale(0.5); opacity: 0.5;}}" +``` + +
diff --git a/curriculum/challenges/01-responsive-web-design/applied-visual-design/Animate Multiple Elements at Variable Rates.md b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Animate Multiple Elements at Variable Rates.md new file mode 100644 index 0000000000..28dc9c5507 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Animate Multiple Elements at Variable Rates.md @@ -0,0 +1,107 @@ +--- +id: 587d78a8367417b2b2512ae6 +title: Animate Multiple Elements at Variable Rates +challengeType: 0 +videoUrl: 'https://scrimba.com/c/cnpWZc9' +--- + +## Description +
+In the previous challenge, you changed the animation rates for two similarly animated elements by altering their @keyframes rules. You can achieve the same goal by manipulating the animation-duration of multiple elements. +In the animation running in the code editor, there are three "stars" in the sky that twinkle at the same rate on a continuous loop. To make them twinkle at different rates, you can set the animation-duration property to different values for each element. +
+ +## Instructions +
+Set the animation-duration of the elements with the classes star-1, star-2, and star-3 to 1s, 0.9s, and 1.1s, respectively. +
+ +## Tests +
+ +```yml +- text: The animation-duration property for the star with class star-1 should remain at 1s. + testString: 'assert($(".star-1").css("animation-duration") == "1s", "The animation-duration property for the star with class star-1 should remain at 1s.");' +- text: The animation-duration property for the star with class star-2 should be 0.9s. + testString: 'assert($(".star-2").css("animation-duration") == "0.9s", "The animation-duration property for the star with class star-2 should be 0.9s.");' +- text: The animation-duration property for the star with class star-3 should be 1.1s. + testString: 'assert($(".star-3").css("animation-duration") == "1.1s", "The animation-duration property for the star with class star-3 should be 1.1s.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + + +
+
+
+
+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/applied-visual-design/Center an Element Horizontally Using the margin Property.md b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Center an Element Horizontally Using the margin Property.md new file mode 100644 index 0000000000..ce1b3cd938 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Center an Element Horizontally Using the margin Property.md @@ -0,0 +1,61 @@ +--- +id: 587d78a3367417b2b2512ad0 +title: Center an Element Horizontally Using the margin Property +challengeType: 0 +videoUrl: 'https://scrimba.com/c/cyLJqU4' +--- + +## Description +
+Another positioning technique is to center a block element horizontally. One way to do this is to set its margin to a value of auto. +This method works for images, too. Images are inline elements by default, but can be changed to block elements when you set the display property to block. +
+ +## Instructions +
+Center the div on the page by adding a margin property with a value of auto. +
+ +## Tests +
+ +```yml +- text: The div should have a margin set to auto. + testString: 'assert(code.match(/margin:\s*?auto;/g), "The div should have a margin set to auto.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + +
+``` + +
+ + + +
+ +## Solution +
+ + +```js +var code = "div {background-color: blue; height: 100px; width: 100px; margin: auto;}" +``` + +
diff --git a/curriculum/challenges/01-responsive-web-design/applied-visual-design/Change Animation Timing with Keywords.md b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Change Animation Timing with Keywords.md new file mode 100644 index 0000000000..10ba211f37 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Change Animation Timing with Keywords.md @@ -0,0 +1,91 @@ +--- +id: 587d78a8367417b2b2512ae7 +title: Change Animation Timing with Keywords +challengeType: 0 +videoUrl: 'https://scrimba.com/c/cJKvwCM' +--- + +## Description +
+In CSS animations, the animation-timing-function property controls how quickly an animated element changes over the duration of the animation. If the animation is a car moving from point A to point B in a given time (your animation-duration), the animation-timing-function says how the car accelerates and decelerates over the course of the drive. +There are a number of predefined keywords available for popular options. For example, the default value is ease, which starts slow, speeds up in the middle, and then slows down again in the end. Other options include ease-out, which is quick in the beginning then slows down, ease-in, which is slow in the beginning, then speeds up at the end, or linear, which applies a constant animation speed throughout. +
+ +## Instructions +
+For the elements with id of ball1 and ball2, add an animation-timing-function property to each, and set #ball1 to linear, and #ball2 to ease-out. Notice the difference between how the elements move during the animation but end together, since they share the same animation-duration of 2 seconds. +
+ +## Tests +
+ +```yml +- text: The value of the animation-timing-function property for the element with the id ball1 should be linear. + testString: 'assert($("#ball1").css("animation-timing-function") == "linear", "The value of the animation-timing-function property for the element with the id ball1 should be linear.");' +- text: The value of the animation-timing-function property for the element with the id ball2 should be ease-out. + testString: 'assert($("#ball2").css("animation-timing-function") == "ease-out", "The value of the animation-timing-function property for the element with the id ball2 should be ease-out.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + + +
+
+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/applied-visual-design/Change an Element's Relative Position.md b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Change an Element's Relative Position.md new file mode 100644 index 0000000000..6c84baee2c --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Change an Element's Relative Position.md @@ -0,0 +1,66 @@ +--- +id: 587d781e367417b2b2512ac9 +title: Change an Element's Relative Position +challengeType: 0 +videoUrl: 'https://scrimba.com/c/czVmMtZ' +--- + +## Description +
+CSS treats each HTML element as its own box, which is usually referred to as the CSS Box Model. Block-level items automatically start on a new line (think headings, paragraphs, and divs) while inline items sit within surrounding content (like images or spans). The default layout of elements in this way is called the normal flow of a document, but CSS offers the position property to override it. +When the position of an element is set to relative, it allows you to specify how CSS should move it relative to its current position in the normal flow of the page. It pairs with the CSS offset properties of left or right, and top or bottom. These say how many pixels, percentages, or ems to move the item away from where it is normally positioned. The following example moves the paragraph 10 pixels away from the bottom: +
p {
  position: relative;
  bottom: 10px;
}
+Changing an element's position to relative does not remove it from the normal flow - other elements around it still behave as if that item were in its default position. +Note
Positioning gives you a lot of flexibility and power over the visual layout of a page. It's good to remember that no matter the position of elements, the underlying HTML markup should be organized and make sense when read from top to bottom. This is how users with visual impairments (who rely on assistive devices like screen readers) access your content. +
+ +## Instructions +
+Change the position of the h2 to relative, and use a CSS offset to move it 15 pixels away from the top of where it sits in the normal flow. Notice there is no impact on the positions of the surrounding h1 and p elements. +
+ +## Tests +
+ +```yml +- text: The h2 element should have a position property set to relative. + testString: 'assert($("h2").css("position") == "relative", "The h2 element should have a position property set to relative.");' +- text: Your code should use a CSS offset to relatively position the h2 15px away from the top of where it normally sits. + testString: 'assert($("h2").css("top") == "15px", "Your code should use a CSS offset to relatively position the h2 15px away from the top of where it normally sits.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + + +

On Being Well-Positioned

+

Move me!

+

I still think the h2 is where it normally sits.

+ +``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/applied-visual-design/Change the Position of Overlapping Elements with the z-index Property.md b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Change the Position of Overlapping Elements with the z-index Property.md new file mode 100644 index 0000000000..12aba0ae9d --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Change the Position of Overlapping Elements with the z-index Property.md @@ -0,0 +1,72 @@ +--- +id: 587d78a3367417b2b2512acf +title: Change the Position of Overlapping Elements with the z-index Property +challengeType: 0 +videoUrl: 'https://scrimba.com/c/cM94aHk' +--- + +## Description +
+When elements are positioned to overlap, the element coming later in the HTML markup will, by default, appear on the top of the other elements. However, the z-index property can specify the order of how elements are stacked on top of one another. It must be an integer (i.e. a whole number and not a decimal), and higher values for the z-index property of an element move it higher in the stack than those with lower values. +
+ +## Instructions +
+Add a z-index property to the element with the class name of first (the red rectangle) and set it to a value of 2 so it covers the other element (blue rectangle). +
+ +## Tests +
+ +```yml +- text: The element with class first should have a z-index value of 2. + testString: 'assert($(".first").css("z-index") == "2", "The element with class first should have a z-index value of 2.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + + +
+
+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/applied-visual-design/Create Movement Using CSS Animation.md b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Create Movement Using CSS Animation.md new file mode 100644 index 0000000000..40f9b345a7 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Create Movement Using CSS Animation.md @@ -0,0 +1,92 @@ +--- +id: 587d78a7367417b2b2512ae1 +title: Create Movement Using CSS Animation +challengeType: 0 +videoUrl: 'https://scrimba.com/c/c7amZfW' +--- + +## Description +
+When elements have a specified position, such as fixed or relative, the CSS offset properties right, left, top, and bottom can be used in animation rules to create movement. +As shown in the example below, you can push the item downwards then upwards by setting the top property of the 50% keyframe to 50px, but having it set to 0px for the first (0%) and the last (100%) keyframe. +
@keyframes rainbow {
  0% {
    background-color: blue;
    top: 0px;
  }
  50% {
    background-color: green;
    top: 50px;
  }
  100% {
    background-color: yellow;
    top: 0px;
  }
}
+
+ +## Instructions +
+Add a horizontal motion to the div animation. Using the left offset property, add to the @keyframes rule so rainbow starts at 0 pixels at 0%, moves to 25 pixels at 50%, and ends at -25 pixels at 100%. Don't replace the top property in the editor - the animation should have both vertical and horizontal motion. +
+ +## Tests +
+ +```yml +- text: The @keyframes rule for 0% should use the left offset of 0px. + testString: 'assert(code.match(/0%\s*?{\s*?background-color:\s*?blue;\s*?top:\s*?0(px)?;\s*?left:\s*?0(px)?;\s*?}/gi), "The @keyframes rule for 0% should use the left offset of 0px.");' +- text: The @keyframes rule for 50% should use the left offset of 25px. + testString: 'assert(code.match(/50%\s*?{\s*?background-color:\s*?green;\s*?top:\s*?50px;\s*?left:\s*?25px;\s*?}/gi), "The @keyframes rule for 50% should use the left offset of 25px.");' +- text: The @keyframes rule for 100% should use the left offset of -25px. + testString: 'assert(code.match(/100%\s*?{\s*?background-color:\s*?yellow;\s*?top:\s*?0(px)?;\s*?left:\s*?-25px;\s*?}/gi), "The @keyframes rule for 100% should use the left offset of -25px.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + + +
+``` + +
+ + + +
+ +## Solution +
+ + +```js +var code = "@keyframes rainbow {0% {background-color: blue; top: 0px; left: 0px;} 50% {background-color: green; top: 50px; left: 25px;} 100% {background-color: yellow; top: 0px; left:-25px;}}" +``` + +
diff --git a/curriculum/challenges/01-responsive-web-design/applied-visual-design/Create Texture by Adding a Subtle Pattern as a Background Image.md b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Create Texture by Adding a Subtle Pattern as a Background Image.md new file mode 100644 index 0000000000..73a9e94cf0 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Create Texture by Adding a Subtle Pattern as a Background Image.md @@ -0,0 +1,56 @@ +--- +id: 587d78a5367417b2b2512ad8 +title: Create Texture by Adding a Subtle Pattern as a Background Image +challengeType: 0 +videoUrl: 'https://scrimba.com/c/cQdwJC8' +--- + +## Description +
+One way to add texture and interest to a background and have it stand out more is to add a subtle pattern. The key is balance, as you don't want the background to stand out too much, and take away from the foreground. The background property supports the url() function in order to link to an image of the chosen texture or pattern. The link address is wrapped in quotes inside the parentheses. +
+ +## Instructions +
+Using the url of https://i.imgur.com/MJAkxbh.png, set the background of the whole page with the body selector. +
+ +## Tests +
+ +```yml +- text: Your body element should have a background property set to a url() with the given link. + testString: 'assert(code.match(/background:\s*?url\(\s*("|"|)https:\/\/i\.imgur\.com\/MJAkxbh\.png\1\s*\)/gi), "Your body element should have a background property set to a url() with the given link.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + +``` + +
+ + + +
+ +## Solution +
+ + +```js +var code = "body {background: url('https://i.imgur.com/MJAkxbh.png')}" +``` + +
diff --git a/curriculum/challenges/01-responsive-web-design/applied-visual-design/Create Visual Balance Using the text-align Property.md b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Create Visual Balance Using the text-align Property.md new file mode 100644 index 0000000000..0c66eae6b5 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Create Visual Balance Using the text-align Property.md @@ -0,0 +1,89 @@ +--- +id: 587d7791367417b2b2512ab3 +title: Create Visual Balance Using the text-align Property +challengeType: 0 +videoUrl: 'https://scrimba.com/c/c3b4EAp' +--- + +## Description +
+This section of the curriculum focuses on Applied Visual Design. The first group of challenges build on the given card layout to show a number of core principles. +Text is often a large part of web content. CSS has several options for how to align it with the text-align property. +text-align: justify; causes all lines of text except the last line to meet the left and right edges of the line box. +text-align: center; centers the text +text-align: right; right-aligns the text +And text-align: left; (the default) left-aligns the text. +
+ +## Instructions +
+Align the h4 tag's text, which says "Google", to the center. Then justify the paragraph tag which contains information about how Google was founded. +
+ +## Tests +
+ +```yml +- text: Your code should use the text-align property on the h4 tag to set it to center. + testString: 'assert($("h4").css("text-align") == "center", "Your code should use the text-align property on the h4 tag to set it to center.");' +- text: Your code should use the text-align property on the p tag to set it to justify. + testString: 'assert($("p").css("text-align") == "justify", "Your code should use the text-align property on the p tag to set it to justify.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + +
+
+
+

Google

+

Google was founded by Larry Page and Sergey Brin while they were Ph.D. students at Stanford University.

+
+ +
+
+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/applied-visual-design/Create Visual Direction by Fading an Element from Left to Right.md b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Create Visual Direction by Fading an Element from Left to Right.md new file mode 100644 index 0000000000..32982293af --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Create Visual Direction by Fading an Element from Left to Right.md @@ -0,0 +1,80 @@ +--- +id: 587d78a7367417b2b2512ae2 +title: Create Visual Direction by Fading an Element from Left to Right +challengeType: 0 +videoUrl: 'https://scrimba.com/c/cGJqqAE' +--- + +## Description +
+For this challenge, you'll change the opacity of an animated element so it gradually fades as it reaches the right side of the screen. +In the displayed animation, the round element with the gradient background moves to the right by the 50% mark of the animation per the @keyframes rule. +
+ +## Instructions +
+Target the element with the id of ball and add the opacity property set to 0.1 at 50%, so the element fades as it moves to the right. +
+ +## Tests +
+ +```yml +- text: The keyframes rule for fade should set the opacity property to 0.1 at 50%. + testString: 'assert(code.match(/@keyframes fade\s*?{\s*?50%\s*?{\s*?(?:left:\s*?60%;\s*?opacity:\s*?0?\.1;|opacity:\s*?0?\.1;\s*?left:\s*?60%;)/gi), "The keyframes rule for fade should set the opacity property to 0.1 at 50%.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + + +
+``` + +
+ + + +
+ +## Solution +
+ + +```js +var code = "@keyframes fade {50% { left: 60%; opacity: 0.1;}}" +``` + +
diff --git a/curriculum/challenges/01-responsive-web-design/applied-visual-design/Create a Gradual CSS Linear Gradient.md b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Create a Gradual CSS Linear Gradient.md new file mode 100644 index 0000000000..6b1a98a30c --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Create a Gradual CSS Linear Gradient.md @@ -0,0 +1,69 @@ +--- +id: 587d78a5367417b2b2512ad6 +title: Create a Gradual CSS Linear Gradient +challengeType: 0 +videoUrl: 'https://scrimba.com/c/cg4dpt9' +--- + +## Description +
+Applying a color on HTML elements is not limited to one flat hue. CSS provides the ability to use color transitions, otherwise known as gradients, on elements. This is accessed through the background property's linear-gradient() function. Here is the general syntax: +background: linear-gradient(gradient_direction, color 1, color 2, color 3, ...); +The first argument specifies the direction from which color transition starts - it can be stated as a degree, where 90deg makes a vertical gradient and 45deg is angled like a backslash. The following arguments specify the order of colors used in the gradient. +Example: +background: linear-gradient(90deg, red, yellow, rgb(204, 204, 255)); +
+ +## Instructions +
+Use a linear-gradient() for the div element's background, and set it from a direction of 35 degrees to change the color from #CCFFFF to #FFCCCC. +Note
While there are other ways to specify a color value, like rgb() or hsl(), use hex values for this challenge. +
+ +## Tests +
+ +```yml +- text: The div element should have a linear-gradient background with the specified direction and colors. + testString: 'assert(code.match(/background:\s*?linear-gradient\(35deg,\s*?(#CCFFFF|#CFF),\s*?(#FFCCCC|#FCC)\);/gi), "The div element should have a linear-gradient background with the specified direction and colors.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + + +
+``` + +
+ + + +
+ +## Solution +
+ + +```js +var code = "
" +``` + +
diff --git a/curriculum/challenges/01-responsive-web-design/applied-visual-design/Create a Graphic Using CSS.md b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Create a Graphic Using CSS.md new file mode 100644 index 0000000000..e11032ae27 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Create a Graphic Using CSS.md @@ -0,0 +1,77 @@ +--- +id: 587d78a6367417b2b2512add +title: Create a Graphic Using CSS +challengeType: 0 +videoUrl: 'https://scrimba.com/c/cEDWPs6' +--- + +## Description +
+By manipulating different selectors and properties, you can make interesting shapes. One of the easier ones to try is a crescent moon shape. For this challenge you need to work with the box-shadow property that sets the shadow of an element, along with the border-radius property that controls the roundness of the element's corners. +You will create a round, transparent object with a crisp shadow that is slightly offset to the side - the shadow is actually going to be the moon shape you see. +In order to create a round object, the border-radius property should be set to a value of 50%. +You may recall from an earlier challenge that the box-shadow property takes values for offset-x, offset-y, blur-radius, spread-radius and a color value in that order. The blur-radius and spread-radius values are optional. +
+ +## Instructions +
+Manipulate the square element in the editor to create the moon shape. First, change the background-color to transparent, then set the border-radius property to 50% to make the circular shape. Finally, change the box-shadow property to set the offset-x to 25px, the offset-y to 10px, blur-radius to 0, spread-radius to 0, and color to blue. +
+ +## Tests +
+ +```yml +- text: The value of the background-color property should be set to transparent. + testString: 'assert(code.match(/background-color:\s*?transparent;/gi), "The value of the background-color property should be set to transparent.");' +- text: The value of the border-radius property should be set to 50%. + testString: 'assert(code.match(/border-radius:\s*?50%;/gi), "The value of the border-radius property should be set to 50%.");' +- text: 'The value of the box-shadow property should be set to 25px for offset-x, 10px for offset-y, 0 for blur-radius, 0 for spread-radius, and finally blue for the color.' + testString: 'assert(code.match(/box-shadow:\s*?25px\s+?10px\s+?0(px)?\s+?0(px)?\s+?blue\s*?;/gi), "The value of the box-shadow property should be set to 25px for offset-x, 10px for offset-y, 0 for blur-radius, 0 for spread-radius, and finally blue for the color.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + +
+``` + +
+ + + +
+ +## Solution +
+ + +```js +var code = ".center {background-color: transparent; border-radius: 50%; box-shadow: 25px 10px 0px 0 blue;}" +``` + +
diff --git a/curriculum/challenges/01-responsive-web-design/applied-visual-design/Create a Horizontal Line Using the hr Element.md b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Create a Horizontal Line Using the hr Element.md new file mode 100644 index 0000000000..a82bbd1444 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Create a Horizontal Line Using the hr Element.md @@ -0,0 +1,91 @@ +--- +id: 587d781b367417b2b2512abb +title: Create a Horizontal Line Using the hr Element +challengeType: 0 +videoUrl: 'https://scrimba.com/c/c3bR8t7' +--- + +## Description +
+You can use the hr tag to add a horizontal line across the width of its containing element. This can be used to define a change in topic or to visually separate groups of content. +
+ +## Instructions +
+Add an hr tag underneath the h4 which contains the card title. +Note
In HTML, hr is a self-closing tag, and therefore doesn't need a separate closing tag. +
+ +## Tests +
+ +```yml +- text: Your code should add an hr tag to the markup. + testString: 'assert($("hr").length == 1, "Your code should add an hr tag to the markup.");' +- text: The hr tag should come between the title and the paragraph. + testString: 'assert(code.match(/<\/h4>\s*?|\s*?\/>)\s*?

/gi), "The hr tag should come between the title and the paragraph.");' + +``` + +

+ +## Challenge Seed +
+ +
+ +```html + +
+
+
+

GoogleAlphabet

+ +

Google was founded by Larry Page and Sergey Brin while they were Ph.D. students at Stanford University.

+
+ +
+
+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/applied-visual-design/Create a More Complex Shape Using CSS and HTML.md b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Create a More Complex Shape Using CSS and HTML.md new file mode 100644 index 0000000000..f78814f095 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Create a More Complex Shape Using CSS and HTML.md @@ -0,0 +1,97 @@ +--- +id: 587d78a6367417b2b2512ade +title: Create a More Complex Shape Using CSS and HTML +challengeType: 0 +videoUrl: 'https://scrimba.com/c/cPpz4fr' +--- + +## Description +
+One of the most popular shapes in the world is the heart shape, and in this challenge you'll create one using pure CSS. But first, you need to understand the ::before and ::after pseudo-elements. These pseudo-elements are used to add something before or after a selected element. In the following example, a ::before pseudo-element is used to add a rectangle to an element with the class heart: +
.heart::before {
  content: "";
  background-color: yellow;
  border-radius: 25%;
  position: absolute;
  height: 50px;
  width: 70px;
  top: -50px;
  left: 5px;
}
+For the ::before and ::after pseudo-elements to function properly, they must have a defined content property. This property is usually used to add things like a photo or text to the selected element. When the ::before and ::after pseudo-elements are used to make shapes, the content property is still required, but it's set to an empty string. +In the above example, the element with the class of heart has a ::before pseudo-element that produces a yellow rectangle with height and width of 50px and 70px, respectively. This rectangle has round corners due to its 25% border radius and is positioned absolutely at 5px from the left and 50px above the top of the element. +
+ +## Instructions +
+Transform the element on the screen to a heart. In the heart::after selector, change the background-color to pink and the border-radius to 50%. +Next, target the element with the class heart (just heart) and fill in the transform property. Use the rotate() function with -45 degrees. (rotate() works the same way that skewX() and skewY() do). +Finally, in the heart::before selector, set its content property to an empty string. +
+ +## Tests +
+ +```yml +- text: 'The background-color property of the heart::after selector should be pink.' + testString: 'assert(code.match(/\.heart::after\s*?{\s*?background-color\s*?:\s*?pink\s*?;/gi), "The background-color property of the heart::after selector should be pink.");' +- text: 'The border-radius of the heart::after selector should be 50%.' + testString: 'assert(code.match(/border-radius\s*?:\s*?50%/gi).length == 2, "The border-radius of the heart::after selector should be 50%.");' +- text: The transform property for the heart class should use a rotate() function set to -45 degrees. + testString: 'assert(code.match(/transform\s*?:\s*?rotate\(\s*?-45deg\s*?\)/gi), "The transform property for the heart class should use a rotate() function set to -45 degrees.");' +- text: 'The content of the heart::before selector should be an empty string.' + testString: 'assert(code.match(/\.heart::before\s*?{\s*?content\s*?:\s*?("|")\1\s*?;/gi), "The content of the heart::before selector should be an empty string.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + +
+``` + +
+ + + +
+ +## Solution +
+ + +```js +var code = ".heart {transform: rotate(-45deg);} .heart::after {background-color: pink; border-radius: 50%;} .heart::before {content: \"\"; border-radius: 50%;}" +``` + +
diff --git a/curriculum/challenges/01-responsive-web-design/applied-visual-design/Decrease the Opacity of an Element.md b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Decrease the Opacity of an Element.md new file mode 100644 index 0000000000..2def9b51c5 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Decrease the Opacity of an Element.md @@ -0,0 +1,96 @@ +--- +id: 587d781c367417b2b2512abf +title: Decrease the Opacity of an Element +challengeType: 0 +videoUrl: 'https://scrimba.com/c/c7aKqu4' +--- + +## Description +
+The opacity property in CSS is used to adjust the opacity, or conversely, the transparency for an item. +
A value of 1 is opaque, which isn't transparent at all.
A value of 0.5 is half see-through.
A value of 0 is completely transparent.
+The value given will apply to the entire element, whether that's an image with some transparency, or the foreground and background colors for a block of text. +
+ +## Instructions +
+Set the opacity of the anchor tags to 0.7 using links class to select them. +
+ +## Tests +
+ +```yml +- text: Your code should set the opacity property to 0.7 on the anchor tags by selecting the class of links. + testString: 'assert.approximately(parseFloat($(".links").css("opacity")), 0.7, 0.1, "Your code should set the opacity property to 0.7 on the anchor tags by selecting the class of links.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + +
+
+
+

Alphabet

+
+

Google was founded by Larry Page and Sergey Brin while they were Ph.D. students at Stanford University.

+
+ +
+
+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/applied-visual-design/Learn How Bezier Curves Work.md b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Learn How Bezier Curves Work.md new file mode 100644 index 0000000000..5a899ecaa1 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Learn How Bezier Curves Work.md @@ -0,0 +1,94 @@ +--- +id: 587d78a9367417b2b2512ae8 +title: Learn How Bezier Curves Work +challengeType: 0 +videoUrl: 'https://scrimba.com/c/c9bDrs8' +--- + +## Description +
+The last challenge introduced the animation-timing-function property and a few keywords that change the speed of an animation over its duration. CSS offers an option other than keywords that provides even finer control over how the animation plays out, through the use of Bezier curves. +In CSS animations, Bezier curves are used with the cubic-bezier function. The shape of the curve represents how the animation plays out. The curve lives on a 1 by 1 coordinate system. The X-axis of this coordinate system is the duration of the animation (think of it as a time scale), and the Y-axis is the change in the animation. +The cubic-bezier function consists of four main points that sit on this 1 by 1 grid: p0, p1, p2, and p3. p0 and p3 are set for you - they are the beginning and end points which are always located respectively at the origin (0, 0) and (1, 1). You set the x and y values for the other two points, and where you place them in the grid dictates the shape of the curve for the animation to follow. This is done in CSS by declaring the x and y values of the p1 and p2 "anchor" points in the form: (x1, y1, x2, y2). Pulling it all together, here's an example of a Bezier curve in CSS code: +animation-timing-function: cubic-bezier(0.25, 0.25, 0.75, 0.75); +In the example above, the x and y values are equivalent for each point (x1 = 0.25 = y1 and x2 = 0.75 = y2), which if you remember from geometry class, results in a line that extends from the origin to point (1, 1). This animation is a linear change of an element during the length of an animation, and is the same as using the linear keyword. In other words, it changes at a constant speed. +
+ +## Instructions +
+For the element with the id of ball1, change the value of the animation-timing-function property from linear to its equivalent cubic-bezier function value. Use the point values given in the example above. +
+ +## Tests +
+ +```yml +- text: The value of the animation-timing-function property for the element with the id ball1 should be the linear-equivalent cubic-bezier function. + testString: 'assert($("#ball1").css("animation-timing-function") == "cubic-bezier(0.25, 0.25, 0.75, 0.75)", "The value of the animation-timing-function property for the element with the id ball1 should be the linear-equivalent cubic-bezier function.");' +- text: The value of the animation-timing-function property for the element with the id ball2 should not change. + testString: 'assert($("#ball2").css("animation-timing-function") == "ease-out", "The value of the animation-timing-function property for the element with the id ball2 should not change.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + + +
+
+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/applied-visual-design/Learn How the CSS @keyframes and animation Properties Work.md b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Learn How the CSS @keyframes and animation Properties Work.md new file mode 100644 index 0000000000..30e223b4f6 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Learn How the CSS @keyframes and animation Properties Work.md @@ -0,0 +1,83 @@ +--- +id: 587d78a7367417b2b2512adf +title: Learn How the CSS @keyframes and animation Properties Work +challengeType: 0 +videoUrl: 'https://scrimba.com/c/cakprhv' +--- + +## Description +
+To animate an element, you need to know about the animation properties and the @keyframes rule. The animation properties control how the animation should behave and the @keyframes rule controls what happens during that animation. There are eight animation properties in total. This challenge will keep it simple and cover the two most important ones first: +animation-name sets the name of the animation, which is later used by @keyframes to tell CSS which rules go with which animations. +animation-duration sets the length of time for the animation. +@keyframes is how to specify exactly what happens within the animation over the duration. This is done by giving CSS properties for specific "frames" during the animation, with percentages ranging from 0% to 100%. If you compare this to a movie, the CSS properties for 0% is how the element displays in the opening scene. The CSS properties for 100% is how the element appears at the end, right before the credits roll. Then CSS applies the magic to transition the element over the given duration to act out the scene. Here's an example to illustrate the usage of @keyframes and the animation properties: +
#anim {
  animation-name: colorful;
  animation-duration: 3s;
}
@keyframes colorful {
  0% {
    background-color: blue;
  }
  100% {
    background-color: yellow;
  }
}
+For the element with the anim id, the code snippet above sets the animation-name to colorful and sets the animation-duration to 3 seconds. Then the @keyframes rule links to the animation properties with the name colorful. It sets the color to blue at the beginning of the animation (0%) which will transition to yellow by the end of the animation (100%). You aren't limited to only beginning-end transitions, you can set properties for the element for any percentage between 0% and 100%. +
+ +## Instructions +
+Create an animation for the element with the id rect, by setting the animation-name to rainbow and the animation-duration to 4 seconds. Next, declare a @keyframes rule, and set the background-color at the beginning of the animation (0%) to blue, the middle of the animation (50%) to green, and the end of the animation (100%) to yellow. +
+ +## Tests +
+ +```yml +- text: The element with id of rect should have an animation-name property with a value of rainbow. + testString: 'assert($("#rect").css("animation-name") == "rainbow", "The element with id of rect should have an animation-name property with a value of rainbow.");' +- text: The element with id of rect should have an animation-duration property with a value of 4s. + testString: 'assert($("#rect").css("animation-duration") == "4s", "The element with id of rect should have an animation-duration property with a value of 4s.");' +- text: The @keyframes rule should use the animation-name of rainbow. + testString: 'assert(code.match(/@keyframes\s+?rainbow\s*?{/g), "The @keyframes rule should use the animation-name of rainbow.");' +- text: The @keyframes rule for rainbow should use a background-color of blue at 0%. + testString: 'assert(code.match(/0%\s*?{\s*?background-color:\s*?blue;\s*?}/gi), "The @keyframes rule for rainbow should use a background-color of blue at 0%.");' +- text: The @keyframes rule for rainbow should use a background-color of green at 50%. + testString: 'assert(code.match(/50%\s*?{\s*?background-color:\s*?green;\s*?}/gi), "The @keyframes rule for rainbow should use a background-color of green at 50%.");' +- text: The @keyframes rule for rainbow should use a background-color of yellow at 100%. + testString: 'assert(code.match(/100%\s*?{\s*?background-color:\s*?yellow;\s*?}/gi), "The @keyframes rule for rainbow should use a background-color of yellow at 100%.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + +
+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/applied-visual-design/Learn about Complementary Colors.md b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Learn about Complementary Colors.md new file mode 100644 index 0000000000..f4cab74041 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Learn about Complementary Colors.md @@ -0,0 +1,75 @@ +--- +id: 587d78a3367417b2b2512ad1 +title: Learn about Complementary Colors +challengeType: 0 +videoUrl: 'https://scrimba.com/c/c2MD3Tr' +--- + +## Description +
+Color theory and its impact on design is a deep topic and only the basics are covered in the following challenges. On a website, color can draw attention to content, evoke emotions, or create visual harmony. Using different combinations of colors can really change the look of a website, and a lot of thought can go into picking a color palette that works with your content. +The color wheel is a useful tool to visualize how colors relate to each other - it's a circle where similar hues are neighbors and different hues are farther apart. When two colors are opposite each other on the wheel, they are called complementary colors. They have the characteristic that if they are combined, they "cancel" each other out and create a gray color. However, when placed side-by-side, these colors appear more vibrant and produce a strong visual contrast. +Some examples of complementary colors with their hex codes are: +
red (#FF0000) and cyan (#00FFFF)
green (#00FF00) and magenta (#FF00FF)
blue (#0000FF) and yellow (#FFFF00)
+This is different than the outdated RYB color model that many of us were taught in school, which has different primary and complementary colors. Modern color theory uses the additive RGB model (like on a computer screen) and the subtractive CMY(K) model (like in printing). Read here for more information on this complex subject. +There are many color picking tools available online that have an option to find the complement of a color. +Note
For all color challenges: Using color can be a powerful way to add visual interest to a page. However, color alone should not be used as the only way to convey important information because users with visual impairments may not understand that content. This issue will be covered in more detail in the Applied Accessibility challenges. +
+ +## Instructions +
+Change the background-color property of the blue and yellow classes to their respective colors. Notice how the colors look different next to each other than they do compared against the white background. +
+ +## Tests +
+ +```yml +- text: The div element with class blue should have a background-color of blue. + testString: 'assert($(".blue").css("background-color") == "rgb(0, 0, 255)", "The div element with class blue should have a background-color of blue.");' +- text: The div element with class yellow should have a background-color of yellow. + testString: 'assert($(".yellow").css("background-color") == "rgb(255, 255, 0)", "The div element with class yellow should have a background-color of yellow.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + +
+
+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/applied-visual-design/Learn about Tertiary Colors.md b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Learn about Tertiary Colors.md new file mode 100644 index 0000000000..7c0c126c25 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Learn about Tertiary Colors.md @@ -0,0 +1,84 @@ +--- +id: 587d78a4367417b2b2512ad2 +title: Learn about Tertiary Colors +challengeType: 0 +videoUrl: 'https://scrimba.com/c/c3bRDAb' +--- + +## Description +
+Computer monitors and device screens create different colors by combining amounts of red, green, and blue light. This is known as the RGB additive color model in modern color theory. Red (R), green (G), and blue (B) are called primary colors. Mixing two primary colors creates the secondary colors cyan (G + B), magenta (R + B) and yellow (R + G). You saw these colors in the Complementary Colors challenge. These secondary colors happen to be the complement to the primary color not used in their creation, and are opposite to that primary color on the color wheel. For example, magenta is made with red and blue, and is the complement to green. +Tertiary colors are the result of combining a primary color with one of its secondary color neighbors. For example, red (primary) and yellow (secondary) make orange. This adds six more colors to a simple color wheel for a total of twelve. +There are various methods of selecting different colors that result in a harmonious combination in design. One example that can use tertiary colors is called the split-complementary color scheme. This scheme starts with a base color, then pairs it with the two colors that are adjacent to its complement. The three colors provide strong visual contrast in a design, but are more subtle than using two complementary colors. +Here are three colors created using the split-complement scheme: +
ColorHex Code
orange#FF7D00
cyan#00FFFF
raspberry#FF007D
+
+ +## Instructions +
+Change the background-color property of the orange, cyan, and raspberry classes to their respective colors. Make sure to use the hex codes as orange and raspberry are not browser-recognized color names. +
+ +## Tests +
+ +```yml +- text: The div element with class orange should have a background-color of orange. + testString: 'assert($(".orange").css("background-color") == "rgb(255, 125, 0)", "The div element with class orange should have a background-color of orange.");' +- text: The div element with class cyan should have a background-color of cyan. + testString: 'assert($(".cyan").css("background-color") == "rgb(0, 255, 255)", "The div element with class cyan should have a background-color of cyan.");' +- text: The div element with class raspberry should have a background-color of raspberry. + testString: 'assert($(".raspberry").css("background-color") == "rgb(255, 0, 125)", "The div element with class raspberry should have a background-color of raspberry.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + + +
+
+
+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/applied-visual-design/Lock an Element to its Parent with Absolute Positioning.md b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Lock an Element to its Parent with Absolute Positioning.md new file mode 100644 index 0000000000..29d9aa545c --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Lock an Element to its Parent with Absolute Positioning.md @@ -0,0 +1,74 @@ +--- +id: 587d781e367417b2b2512acb +title: Lock an Element to its Parent with Absolute Positioning +challengeType: 0 +videoUrl: 'https://scrimba.com/c/cyLJ7c3' +--- + +## Description +
+The next option for the CSS position property is absolute, which locks the element in place relative to its parent container. Unlike the relative position, this removes the element from the normal flow of the document, so surrounding items ignore it. The CSS offset properties (top or bottom and left or right) are used to adjust the position. +One nuance with absolute positioning is that it will be locked relative to its closest positioned ancestor. If you forget to add a position rule to the parent item, (this is typically done using position: relative;), the browser will keep looking up the chain and ultimately default to the body tag. +
+ +## Instructions +
+Lock the #searchbar element to the top-right of its section parent by declaring its position as absolute. Give it top and right offsets of 50 pixels each. +
+ +## Tests +
+ +```yml +- text: 'The #searchbar element should have a position set to absolute.' + testString: 'assert($("#searchbar").css("position") == "absolute", "The #searchbar element should have a position set to absolute.");' +- text: 'Your code should use the top CSS offset of 50 pixels on the #searchbar element.' + testString: 'assert($("#searchbar").css("top") == "50px", "Your code should use the top CSS offset of 50 pixels on the #searchbar element.");' +- text: 'Your code should use the right CSS offset of 50 pixels on the #searchbar element.' + testString: 'assert($("#searchbar").css("right") == "50px", "Your code should use the right CSS offset of 50 pixels on the #searchbar element.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + + +

Welcome!

+
+ +
+ +``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/applied-visual-design/Lock an Element to the Browser Window with Fixed Positioning.md b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Lock an Element to the Browser Window with Fixed Positioning.md new file mode 100644 index 0000000000..22f326769c --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Lock an Element to the Browser Window with Fixed Positioning.md @@ -0,0 +1,86 @@ +--- +id: 587d781e367417b2b2512acc +title: Lock an Element to the Browser Window with Fixed Positioning +challengeType: 0 +videoUrl: 'https://scrimba.com/c/c2MDNUR' +--- + +## Description +
+The next layout scheme that CSS offers is the fixed position, which is a type of absolute positioning that locks an element relative to the browser window. Similar to absolute positioning, it's used with the CSS offset properties and also removes the element from the normal flow of the document. Other items no longer "realize" where it is positioned, which may require some layout adjustments elsewhere. +One key difference between the fixed and absolute positions is that an element with a fixed position won't move when the user scrolls. +
+ +## Instructions +
+The navigation bar in the code is labeled with an id of navbar. Change its position to fixed, and offset it 0 pixels from the top and 0 pixels from the left. Notice the (lack of) impact to the h1 position, it hasn't been pushed down to accommodate the navigation bar and would need to be adjusted separately. +
+ +## Tests +
+ +```yml +- text: 'The #navbar element should have a position set to fixed.' + testString: 'assert($("#navbar").css("position") == "fixed", "The #navbar element should have a position set to fixed.");' +- text: 'Your code should use the top CSS offset of 0 pixels on the #navbar element.' + testString: 'assert($("#navbar").css("top") == "0px", "Your code should use the top CSS offset of 0 pixels on the #navbar element.");' +- text: 'Your code should use the left CSS offset of 0 pixels on the #navbar element.' + testString: 'assert($("#navbar").css("left") == "0px", "Your code should use the left CSS offset of 0 pixels on the #navbar element.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + + +
+

Welcome!

+ +
+

I shift up when the #navbar is fixed to the browser window.

+ +``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/applied-visual-design/Make Motion More Natural Using a Bezier Curve.md b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Make Motion More Natural Using a Bezier Curve.md new file mode 100644 index 0000000000..1235d57b4e --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Make Motion More Natural Using a Bezier Curve.md @@ -0,0 +1,89 @@ +--- +id: 587d78a9367417b2b2512aea +title: Make Motion More Natural Using a Bezier Curve +challengeType: 0 +videoUrl: 'https://scrimba.com/c/c7akWUv' +--- + +## Description +
+This challenge animates an element to replicate the movement of a ball being juggled. Prior challenges covered the linear and ease-out cubic Bezier curves, however neither depicts the juggling movement accurately. You need to customize a Bezier curve for this. +The animation-timing-function automatically loops at every keyframe when the animation-iteration-count is set to infinite. Since there is a keyframe rule set in the middle of the animation duration (at 50%), it results in two identical animation progressions at the upward and downward movement of the ball. +The following cubic Bezier curve simulates a juggling movement: +cubic-bezier(0.3, 0.4, 0.5, 1.6); +Notice that the value of y2 is larger than 1. Although the cubic Bezier curve is mapped on an 1 by 1 coordinate system, and it can only accept x values from 0 to 1, the y value can be set to numbers larger than one. This results in a bouncing movement that is ideal for simulating the juggling ball. +
+ +## Instructions +
+Change value of the animation-timing-function of the element with the id of green to a cubic-bezier function with x1, y1, x2, y2 values set respectively to 0.311, 0.441, 0.444, 1.649. +
+ +## Tests +
+ +```yml +- text: 'The value of the animation-timing-function property for the element with the id green should be a cubic-bezier function with x1, y1, x2, y2 values as specified.' + testString: 'assert($("#green").css("animation-timing-function") == "cubic-bezier(0.311, 0.441, 0.444, 1.649)", "The value of the animation-timing-function property for the element with the id green should be a cubic-bezier function with x1, y1, x2, y2 values as specified.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + +
+
+
+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/applied-visual-design/Make a CSS Heartbeat using an Infinite Animation Count.md b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Make a CSS Heartbeat using an Infinite Animation Count.md new file mode 100644 index 0000000000..b7bf150f5e --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Make a CSS Heartbeat using an Infinite Animation Count.md @@ -0,0 +1,121 @@ +--- +id: 587d78a8367417b2b2512ae4 +title: Make a CSS Heartbeat using an Infinite Animation Count +challengeType: 0 +videoUrl: 'https://scrimba.com/c/cDZpDUr' +--- + +## Description +
+Here's one more continuous animation example with the animation-iteration-count property that uses the heart you designed in a previous challenge. +The one-second long heartbeat animation consists of two animated pieces. The heart elements (including the :before and :after pieces) are animated to change size using the transform property, and the background div is animated to change its color using the background property. +
+ +## Instructions +
+Keep the heart beating by adding the animation-iteration-count property for both the back class and the heart class and setting the value to infinite. The heart:before and heart:after selectors do not need any animation properties. +
+ +## Tests +
+ +```yml +- text: The animation-iteration-count property for the heart class should have a value of infinite. + testString: 'assert($(".heart").css("animation-iteration-count") == "infinite", "The animation-iteration-count property for the heart class should have a value of infinite.");' +- text: The animation-iteration-count property for the back class should have a value of infinite. + testString: 'assert($(".back").css("animation-iteration-count") == "infinite", "The animation-iteration-count property for the back class should have a value of infinite.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + +
+
+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/applied-visual-design/Modify Fill Mode of an Animation.md b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Modify Fill Mode of an Animation.md new file mode 100644 index 0000000000..803091d95e --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Modify Fill Mode of an Animation.md @@ -0,0 +1,74 @@ +--- +id: 58a7a6ebf9a6318348e2d5aa +title: Modify Fill Mode of an Animation +challengeType: 0 +videoUrl: 'https://scrimba.com/c/cVJDmcE' +--- + +## Description +
+That's great, but it doesn't work right yet. Notice how the animation resets after 500ms has passed, causing the button to revert back to the original color. You want the button to stay highlighted. +This can be done by setting the animation-fill-mode property to forwards. The animation-fill-mode specifies the style applied to an element when the animation has finished. You can set it like so: +animation-fill-mode: forwards; +
+ +## Instructions +
+Set the animation-fill-mode property of button:hover to forwards so the button stays highlighted when a user hovers over it. +
+ +## Tests +
+ +```yml +- text: 'button:hover should have a animation-fill-mode property with a value of forwards.' + testString: 'assert(code.match(/button\s*?:\s*?hover\s*?{[\s\S]*animation-fill-mode\s*?:\s*?forwards\s*?;[\s\S]*}/gi) && code.match(/button\s*?:\s*?hover\s*?{[\s\S]*animation-name\s*?:\s*?background-color\s*?;[\s\S]*}/gi) && code.match(/button\s*?:\s*?hover\s*?{[\s\S]*animation-duration\s*?:\s*?500ms\s*?;[\s\S]*}/gi), "button:hover should have a animation-fill-mode property with a value of forwards.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + + +``` + +
+ + + +
+ +## Solution +
+ + +```js +var code = "button:hover {animation-name: background-color; animation-duration: 500ms; animation-fill-mode: forwards;}" +``` + +
diff --git a/curriculum/challenges/01-responsive-web-design/applied-visual-design/Move a Relatively Positioned Element with CSS Offsets.md b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Move a Relatively Positioned Element with CSS Offsets.md new file mode 100644 index 0000000000..e6be6abba1 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Move a Relatively Positioned Element with CSS Offsets.md @@ -0,0 +1,66 @@ +--- +id: 587d781e367417b2b2512aca +title: Move a Relatively Positioned Element with CSS Offsets +challengeType: 0 +videoUrl: 'https://scrimba.com/c/c9bQEA4' +--- + +## Description +
+The CSS offsets of top or bottom, and left or right tell the browser how far to offset an item relative to where it would sit in the normal flow of the document. You're offsetting an element away from a given spot, which moves the element away from the referenced side (effectively, the opposite direction). As you saw in the last challenge, using the top offset moved the h2 downwards. Likewise, using a left offset moves an item to the right. + />
+</section>
+
+## Instructions
+<section id='instructions'>
+Use CSS offsets to move the <code>h2</code> 15 pixels to the right and 10 pixels up.
+</section>
+
+## Tests
+<section id='tests'>
+
+```yml
+- text: 'Your code should use a CSS offset to relatively position the <code>h2</code> 10px upwards. In other words, move it 10px away from the <code>bottom</code> of where it normally sits.'
+  testString: 'assert($(h2 10px upwards. In other words, move it 10px away from the bottom of where it normally sits.");' +- text: 'Your code should use a CSS offset to relatively position the h2 15px towards the right. In other words, move it 15px away from the left of where it normally sits.' + testString: 'assert($("h2").css("left") == "15px", "Your code should use a CSS offset to relatively position the h2 15px towards the right. In other words, move it 15px away from the left of where it normally sits.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + + + + +

On Being Well-Positioned

+

Move me!

+

I still think the h2 is where it normally sits.

+ +``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/applied-visual-design/Push Elements Left or Right with the float Property.md b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Push Elements Left or Right with the float Property.md new file mode 100644 index 0000000000..6d3df284fe --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Push Elements Left or Right with the float Property.md @@ -0,0 +1,80 @@ +--- +id: 587d78a3367417b2b2512ace +title: Push Elements Left or Right with the float Property +challengeType: 0 +videoUrl: 'https://scrimba.com/c/c2MDqu2' +--- + +## Description +
+The next positioning tool does not actually use position, but sets the float property of an element. Floating elements are removed from the normal flow of a document and pushed to either the left or right of their containing parent element. It's commonly used with the width property to specify how much horizontal space the floated element requires. +
+ +## Instructions +
+The given markup would work well as a two-column layout, with the section and aside elements next to each other. Give the #left item a float of left and the #right item a float of right. +
+ +## Tests +
+ +```yml +- text: The element with id left should have a float value of left. + testString: 'assert($("#left").css("float") == "left", "The element with id left should have a float value of left.");' +- text: The element with id right should have a float value of right. + testString: 'assert($("#right").css("float") == "right", "The element with id right should have a float value of right.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + + + + +
+

Welcome!

+
+
+

Content

+

Good stuff

+
+ + +``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/applied-visual-design/Set the font-size for Multiple Heading Elements.md b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Set the font-size for Multiple Heading Elements.md new file mode 100644 index 0000000000..05f123b6a2 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Set the font-size for Multiple Heading Elements.md @@ -0,0 +1,73 @@ +--- +id: 587d781c367417b2b2512ac2 +title: Set the font-size for Multiple Heading Elements +challengeType: 0 +videoUrl: 'https://scrimba.com/c/cPpQNT3' +--- + +## Description +
+The font-size property is used to specify how large the text is in a given element. This rule can be used for multiple elements to create visual consistency of text on a page. In this challenge, you'll set the values for all h1 through h6 tags to balance the heading sizes. +
+ +## Instructions +
+ +
+ +## Tests +
+ +```yml +- text: Your code should set the font-size property for the h1 tag to 68 pixels. + testString: 'assert($("h1").css("font-size") == "68px", "Your code should set the font-size property for the h1 tag to 68 pixels.");' +- text: Your code should set the font-size property for the h2 tag to 52 pixels. + testString: 'assert($("h2").css("font-size") == "52px", "Your code should set the font-size property for the h2 tag to 52 pixels.");' +- text: Your code should set the font-size property for the h3 tag to 40 pixels. + testString: 'assert($("h3").css("font-size") == "40px", "Your code should set the font-size property for the h3 tag to 40 pixels.");' +- text: Your code should set the font-size property for the h4 tag to 32 pixels. + testString: 'assert($("h4").css("font-size") == "32px", "Your code should set the font-size property for the h4 tag to 32 pixels.");' +- text: Your code should set the font-size property for the h5 tag to 21 pixels. + testString: 'assert($("h5").css("font-size") == "21px", "Your code should set the font-size property for the h5 tag to 21 pixels.");' +- text: Your code should set the font-size property for the h6 tag to 14 pixels. + testString: 'assert($("h6").css("font-size") == "14px", "Your code should set the font-size property for the h6 tag to 14 pixels.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + +

This is h1 text

+

This is h2 text

+

This is h3 text

+

This is h4 text

+
This is h5 text
+
This is h6 text
+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/applied-visual-design/Set the font-size of Paragraph Text.md b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Set the font-size of Paragraph Text.md new file mode 100644 index 0000000000..8b43b61179 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Set the font-size of Paragraph Text.md @@ -0,0 +1,57 @@ +--- +id: 587d781c367417b2b2512ac4 +title: Set the font-size of Paragraph Text +challengeType: 0 +videoUrl: 'https://scrimba.com/c/cVJ36Cr' +--- + +## Description +
+The font-size property in CSS is not limited to headings, it can be applied to any element containing text. +
+ +## Instructions +
+Change the value of the font-size property for the paragraph to 16px to make it more visible. +
+ +## Tests +
+ +```yml +- text: Your p tag should have a font-size of 16 pixels. + testString: 'assert($("p").css("font-size") == "16px", "Your p tag should have a font-size of 16 pixels.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + +

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. +

+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/applied-visual-design/Set the font-weight for Multiple Heading Elements.md b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Set the font-weight for Multiple Heading Elements.md new file mode 100644 index 0000000000..6c779c490b --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Set the font-weight for Multiple Heading Elements.md @@ -0,0 +1,92 @@ +--- +id: 587d781c367417b2b2512ac3 +title: Set the font-weight for Multiple Heading Elements +challengeType: 0 +videoUrl: 'https://scrimba.com/c/crVWRHq' +--- + +## Description +
+You set the font-size of each heading tag in the last challenge, here you'll adjust the font-weight. +The font-weight property sets how thick or thin characters are in a section of text. +
+ +## Instructions +
+ +
+ +## Tests +
+ +```yml +- text: Your code should set the font-weight property for the h1 tag to 800. + testString: 'assert($("h1").css("font-weight") == "800", "Your code should set the font-weight property for the h1 tag to 800.");' +- text: Your code should set the font-weight property for the h2 tag to 600. + testString: 'assert($("h2").css("font-weight") == "600", "Your code should set the font-weight property for the h2 tag to 600.");' +- text: Your code should set the font-weight property for the h3 tag to 500. + testString: 'assert($("h3").css("font-weight") == "500", "Your code should set the font-weight property for the h3 tag to 500.");' +- text: Your code should set the font-weight property for the h4 tag to 400. + testString: 'assert($("h4").css("font-weight") == "400", "Your code should set the font-weight property for the h4 tag to 400.");' +- text: Your code should set the font-weight property for the h5 tag to 300. + testString: 'assert($("h5").css("font-weight") == "300", "Your code should set the font-weight property for the h5 tag to 300.");' +- text: Your code should set the font-weight property for the h6 tag to 200. + testString: 'assert($("h6").css("font-weight") == "200", "Your code should set the font-weight property for the h6 tag to 200.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + +

This is h1 text

+

This is h2 text

+

This is h3 text

+

This is h4 text

+
This is h5 text
+
This is h6 text
+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/applied-visual-design/Set the line-height of Paragraphs.md b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Set the line-height of Paragraphs.md new file mode 100644 index 0000000000..737596ea63 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Set the line-height of Paragraphs.md @@ -0,0 +1,58 @@ +--- +id: 587d781d367417b2b2512ac5 +title: Set the line-height of Paragraphs +challengeType: 0 +videoUrl: 'https://scrimba.com/c/crVWdcv' +--- + +## Description +
+CSS offers the line-height property to change the height of each line in a block of text. As the name suggests, it changes the amount of vertical space that each line of text gets. +
+ +## Instructions +
+Add a line-height property to the p tag and set it to 25px. +
+ +## Tests +
+ +```yml +- text: Your code should set the line-height of the p tag to 25 pixels. + testString: 'assert($("p").css("line-height") == "25px", "Your code should set the line-height of the p tag to 25 pixels.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + +

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. +

+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/applied-visual-design/Use CSS Animation to Change the Hover State of a Button.md b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Use CSS Animation to Change the Hover State of a Button.md new file mode 100644 index 0000000000..aac23936bb --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Use CSS Animation to Change the Hover State of a Button.md @@ -0,0 +1,71 @@ +--- +id: 587d78a7367417b2b2512ae0 +title: Use CSS Animation to Change the Hover State of a Button +challengeType: 0 +videoUrl: 'https://scrimba.com/c/cg4vZAa' +--- + +## Description +
+You can use CSS @keyframes to change the color of a button in its hover state. +Here's an example of changing the width of an image on hover: +
<style>
  img:hover {
    animation-name: width;
    animation-duration: 500ms;
  }

  @keyframes width {
    100% {
      width: 40px;
    }
  }
</style>

<img src="https://bit.ly/smallgooglelogo" alt="Google's Logo" />
+
+ +## Instructions +
+Note that ms stands for milliseconds, where 1000ms is equal to 1s. +Use CSS @keyframes to change the background-color of the button element so it becomes #4791d0 when a user hovers over it. The @keyframes rule should only have an entry for 100%. +
+ +## Tests +
+ +```yml +- text: The @keyframes rule should use the animation-name background-color. + testString: 'assert(code.match(/@keyframes\s+?background-color\s*?{/g), "The @keyframes rule should use the animation-name background-color.");' +- text: 'There should be one rule under @keyframes that changes the background-color to #4791d0 at 100%.' + testString: 'assert(code.match(/100%\s*?{\s*?background-color:\s*?#4791d0;\s*?}/gi), "There should be one rule under @keyframes that changes the background-color to #4791d0 at 100%.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + + + +``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/applied-visual-design/Use a Bezier Curve to Move a Graphic.md b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Use a Bezier Curve to Move a Graphic.md new file mode 100644 index 0000000000..0873519399 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Use a Bezier Curve to Move a Graphic.md @@ -0,0 +1,88 @@ +--- +id: 587d78a9367417b2b2512ae9 +title: Use a Bezier Curve to Move a Graphic +challengeType: 0 +videoUrl: 'https://scrimba.com/c/c6bnRCK' +--- + +## Description +
+A previous challenge discussed the ease-out keyword that describes an animation change that speeds up first and then slows down at the end of the animation. On the right, the difference between the ease-out keyword (for the blue element) and linear keyword (for the red element) is demonstrated. Similar animation progressions to the ease-out keyword can be achieved by using a custom cubic Bezier curve function. +In general, changing the p1 and p2 anchor points drives the creation of different Bezier curves, which controls how the animation progresses through time. Here's an example of a Bezier curve using values to mimic the ease-out style: +animation-timing-function: cubic-bezier(0, 0, 0.58, 1); +Remember that all cubic-bezier functions start with p0 at (0, 0) and end with p3 at (1, 1). In this example, the curve moves faster through the Y-axis (starts at 0, goes to p1 y value of 0, then goes to p2 y value of 1) than it moves through the X-axis (0 to start, then 0 for p1, up to 0.58 for p2). As a result, the change in the animated element progresses faster than the time of the animation for that segment. Towards the end of the curve, the relationship between the change in x and y values reverses - the y value moves from 1 to 1 (no change), and the x values move from 0.58 to 1, making the animation changes progress slower compared to the animation duration. +
+ +## Instructions +
+To see the effect of this Bezier curve in action, change the animation-timing-function of the element with id of red to a cubic-bezier function with x1, y1, x2, y2 values set respectively to 0, 0, 0.58, 1. This will make both elements progress through the animation similarly. +
+ +## Tests +
+ +```yml +- text: 'The value of the animation-timing-function property of the element with the id red should be a cubic-bezier function with x1, y1, x2, y2 values set respectively to 0, 0, 0.58, 1 .' + testString: 'assert($("#red").css("animation-timing-function") == "cubic-bezier(0, 0, 0.58, 1)", "The value of the animation-timing-function property of the element with the id red should be a cubic-bezier function with x1, y1, x2, y2 values set respectively to 0, 0, 0.58, 1 .");' +- text: The element with the id red should no longer have the animation-timing-function property of linear. + testString: 'assert($("#red").css("animation-timing-function") !== "linear", "The element with the id red should no longer have the animation-timing-function property of linear.");' +- text: The value of the animation-timing-function property for the element with the id blue should not change. + testString: 'assert($("#blue").css("animation-timing-function") == "ease-out", "The value of the animation-timing-function property for the element with the id blue should not change.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + +
+
+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/applied-visual-design/Use a CSS Linear Gradient to Create a Striped Element.md b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Use a CSS Linear Gradient to Create a Striped Element.md new file mode 100644 index 0000000000..a6bded2d26 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Use a CSS Linear Gradient to Create a Striped Element.md @@ -0,0 +1,85 @@ +--- +id: 587d78a5367417b2b2512ad7 +title: Use a CSS Linear Gradient to Create a Striped Element +challengeType: 0 +videoUrl: 'https://scrimba.com/c/c6bmQh2' +--- + +## Description +
+The repeating-linear-gradient() function is very similar to linear-gradient() with the major difference that it repeats the specified gradient pattern. repeating-linear-gradient() accepts a variety of values, but for simplicity, you'll work with an angle value and color stop values in this challenge. +The angle value is the direction of the gradient. Color stops are like width values that mark where a transition takes place, and are given with a percentage or a number of pixels. +In the example demonstrated in the code editor, the gradient starts with the color yellow at 0 pixels which blends into the second color blue at 40 pixels away from the start. Since the next color stop is also at 40 pixels, the gradient immediately changes to the third color green, which itself blends into the fourth color value red as that is 80 pixels away from the beginning of the gradient. +For this example, it helps to think about the color stops as pairs where every two colors blend together. +0px [yellow -- blend -- blue] 40px [green -- blend -- red] 80px +If every two color stop values are the same color, the blending isn't noticeable because it's between the same color, followed by a hard transition to the next color, so you end up with stripes. +
+ +## Instructions +
+Make stripes by changing the repeating-linear-gradient() to use a gradient angle of 45deg, then set the first two color stops to yellow, and finally the second two color stops to black. +
+ +## Tests +
+ +```yml +- text: The angle of the repeating-linear-gradient() should be 45deg. + testString: 'assert(code.match(/background:\s*?repeating-linear-gradient\(\s*?45deg/gi), "The angle of the repeating-linear-gradient() should be 45deg.");' +- text: The angle of the repeating-linear-gradient() should no longer be 90deg + testString: 'assert(!code.match(/90deg/gi), "The angle of the repeating-linear-gradient() should no longer be 90deg");' +- text: The color stop at 0 pixels should be yellow. + testString: 'assert(code.match(/yellow\s+?0(px)?/gi), "The color stop at 0 pixels should be yellow.");' +- text: One color stop at 40 pixels should be yellow. + testString: 'assert(code.match(/yellow\s+?40px/gi), "One color stop at 40 pixels should be yellow.");' +- text: The second color stop at 40 pixels should be black. + testString: 'assert(code.match(/yellow\s+?40px,\s*?black\s+?40px/gi), "The second color stop at 40 pixels should be black.");' +- text: The last color stop at 80 pixels should be black. + testString: 'assert(code.match(/black\s+?80px/gi), "The last color stop at 80 pixels should be black.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + + +
+``` + +
+ + + +
+ +## Solution +
+ + +```js +var code = "background: repeating-linear-gradient(45deg, yellow 0px, yellow 40px, black 40px, black 80px);" +``` + +
diff --git a/curriculum/challenges/01-responsive-web-design/applied-visual-design/Use the CSS Transform Property skewX to Skew an Element Along the X-Axis.md b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Use the CSS Transform Property skewX to Skew an Element Along the X-Axis.md new file mode 100644 index 0000000000..49957d04c9 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Use the CSS Transform Property skewX to Skew an Element Along the X-Axis.md @@ -0,0 +1,70 @@ +--- +id: 587d78a6367417b2b2512adb +title: Use the CSS Transform Property skewX to Skew an Element Along the X-Axis +challengeType: 0 +videoUrl: 'https://scrimba.com/c/cyLP8Sr' +--- + +## Description +
+The next function of the transform property is skewX(), which skews the selected element along its X (horizontal) axis by a given degree. +The following code skews the paragraph element by -32 degrees along the X-axis. +
p {
  transform: skewX(-32deg);
}
+
+ +## Instructions +
+Skew the element with the id of bottom by 24 degrees along the X-axis by using the transform property. +
+ +## Tests +
+ +```yml +- text: The element with id bottom should be skewed by 24 degrees along its X-axis. + testString: 'assert(code.match(/#bottom\s*?{\s*?.*?\s*?transform:\s*?skewX\(24deg\);/g), "The element with id bottom should be skewed by 24 degrees along its X-axis.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + + +
+
+``` + +
+ + + +
+ +## Solution +
+ + +```js +var code = "#bottom {background-color: blue; transform: skewX(24deg);}" +``` + +
diff --git a/curriculum/challenges/01-responsive-web-design/applied-visual-design/Use the CSS Transform Property skewY to Skew an Element Along the Y-Axis.md b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Use the CSS Transform Property skewY to Skew an Element Along the Y-Axis.md new file mode 100644 index 0000000000..0b7dcd1dfc --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Use the CSS Transform Property skewY to Skew an Element Along the Y-Axis.md @@ -0,0 +1,69 @@ +--- +id: 587d78a6367417b2b2512adc +title: Use the CSS Transform Property skewY to Skew an Element Along the Y-Axis +challengeType: 0 +videoUrl: 'https://scrimba.com/c/c2MZ2uB' +--- + +## Description +
+Given that the skewX() function skews the selected element along the X-axis by a given degree, it is no surprise that the skewY() property skews an element along the Y (vertical) axis. +
+ +## Instructions +
+Skew the element with the id of top -10 degrees along the Y-axis by using the transform property. +
+ +## Tests +
+ +```yml +- text: The element with id top should be skewed by -10 degrees along its Y-axis. + testString: 'assert(code.match(/#top\s*?{\s*?.*?\s*?transform:\s*?skewY\(-10deg\);/g), "The element with id top should be skewed by -10 degrees along its Y-axis.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + + +
+
+``` + +
+ + + +
+ +## Solution +
+ + +```js +var code = "#top {background-color: red; transform: skewY(-10deg);}" +``` + +
diff --git a/curriculum/challenges/01-responsive-web-design/applied-visual-design/Use the CSS Transform scale Property to Change the Size of an Element.md b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Use the CSS Transform scale Property to Change the Size of an Element.md new file mode 100644 index 0000000000..84b045f3ac --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Use the CSS Transform scale Property to Change the Size of an Element.md @@ -0,0 +1,78 @@ +--- +id: 587d78a5367417b2b2512ad9 +title: Use the CSS Transform scale Property to Change the Size of an Element +challengeType: 0 +videoUrl: 'https://scrimba.com/c/c2MZVSg' +--- + +## Description +
+To change the scale of an element, CSS has the transform property, along with its scale() function. The following code example doubles the size of all the paragraph elements on the page: +
p {
  transform:scale(2);
}
+
+ +## Instructions +
+Increase the size of the element with the id of ball2 to 1.5 times its original size. +
+ +## Tests +
+ +```yml +- text: 'Set the transform property for #ball2 to scale it 1.5 times its size.' + testString: 'assert(code.match(/#ball2\s*?{\s*?left:\s*?65%;\s*?transform:\s*?scale\(1\.5\);\s*?}|#ball2\s*?{\s*?transform:\s*?scale\(1\.5\);\s*?left:\s*?65%;\s*?}/gi), "Set the transform property for #ball2 to scale it 1.5 times its size.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + + +
+
+``` + +
+ + + +
+ +## Solution +
+ + +```js +var code = "#ball2 {left: 65%; transform: scale(1.5);}" +``` + +
diff --git a/curriculum/challenges/01-responsive-web-design/applied-visual-design/Use the CSS Transform scale Property to Scale an Element on Hover.md b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Use the CSS Transform scale Property to Scale an Element on Hover.md new file mode 100644 index 0000000000..5ded9b4a15 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Use the CSS Transform scale Property to Scale an Element on Hover.md @@ -0,0 +1,70 @@ +--- +id: 587d78a5367417b2b2512ada +title: Use the CSS Transform scale Property to Scale an Element on Hover +challengeType: 0 +videoUrl: 'https://scrimba.com/c/cyLPJuM' +--- + +## Description +
+The transform property has a variety of functions that lets you scale, move, rotate, skew, etc., your elements. When used with pseudo-classes such as :hover that specify a certain state of an element, the transform property can easily add interactivity to your elements. +Here's an example to scale the paragraph elements to 2.1 times their original size when a user hovers over them: +
p:hover {
  transform: scale(2.1);
}
+
+ +## Instructions +
+Add a CSS rule for the hover state of the div and use the transform property to scale the div element to 1.1 times its original size when a user hovers over it. +
+ +## Tests +
+ +```yml +- text: The size of the div element should scale 1.1 times when the user hovers over it. + testString: 'assert(code.match(/div:hover\s*?{\s*?transform:\s*?scale\(1\.1\);/gi), "The size of the div element should scale 1.1 times when the user hovers over it.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + + +
+``` + +
+ + + +
+ +## Solution +
+ + +```js +var code = "div:hover {transform: scale(1.1);}" +``` + +
diff --git a/curriculum/challenges/01-responsive-web-design/applied-visual-design/Use the em Tag to Italicize Text.md b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Use the em Tag to Italicize Text.md new file mode 100644 index 0000000000..952b3b9064 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Use the em Tag to Italicize Text.md @@ -0,0 +1,89 @@ +--- +id: 587d781a367417b2b2512ab9 +title: Use the em Tag to Italicize Text +challengeType: 0 +videoUrl: 'https://scrimba.com/c/cVJRBtp' +--- + +## Description +
+To emphasize text, you can use the em tag. This displays text as italicized, as the browser applies the CSS of font-style: italic; to the element. +
+ +## Instructions +
+Wrap an em tag around the contents of the paragraph tag to give it emphasis. +
+ +## Tests +
+ +```yml +- text: Your code should add an em tag to the markup. + testString: 'assert($("em").length == 1, "Your code should add an em tag to the markup.");' +- text: The em tag should wrap around the contents of the p tag but not the p tag itself. + testString: 'assert($("p").children().length == 1 && $("em").children().length == 2, "The em tag should wrap around the contents of the p tag but not the p tag itself.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + +
+
+
+

Google

+

Google was founded by Larry Page and Sergey Brin while they were Ph.D. students at Stanford University.

+
+ +
+
+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/applied-visual-design/Use the s Tag to Strikethrough Text.md b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Use the s Tag to Strikethrough Text.md new file mode 100644 index 0000000000..c4c4e9131e --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Use the s Tag to Strikethrough Text.md @@ -0,0 +1,91 @@ +--- +id: 587d781b367417b2b2512aba +title: Use the s Tag to Strikethrough Text +challengeType: 0 +videoUrl: " +--- + +## Description +
+To strikethrough text, which is when a horizontal line cuts across the characters, you can use the s tag. It shows that a section of text is no longer valid. With the s tag, the browser applies the CSS of text-decoration: line-through; to the element. +
+ +## Instructions +
+Wrap the s tag around "Google" inside the h4 tag and then add the word Alphabet beside it, which should not have the strikethrough formatting. +
+ +## Tests +
+ +```yml +- text: Your code should add one s tag to the markup. + testString: 'assert($("s").length == 1, "Your code should add one s tag to the markup.");' +- text: A s tag should wrap around the Google text in the h4 tag. It should not contain the word Alphabet. + testString: 'assert($("s").text().match(/Google/gi) && !$("s").text().match(/Alphabet/gi), "A s tag should wrap around the Google text in the h4 tag. It should not contain the word Alphabet.");' +- text: 'Include the word Alphabet in the h4 tag, without strikethrough formatting.' + testString: 'assert($("h4").html().match(/Alphabet/gi), "Include the word Alphabet in the h4 tag, without strikethrough formatting.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + +
+
+
+

Google

+

Google was founded by Larry Page and Sergey Brin while they were Ph.D. students at Stanford University.

+
+ +
+
+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/applied-visual-design/Use the strong Tag to Make Text Bold.md b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Use the strong Tag to Make Text Bold.md new file mode 100644 index 0000000000..8cb73b1f62 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Use the strong Tag to Make Text Bold.md @@ -0,0 +1,91 @@ +--- +id: 587d781a367417b2b2512ab7 +title: Use the strong Tag to Make Text Bold +challengeType: 0 +videoUrl: 'https://scrimba.com/c/ceJNBSb' +--- + +## Description +
+To make text bold, you can use the strong tag. This is often used to draw attention to text and symbolize that it is important. With the strong tag, the browser applies the CSS of font-weight: bold; to the element. +
+ +## Instructions +
+Wrap a strong tag around "Stanford University" inside the p tag. +
+ +## Tests +
+ +```yml +- text: Your code should add one strong tag to the markup. + testString: 'assert($("strong").length == 1, "Your code should add one strong tag to the markup.");' +- text: The strong tag should be inside the p tag. + testString: 'assert($("p").children("strong").length == 1, "The strong tag should be inside the p tag.");' +- text: The strong tag should wrap around the words "Stanford University". + testString: 'assert($("strong").text().match(/^Stanford University$/gi), "The strong tag should wrap around the words "Stanford University".");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + +
+
+
+

Google

+

Google was founded by Larry Page and Sergey Brin while they were Ph.D. students at Stanford University.

+
+ +
+
+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/applied-visual-design/Use the text-transform Property to Make Text Uppercase.md b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Use the text-transform Property to Make Text Uppercase.md new file mode 100644 index 0000000000..f2a22f1b40 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Use the text-transform Property to Make Text Uppercase.md @@ -0,0 +1,99 @@ +--- +id: 587d781c367417b2b2512ac0 +title: Use the text-transform Property to Make Text Uppercase +challengeType: 0 +videoUrl: 'https://scrimba.com/c/cvVZQSP' +--- + +## Description +
+The text-transform property in CSS is used to change the appearance of text. It's a convenient way to make sure text on a webpage appears consistently, without having to change the text content of the actual HTML elements. +The following table shows how the different text-transformvalues change the example text "Transform me". +
ValueResult
lowercase"transform me"
uppercase"TRANSFORM ME"
capitalize"Transform Me"
initialUse the default value
inheritUse the text-transform value from the parent element
noneDefault: Use the original text
+
+ +## Instructions +
+Transform the text of the h4 to be uppercase using the text-transform property. +
+ +## Tests +
+ +```yml +- text: The h4 text should be uppercase. + testString: 'assert($("h4").css("text-transform") === "uppercase", "The h4 text should be uppercase.");' +- text: The original text of the h4 should not be changed. + testString: 'assert(($("h4").text() !== $("h4").text().toUpperCase()), "The original text of the h4 should not be changed.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + +
+
+
+

Alphabet

+
+

Google was founded by Larry Page and Sergey Brin while they were Ph.D. students at Stanford University.

+
+ +
+
+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/applied-visual-design/Use the u Tag to Underline Text.md b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Use the u Tag to Underline Text.md new file mode 100644 index 0000000000..3caaf830ad --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/applied-visual-design/Use the u Tag to Underline Text.md @@ -0,0 +1,90 @@ +--- +id: 587d781a367417b2b2512ab8 +title: Use the u Tag to Underline Text +challengeType: 0 +videoUrl: 'https://scrimba.com/c/cN6aQCL' +--- + +## Description +
+To underline text, you can use the u tag. This is often used to signify that a section of text is important, or something to remember. With the u tag, the browser applies the CSS of text-decoration: underline; to the element. +
+ +## Instructions +
+Wrap the u tag only around the text "Ph.D. students". +Note
Try to avoid using the u tag when it could be confused for a link. Anchor tags also have a default underlined formatting. +
+ +## Tests +
+ +```yml +- text: Your code should add a u tag to the markup. + testString: 'assert($("u").length === 1, "Your code should add a u tag to the markup.");' +- text: The u tag should wrap around the text "Ph.D. students". + testString: 'assert($("u").text() === "Ph.D. students", "The u tag should wrap around the text "Ph.D. students".");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + +
+
+
+

Google

+

Google was founded by Larry Page and Sergey Brin while they were Ph.D. students at Stanford University.

+
+ +
+
+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/applied-visual-design/meta.json b/curriculum/challenges/01-responsive-web-design/applied-visual-design/meta.json new file mode 100644 index 0000000000..f061f7847f --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/applied-visual-design/meta.json @@ -0,0 +1,8 @@ +{ + "name": "Applied Visual Design", + "dashedName": "applied-visual-design", + "order": 2, + "time": "5 hours", + "superBlock": "responsive-web-design", + "superOrder": 1 +} \ No newline at end of file diff --git a/curriculum/challenges/01-responsive-web-design/basic-css/Add Borders Around Your Elements.md b/curriculum/challenges/01-responsive-web-design/basic-css/Add Borders Around Your Elements.md new file mode 100644 index 0000000000..6e006a0e20 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/basic-css/Add Borders Around Your Elements.md @@ -0,0 +1,113 @@ +--- +id: bad87fee1348bd9bedf08813 +title: Add Borders Around Your Elements +challengeType: 0 +guideUrl: 'https://guide.freecodecamp.org/certificates/add-borders-around-your-elements' +videoUrl: 'https://scrimba.com/c/c2MvnHZ' +--- + +## Description +
+CSS borders have properties like style, color and width +For example, if we wanted to create a red, 5 pixel border around an HTML element, we could use this class: +
<style>
  .thin-red-border {
    border-color: red;
    border-width: 5px;
    border-style: solid;
  }
</style>
+
+ +## Instructions +
+Create a class called thick-green-border. This class should add a 10px, solid, green border around an HTML element. Apply the class to your cat photo. +Remember that you can apply multiple classes to an element using its class attribute, by separating each class name with a space. For example: +<img class="class1 class2"> +
+ +## Tests +
+ +```yml +- text: Your img element should have the class smaller-image. + testString: 'assert($("img").hasClass("smaller-image"), "Your img element should have the class smaller-image.");' +- text: Your img element should have the class thick-green-border. + testString: 'assert($("img").hasClass("thick-green-border"), "Your img element should have the class thick-green-border.");' +- text: Give your image a border width of 10px. + testString: 'assert($("img").hasClass("thick-green-border") && parseInt($("img").css("border-top-width"), 10) >= 8 && parseInt($("img").css("border-top-width"), 10) <= 12, "Give your image a border width of 10px.");' +- text: Give your image a border style of solid. + testString: 'assert($("img").css("border-right-style") === "solid", "Give your image a border style of solid.");' +- text: The border around your img element should be green. + testString: 'assert($("img").css("border-left-color") === "rgb(0, 128, 0)", "The border around your img element should be green.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + + + +

CatPhotoApp

+
+

Click here to view more cat photos.

+ + A cute orange cat lying on its back. + +
+

Things cats love:

+
    +
  • cat nip
  • +
  • laser pointers
  • +
  • lasagna
  • +
+

Top 3 things cats hate:

+
    +
  1. flea treatment
  2. +
  3. thunder
  4. +
  5. other cats
  6. +
+
+ +
+ +
+ + +
+ + +
+
+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/basic-css/Add Different Margins to Each Side of an Element.md b/curriculum/challenges/01-responsive-web-design/basic-css/Add Different Margins to Each Side of an Element.md new file mode 100644 index 0000000000..1b90383e38 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/basic-css/Add Different Margins to Each Side of an Element.md @@ -0,0 +1,94 @@ +--- +id: bad87fee1248bd9aedf08824 +title: Add Different Margins to Each Side of an Element +challengeType: 0 +videoUrl: 'https://scrimba.com/c/cg4RWh4' +--- + +## Description +
+Sometimes you will want to customize an element so that it has a different margin on each of its sides. +CSS allows you to control the margin of all four individual sides of an element with the margin-top, margin-right, margin-bottom, and margin-left properties. +
+ +## Instructions +
+Give the blue box a margin of 40px on its top and left side, but only 20px on its bottom and right side. +
+ +## Tests +
+ +```yml +- text: Your blue-box class should give the top of elements 40px of margin. + testString: 'assert($(".blue-box").css("margin-top") === "40px", "Your blue-box class should give the top of elements 40px of margin.");' +- text: Your blue-box class should give the right of elements 20px of margin. + testString: 'assert($(".blue-box").css("margin-right") === "20px", "Your blue-box class should give the right of elements 20px of margin.");' +- text: Your blue-box class should give the bottom of elements 20px of margin. + testString: 'assert($(".blue-box").css("margin-bottom") === "20px", "Your blue-box class should give the bottom of elements 20px of margin.");' +- text: Your blue-box class should give the left of elements 40px of margin. + testString: 'assert($(".blue-box").css("margin-left") === "40px", "Your blue-box class should give the left of elements 40px of margin.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + +
margin
+ +
+
padding
+
padding
+
+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/basic-css/Add Different Padding to Each Side of an Element.md b/curriculum/challenges/01-responsive-web-design/basic-css/Add Different Padding to Each Side of an Element.md new file mode 100644 index 0000000000..f40eac2fb6 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/basic-css/Add Different Padding to Each Side of an Element.md @@ -0,0 +1,95 @@ +--- +id: bad87fee1348bd9aedf08824 +title: Add Different Padding to Each Side of an Element +challengeType: 0 +guideUrl: 'https://guide.freecodecamp.org/certificates/add-different-padding-to-each-side-of-an-element' +videoUrl: 'https://scrimba.com/c/cB7mwUw' +--- + +## Description +
+Sometimes you will want to customize an element so that it has different amounts of padding on each of its sides. +CSS allows you to control the padding of all four individual sides of an element with the padding-top, padding-right, padding-bottom, and padding-left properties. +
+ +## Instructions +
+Give the blue box a padding of 40px on its top and left side, but only 20px on its bottom and right side. +
+ +## Tests +
+ +```yml +- text: Your blue-box class should give the top of the elements 40px of padding. + testString: 'assert($(".blue-box").css("padding-top") === "40px", "Your blue-box class should give the top of the elements 40px of padding.");' +- text: Your blue-box class should give the right of the elements 20px of padding. + testString: 'assert($(".blue-box").css("padding-right") === "20px", "Your blue-box class should give the right of the elements 20px of padding.");' +- text: Your blue-box class should give the bottom of the elements 20px of padding. + testString: 'assert($(".blue-box").css("padding-bottom") === "20px", "Your blue-box class should give the bottom of the elements 20px of padding.");' +- text: Your blue-box class should give the left of the elements 40px of padding. + testString: 'assert($(".blue-box").css("padding-left") === "40px", "Your blue-box class should give the left of the elements 40px of padding.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + +
margin
+ +
+
padding
+
padding
+
+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/basic-css/Add Rounded Corners with border-radius.md b/curriculum/challenges/01-responsive-web-design/basic-css/Add Rounded Corners with border-radius.md new file mode 100644 index 0000000000..1d65e9f2ca --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/basic-css/Add Rounded Corners with border-radius.md @@ -0,0 +1,110 @@ +--- +id: bad87fee1348bd9aedf08814 +title: Add Rounded Corners with border-radius +challengeType: 0 +guideUrl: 'https://guide.freecodecamp.org/certificates/add-rounded-corners-a-border-radius' +videoUrl: 'https://scrimba.com/c/cbZm2hg' +--- + +## Description +
+Your cat photo currently has sharp corners. We can round out those corners with a CSS property called border-radius. +
+ +## Instructions +
+You can specify a border-radius with pixels. Give your cat photo a border-radius of 10px. +Note: this challenge allows for multiple possible solutions. For example, you may add border-radius to either the .thick-green-border class or the .smaller-image class. +
+ +## Tests +
+ +```yml +- text: Your image element should have the class "thick-green-border". + testString: 'assert($("img").hasClass("thick-green-border"), "Your image element should have the class "thick-green-border".");' +- text: Your image should have a border radius of 10px + testString: 'assert(parseInt($("img").css("border-top-left-radius")) > 8, "Your image should have a border radius of 10px");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + + + +

CatPhotoApp

+
+

Click here to view more cat photos.

+ + A cute orange cat lying on its back. + +
+

Things cats love:

+
    +
  • cat nip
  • +
  • laser pointers
  • +
  • lasagna
  • +
+

Top 3 things cats hate:

+
    +
  1. flea treatment
  2. +
  3. thunder
  4. +
  5. other cats
  6. +
+
+ +
+ +
+ + +
+ + +
+
+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/basic-css/Add a Negative Margin to an Element.md b/curriculum/challenges/01-responsive-web-design/basic-css/Add a Negative Margin to an Element.md new file mode 100644 index 0000000000..953f2fa1fa --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/basic-css/Add a Negative Margin to an Element.md @@ -0,0 +1,89 @@ +--- +id: bad87fee1348bd9aedf08823 +title: Add a Negative Margin to an Element +challengeType: 0 +guideUrl: 'https://guide.freecodecamp.org/certificates/add-a-negative-margin-to-an-element' +videoUrl: 'https://scrimba.com/c/cnpyGs3' +--- + +## Description +
+An element's margin controls the amount of space between an element's border and surrounding elements. +If you set an element's margin to a negative value, the element will grow larger. +
+ +## Instructions +
+Try to set the margin to a negative value like the one for the red box. +Change the margin of the blue box to -15px, so it fills the entire horizontal width of the yellow box around it. +
+ +## Tests +
+ +```yml +- text: Your blue-box class should give elements -15px of margin. + testString: 'assert($(".blue-box").css("margin-top") === "-15px", "Your blue-box class should give elements -15px of margin.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + + +
+
padding
+
padding
+
+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/basic-css/Adjust the Margin of an Element.md b/curriculum/challenges/01-responsive-web-design/basic-css/Adjust the Margin of an Element.md new file mode 100644 index 0000000000..f2f792151e --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/basic-css/Adjust the Margin of an Element.md @@ -0,0 +1,90 @@ +--- +id: bad87fee1348bd9aedf08822 +title: Adjust the Margin of an Element +challengeType: 0 +guideUrl: 'https://guide.freecodecamp.org/certificates/adjust-the-margin-of-an-element' +videoUrl: 'https://scrimba.com/c/cVJarHW' +--- + +## Description +
+An element's margin controls the amount of space between an element's border and surrounding elements. +Here, we can see that the blue box and the red box are nested within the yellow box. Note that the red box has a bigger margin than the blue box, making it appear smaller. +When you increase the blue box's margin, it will increase the distance between its border and surrounding elements. +
+ +## Instructions +
+Change the margin of the blue box to match that of the red box. +
+ +## Tests +
+ +```yml +- text: Your blue-box class should give elements 20px of margin. + testString: 'assert($(".blue-box").css("margin-top") === "20px", "Your blue-box class should give elements 20px of margin.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + +
margin
+ +
+
padding
+
padding
+
+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/basic-css/Adjust the Padding of an Element.md b/curriculum/challenges/01-responsive-web-design/basic-css/Adjust the Padding of an Element.md new file mode 100644 index 0000000000..95504c8263 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/basic-css/Adjust the Padding of an Element.md @@ -0,0 +1,91 @@ +--- +id: bad88fee1348bd9aedf08825 +title: Adjust the Padding of an Element +challengeType: 0 +guideUrl: 'https://guide.freecodecamp.org/certificates/adjust-the-padding-of-an-element' +videoUrl: 'https://scrimba.com/c/cED8ZC2' +--- + +## Description +
+Now let's put our Cat Photo App away for a little while and learn more about styling HTML. +You may have already noticed this, but all HTML elements are essentially little rectangles. +Three important properties control the space that surrounds each HTML element: padding, margin, and border. +An element's padding controls the amount of space between the element's content and its border. +Here, we can see that the blue box and the red box are nested within the yellow box. Note that the red box has more padding than the blue box. +When you increase the blue box's padding, it will increase the distance(padding) between the text and the border around it. +
+ +## Instructions +
+Change the padding of your blue box to match that of your red box. +
+ +## Tests +
+ +```yml +- text: Your blue-box class should give elements 20px of padding. + testString: 'assert($(".blue-box").css("padding-top") === "20px", "Your blue-box class should give elements 20px of padding.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + +
margin
+ +
+
padding
+
padding
+
+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/basic-css/Attach a Fallback value to a CSS Variable.md b/curriculum/challenges/01-responsive-web-design/basic-css/Attach a Fallback value to a CSS Variable.md new file mode 100644 index 0000000000..6b3b51de19 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/basic-css/Attach a Fallback value to a CSS Variable.md @@ -0,0 +1,262 @@ +--- +id: 5a9d7286424fe3d0e10cad13 +title: Attach a Fallback value to a CSS Variable +challengeType: 0 +videoUrl: 'https://scrimba.com/c/c6bDNfp' +--- + +## Description +
+When using your variable as a CSS property value, you can attach a fallback value that your browser will revert to if the given variable is invalid. +Note: This fallback is not used to increase browser compatibilty, and it will not work on IE browsers. Rather, it is used so that the browser has a color to display if it cannot find your variable. +Here's how you do it: +
background: var(--penguin-skin, black);
+This will set background to black if your variable wasn't set. +Note that this can be useful for debugging. +
+ +## Instructions +
+It looks there is a problem with the variables supplied to the .penguin-top and .penguin-bottom classes. Rather than fix the typo, add a fallback value of black to the background property of the .penguin-top and .penguin-bottom classes. +
+ +## Tests +
+ +```yml +- text: Apply the fallback value of black to the background property of the penguin-top class. + testString: 'assert(code.match(/.penguin-top\s*?{[\s\S]*background\s*?:\s*?var\(\s*?--pengiun-skin\s*?,\s*?black\s*?\)\s*?;[\s\S]*}[\s\S]*.penguin-bottom\s{/gi), "Apply the fallback value of black to the background property of the penguin-top class.");' +- text: Apply the fallback value of black to the background property of the penguin-bottom class. + testString: 'assert(code.match(/.penguin-bottom\s*?{[\s\S]*background\s*?:\s*?var\(\s*?--pengiun-skin\s*?,\s*?black\s*?\)\s*?;[\s\S]*}/gi), "Apply the fallback value of black to the background property of the penguin-bottom class.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+``` + +
+ + + +
+ +## Solution +
+ + +```js +var code = ".penguin-top {background: var(--pengiun-skin, black);} .penguin-bottom {background: var(--pengiun-skin, black);}" +``` + +
diff --git a/curriculum/challenges/01-responsive-web-design/basic-css/Cascading CSS variables.md b/curriculum/challenges/01-responsive-web-design/basic-css/Cascading CSS variables.md new file mode 100644 index 0000000000..c1d575b24c --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/basic-css/Cascading CSS variables.md @@ -0,0 +1,255 @@ +--- +id: 5a9d7295424fe3d0e10cad14 +title: Cascading CSS variables +challengeType: 0 +videoUrl: 'https://scrimba.com/c/cyLZZhZ' +--- + +## Description +
+When you create a variable, it becomes available for you to use inside the element in which you create it. It also becomes available within any elements nested within it. This effect is known as cascading. +Because of cascading, CSS variables are often defined in the :root element. +:root is a pseudo-class selector that matches the root element of the document, usually the element. By creating your variables in :root, they will be available globally and can be accessed from any other selector later in the style sheet. +
+ +## Instructions +
+Define a variable named --penguin-belly in the :root selector and give it the value of pink. You can then see how the value will cascade down to change the value to pink, anywhere that variable is used. +
+ +## Tests +
+ +```yml +- text: 'declare the --penguin-belly variable in the :root and assign it to pink.' + testString: 'assert(code.match(/:root\s*?{[\s\S]*--penguin-belly\s*?:\s*?pink\s*?;[\s\S]*}/gi), "declare the --penguin-belly variable in the :root and assign it to pink.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+``` + +
+ + + +
+ +## Solution +
+ + +```js +var code = ":root {--penguin-belly: pink;}" +``` + +
diff --git a/curriculum/challenges/01-responsive-web-design/basic-css/Change a variable for a specific area.md b/curriculum/challenges/01-responsive-web-design/basic-css/Change a variable for a specific area.md new file mode 100644 index 0000000000..b91f201092 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/basic-css/Change a variable for a specific area.md @@ -0,0 +1,256 @@ +--- +id: 5a9d72a1424fe3d0e10cad15 +title: Change a variable for a specific area +challengeType: 0 +videoUrl: 'https://scrimba.com/c/cdRwbuW' +--- + +## Description +
+When you create your variables in :root they will set the value of that variable for the whole page. +You can then over-write these variables by setting them again within a specific element. +
+ +## Instructions +
+Change the value of --penguin-belly to white in the penguin class. +
+ +## Tests +
+ +```yml +- text: The penguin class should reassign the --penguin-belly variable to white. + testString: 'assert(code.match(/.penguin\s*?{[\s\S]*--penguin-belly\s*?:\s*?white\s*?;[\s\S]*}/gi), "The penguin class should reassign the --penguin-belly variable to white.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+``` + +
+ + + +
+ +## Solution +
+ + +```js +var code = ".penguin {--penguin-belly: white;}" +``` + +
diff --git a/curriculum/challenges/01-responsive-web-design/basic-css/Change the Color of Text.md b/curriculum/challenges/01-responsive-web-design/basic-css/Change the Color of Text.md new file mode 100644 index 0000000000..6981dca3d3 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/basic-css/Change the Color of Text.md @@ -0,0 +1,87 @@ +--- +id: bad87fee1348bd9aedf08803 +title: Change the Color of Text +challengeType: 0 +videoUrl: 'https://scrimba.com/c/cRkVmSm' +--- + +## Description +
+Now let's change the color of some of our text. +We can do this by changing the style of your h2 element. +The property that is responsible for the color of an element's text is the color style property. +Here's how you would set your h2 element's text color to blue: +<h2 style="color: blue;">CatPhotoApp</h2> +Note that it is a good practice to end inline style declarations with a ; . +
+ +## Instructions +
+Change your h2 element's style so that its text color is red. +
+ +## Tests +
+ +```yml +- text: Your h2 element should be red. + testString: 'assert($("h2").css("color") === "rgb(255, 0, 0)", "Your h2 element should be red.");' +- text: Your style declaration should end with a ; . + testString: 'assert(code.match(/\s*CatPhotoApp\s*<\/h2>/)," Your style declaration should end with a ; .");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html +

CatPhotoApp

+
+

Click here to view more cat photos.

+ + A cute orange cat lying on its back. + +
+

Things cats love:

+
    +
  • cat nip
  • +
  • laser pointers
  • +
  • lasagna
  • +
+

Top 3 things cats hate:

+
    +
  1. flea treatment
  2. +
  3. thunder
  4. +
  5. other cats
  6. +
+
+ +
+ +
+ + +
+ + +
+
+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/basic-css/Change the Font Size of an Element.md b/curriculum/challenges/01-responsive-web-design/basic-css/Change the Font Size of an Element.md new file mode 100644 index 0000000000..f86a02bc8f --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/basic-css/Change the Font Size of an Element.md @@ -0,0 +1,87 @@ +--- +id: bad87fee1348bd9aedf08806 +title: Change the Font Size of an Element +challengeType: 0 +videoUrl: 'https://scrimba.com/c/c3bvDc8' +--- + +## Description +
+Font size is controlled by the font-size CSS property, like this: +
h1 {
  font-size: 30px;
}
+
+ +## Instructions +
+Inside the same <style> tag that contains your red-text class, create an entry for p elements and set the font-size to 16 pixels (16px). +
+ +## Tests +
+ +```yml +- text: 'Between the style tags, give the p elements font-size of 16px. Browser and Text zoom should be at 100%.' + testString: 'assert(code.match(/p\s*{\s*font-size\s*:\s*16\s*px\s*;\s*}/i), "Between the style tags, give the p elements font-size of 16px. Browser and Text zoom should be at 100%.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + + +

CatPhotoApp

+
+

Click here to view more cat photos.

+ + A cute orange cat lying on its back. + +
+

Things cats love:

+
    +
  • cat nip
  • +
  • laser pointers
  • +
  • lasagna
  • +
+

Top 3 things cats hate:

+
    +
  1. flea treatment
  2. +
  3. thunder
  4. +
  5. other cats
  6. +
+
+ +
+ +
+ + +
+ + +
+
+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/basic-css/Create a custom CSS Variable.md b/curriculum/challenges/01-responsive-web-design/basic-css/Create a custom CSS Variable.md new file mode 100644 index 0000000000..7770a00253 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/basic-css/Create a custom CSS Variable.md @@ -0,0 +1,251 @@ +--- +id: 5a9d726c424fe3d0e10cad11 +title: Create a custom CSS Variable +challengeType: 0 +videoUrl: 'https://scrimba.com/c/cQd27Hr' +--- + +## Description +
+To create a CSS Variable, you just need to give it a name with two dashes in front of it and assign it a value like this: +
--penguin-skin: gray;
+This will create a variable named --penguin-skin and assign it the value of gray. +Now you can use that variable elsewhere in your CSS to change the value of other elements to gray. +
+ +## Instructions +
+In the penguin class, create a variable name --penguin-skin and give it a value of gray +
+ +## Tests +
+ +```yml +- text: penguin class should declare the --penguin-skin variable and assign it to gray. + testString: 'assert(code.match(/.penguin\s*?{[\s\S]*--penguin-skin\s*?:\s*?gray\s*?;[\s\S]*}/gi), "penguin class should declare the --penguin-skin variable and assign it to gray.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+``` + +
+ + + +
+ +## Solution +
+ + +```js +var code = ".penguin {--penguin-skin: gray;}" +``` + +
diff --git a/curriculum/challenges/01-responsive-web-design/basic-css/Give a Background Color to a div Element.md b/curriculum/challenges/01-responsive-web-design/basic-css/Give a Background Color to a div Element.md new file mode 100644 index 0000000000..f98272ac03 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/basic-css/Give a Background Color to a div Element.md @@ -0,0 +1,113 @@ +--- +id: bad87fed1348bd9aede07836 +title: Give a Background Color to a div Element +challengeType: 0 +videoUrl: 'https://scrimba.com/c/cdRKMCk' +--- + +## Description +
+You can set an element's background color with the background-color property. +For example, if you wanted an element's background color to be green, you'd put this within your style element: +
.green-background {
  background-color: green;
}
+
+ +## Instructions +
+Create a class called silver-background with the background-color of silver. Assign this class to your div element. +
+ +## Tests +
+ +```yml +- text: Give your div element the class silver-background. + testString: 'assert($("div").hasClass("silver-background"), "Give your div element the class silver-background.");' +- text: Your div element should have a silver background. + testString: 'assert($("div").css("background-color") === "rgb(192, 192, 192)", "Your div element should have a silver background.");' +- text: Define a class named silver-background within the style element and assign the value of silver to the background-color property. + testString: 'assert(code.match(/\.silver-background\s*{\s*background-color:\s*silver;\s*}/), "Define a class named silver-background within the style element and assign the value of silver to the background-color property.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + + + +

CatPhotoApp

+
+

Click here to view more cat photos.

+ + A cute orange cat lying on its back. + +
+

Things cats love:

+
    +
  • cat nip
  • +
  • laser pointers
  • +
  • lasagna
  • +
+

Top 3 things cats hate:

+
    +
  1. flea treatment
  2. +
  3. thunder
  4. +
  5. other cats
  6. +
+
+ +
+ +
+ + +
+ + +
+
+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/basic-css/Import a Google Font.md b/curriculum/challenges/01-responsive-web-design/basic-css/Import a Google Font.md new file mode 100644 index 0000000000..cdc8dc49e4 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/basic-css/Import a Google Font.md @@ -0,0 +1,104 @@ +--- +id: bad87fee1348bd9aedf08807 +title: Import a Google Font +challengeType: 0 +videoUrl: 'https://scrimba.com/c/cM9MRsJ' +--- + +## Description +
+In addition to specifying common fonts that are found on most operating systems, we can also specify non-standard, custom web fonts for use on our website. There are various sources for web fonts on the internet but, for this example we will focus on the Google Fonts library. +Google Fonts is a free library of web fonts that you can use in your CSS by referencing the font's URL. +So, let's go ahead and import and apply a Google font (note that if Google is blocked in your country, you will need to skip this challenge). +To import a Google Font, you can copy the font(s) URL from the Google Fonts library and then paste it in your HTML. For this challenge, we'll import the Lobster font. To do this, copy the following code snippet and paste it into the top of your code editor(before the opening style element): +<link href="https://fonts.googleapis.com/css?family=Lobster" rel="stylesheet" type="text/css"> +Now you can use the Lobster font in your CSS by using Lobster as the FAMILY_NAME as in the following example:
font-family: FAMILY_NAME, GENERIC_NAME;. +The GENERIC_NAME is optional, and is a fallback font in case the other specified font is not available. This is covered in the next challenge. +Family names are case-sensitive and need to be wrapped in quotes if there is a space in the name. For example, you need quotes to use the "Open Sans" font, but not to use the Lobster font. +
+ +## Instructions +
+Create a font-family CSS rule that uses the Lobster font, and ensure that it will be applied to your h2 element. +
+ +## Tests +
+ +```yml +- text: Import the Lobster font. + testString: 'assert(new RegExp("googleapis", "gi").test(code), "Import the Lobster font.");' +- text: Your h2 element should use the font Lobster. + testString: 'assert($("h2").css("font-family").match(/lobster/i), "Your h2 element should use the font Lobster.");' +- text: Use an h2 CSS selector to change the font. + testString: 'assert(/\s*h2\s*\{\s*font-family\:\s*(\"|")?Lobster(\"|")?\s*;\s*\}/gi.test(code), "Use an h2 CSS selector to change the font.");' +- text: Your p element should still use the font monospace. + testString: 'assert($("p").css("font-family").match(/monospace/i), "Your p element should still use the font monospace.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + + +

CatPhotoApp

+
+

Click here to view more cat photos.

+ + A cute orange cat lying on its back. + +
+

Things cats love:

+
    +
  • cat nip
  • +
  • laser pointers
  • +
  • lasagna
  • +
+

Top 3 things cats hate:

+
    +
  1. flea treatment
  2. +
  3. thunder
  4. +
  5. other cats
  6. +
+
+ +
+ +
+ + +
+ + +
+
+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/basic-css/Improve Compatibility with Browser Fallbacks.md b/curriculum/challenges/01-responsive-web-design/basic-css/Improve Compatibility with Browser Fallbacks.md new file mode 100644 index 0000000000..8c29cd1b7b --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/basic-css/Improve Compatibility with Browser Fallbacks.md @@ -0,0 +1,65 @@ +--- +id: 5b7d72c338cd7e35b63f3e14 +title: Improve Compatibility with Browser Fallbacks +challengeType: 0 +videoUrl: " +--- + +## Description +
+When working with CSS you will likely run into browser compatibility issues at some point. This is why it's important to provide browser fallbacks to avoid potential problems. +When your browser parses the CSS of a webpage, it ignores any properties that it doesn't recognize or support. For example, if you use a CSS variable to assign a background color on a site, Internet Explorer will ignore the background color because it does not support CSS variables. In that case, the browser will use whatever value it has for that property. If it can't find any other value set for that property, it will revert to the default value, which is typically not ideal. +This means that if you do want to provide a browser fallback, it's as easy as providing another more widely supported value immediately before your declaration. That way an older browser will have something to fall back on, while a newer browser will just interpret whatever declaration comes later in the cascade. +
+ +## Instructions +
+It looks like a variable is being used to set the background color of the .red-box class. Let's improve our browser compatibility by adding another background declaration right before the existing declaration and set its value to red. +
+ +## Tests +
+ +```yml +- text: Your .red-box rule should include a fallback with the background set to red immediately before the existing background declaration. + testString: 'assert(code.match(/.red-box\s*{[^}]*background:\s*(red|#ff0000|#f00|rgb\(\s*255\s*,\s*0\s*,\s*0\s*\)|rgb\(\s*100%\s*,\s*0%\s*,\s*0%\s*\)|hsl\(\s*0\s*,\s*100%\s*,\s*50%\s*\))\s*;\s*background:\s*var\(\s*--red-color\s*\);/gi), "Your .red-box rule should include a fallback with the background set to red immediately before the existing background declaration.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + +
+``` + +
+ + + +
+ +## Solution +
+ + +```js +var code=".red-box {background: red; background: var(--red-color);}" +``` + +
diff --git a/curriculum/challenges/01-responsive-web-design/basic-css/Inherit Styles from the Body Element.md b/curriculum/challenges/01-responsive-web-design/basic-css/Inherit Styles from the Body Element.md new file mode 100644 index 0000000000..07e487d3e3 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/basic-css/Inherit Styles from the Body Element.md @@ -0,0 +1,70 @@ +--- +id: bad87fee1348bd9aedf08746 +title: Inherit Styles from the Body Element +challengeType: 0 +videoUrl: 'https://scrimba.com/c/c9bmdtR' +--- + +## Description +
+Now we've proven that every HTML page has a body element, and that its body element can also be styled with CSS. +Remember, you can style your body element just like any other HTML element, and all your other elements will inherit your body element's styles. +
+ +## Instructions +
+First, create a h1 element with the text Hello World +Then, let's give all elements on your page the color of green by adding color: green; to your body element's style declaration. +Finally, give your body element the font-family of monospace by adding font-family: monospace; to your body element's style declaration. +
+ +## Tests +
+ +```yml +- text: Create an h1 element. + testString: 'assert(($("h1").length > 0), "Create an h1 element.");' +- text: Your h1 element should have the text Hello World. + testString: 'assert(($("h1").length > 0 && $("h1").text().match(/hello world/i)), "Your h1 element should have the text Hello World.");' +- text: Make sure your h1 element has a closing tag. + testString: 'assert(code.match(/<\/h1>/g) && code.match(/

/g).length === code.match(/

h1 element has a closing tag.");' +- text: Give your body element the color property of green. + testString: 'assert(($("body").css("color") === "rgb(0, 128, 0)"), "Give your body element the color property of green.");' +- text: Give your body element the font-family property of monospace. + testString: 'assert(($("body").css("font-family").match(/monospace/i)), "Give your body element the font-family property of monospace.");' +- text: Your h1 element should inherit the font monospace from your body element. + testString: 'assert(($("h1").length > 0 && $("h1").css("font-family").match(/monospace/i)), "Your h1 element should inherit the font monospace from your body element.");' +- text: Your h1 element should inherit the color green from your body element. + testString: 'assert(($("h1").length > 0 && $("h1").css("color") === "rgb(0, 128, 0)"), "Your h1 element should inherit the color green from your body element.");' + +``` + +

+ +## Challenge Seed +
+ +
+ +```html + +``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/basic-css/Make Circular Images with a border-radius.md b/curriculum/challenges/01-responsive-web-design/basic-css/Make Circular Images with a border-radius.md new file mode 100644 index 0000000000..b588b9c1f3 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/basic-css/Make Circular Images with a border-radius.md @@ -0,0 +1,109 @@ +--- +id: bad87fee1348bd9aedf08815 +title: Make Circular Images with a border-radius +challengeType: 0 +videoUrl: 'https://scrimba.com/c/c2MvrcB' +--- + +## Description +
+In addition to pixels, you can also specify the border-radius using a percentage. +
+ +## Instructions +
+Give your cat photo a border-radius of 50%. +
+ +## Tests +
+ +```yml +- text: 'Your image should have a border radius of 50%, making it perfectly circular.' + testString: 'assert(parseInt($("img").css("border-top-left-radius")) > 48, "Your image should have a border radius of 50%, making it perfectly circular.");' +- text: Be sure to use a percentage value of 50%. + testString: 'assert(code.match(/50%/g), "Be sure to use a percentage value of 50%.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + + + +

CatPhotoApp

+
+

Click here to view more cat photos.

+ + A cute orange cat lying on its back. + +
+

Things cats love:

+
    +
  • cat nip
  • +
  • laser pointers
  • +
  • lasagna
  • +
+

Top 3 things cats hate:

+
    +
  1. flea treatment
  2. +
  3. thunder
  4. +
  5. other cats
  6. +
+
+ +
+ +
+ + +
+ + +
+
+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/basic-css/Override All Other Styles by using Important.md b/curriculum/challenges/01-responsive-web-design/basic-css/Override All Other Styles by using Important.md new file mode 100644 index 0000000000..f5c194e06e --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/basic-css/Override All Other Styles by using Important.md @@ -0,0 +1,81 @@ +--- +id: bad87fee1348bd9aedf07756 +title: Override All Other Styles by using Important +challengeType: 0 +videoUrl: 'https://scrimba.com/c/cm24rcp' +--- + +## Description +
+Yay! We just proved that inline styles will override all the CSS declarations in your style element. +But wait. There's one last way to override CSS. This is the most powerful method of all. But before we do it, let's talk about why you would ever want to override CSS. +In many situations, you will use CSS libraries. These may accidentally override your own CSS. So when you absolutely need to be sure that an element has specific CSS, you can use !important +Let's go all the way back to our pink-text class declaration. Remember that our pink-text class was overridden by subsequent class declarations, id declarations, and inline styles. +
+ +## Instructions +
+Let's add the keyword !important to your pink-text element's color declaration to make 100% sure that your h1 element will be pink. +An example of how to do this is: +color: red !important; +
+ +## Tests +
+ +```yml +- text: Your h1 element should have the class pink-text. + testString: 'assert($("h1").hasClass("pink-text"), "Your h1 element should have the class pink-text.");' +- text: Your h1 element should have the class blue-text. + testString: 'assert($("h1").hasClass("blue-text"), "Your h1 element should have the class blue-text.");' +- text: Your h1 element should have the id of orange-text. + testString: 'assert($("h1").attr("id") === "orange-text", "Your h1 element should have the id of orange-text.");' +- text: 'Your h1 element should have the inline style of color: white.' + testString: 'assert(code.match(/h1 element should have the inline style of color: white.");' +- text: Your pink-text class declaration should have the !important keyword to override all other declarations. + testString: 'assert(code.match(/\.pink-text\s*?\{[\s\S]*?color:.*pink.*!important\s*;?[^\.]*\}/g), "Your pink-text class declaration should have the !important keyword to override all other declarations.");' +- text: Your h1 element should be pink. + testString: 'assert($("h1").css("color") === "rgb(255, 192, 203)", "Your h1 element should be pink.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + +

Hello World!

+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/basic-css/Override Class Declarations by Styling ID Attributes.md b/curriculum/challenges/01-responsive-web-design/basic-css/Override Class Declarations by Styling ID Attributes.md new file mode 100644 index 0000000000..1f33182afa --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/basic-css/Override Class Declarations by Styling ID Attributes.md @@ -0,0 +1,82 @@ +--- +id: bad87fee1348bd8aedf06756 +title: Override Class Declarations by Styling ID Attributes +challengeType: 0 +videoUrl: 'https://scrimba.com/c/cRkpDhB' +--- + +## Description +
+We just proved that browsers read CSS from top to bottom. That means that, in the event of a conflict, the browser will use whichever CSS declaration came last. +But we're not done yet. There are other ways that you can override CSS. Do you remember id attributes? +Let's override your pink-text and blue-text classes, and make your h1 element orange, by giving the h1 element an id and then styling that id. +
+ +## Instructions +
+Give your h1 element the id attribute of orange-text. Remember, id styles look like this: +<h1 id="orange-text"> +Leave the blue-text and pink-text classes on your h1 element. +Create a CSS declaration for your orange-text id in your style element. Here's an example of what this looks like: +
#brown-text {
  color: brown;
}
+Note: It doesn't matter whether you declare this CSS above or below pink-text class, since id attribute will always take precedence. +
+ +## Tests +
+ +```yml +- text: Your h1 element should have the class pink-text. + testString: 'assert($("h1").hasClass("pink-text"), "Your h1 element should have the class pink-text.");' +- text: Your h1 element should have the class blue-text. + testString: 'assert($("h1").hasClass("blue-text"), "Your h1 element should have the class blue-text.");' +- text: Give your h1 element the id of orange-text. + testString: 'assert($("h1").attr("id") === "orange-text", "Give your h1 element the id of orange-text.");' +- text: There should be only one h1 element. + testString: 'assert(($("h1").length === 1), "There should be only one h1 element.");' +- text: Create a CSS declaration for your orange-text id + testString: 'assert(code.match(/#orange-text\s*{/gi), "Create a CSS declaration for your orange-text id");' +- text: Do not give your h1 any style attributes. + testString: 'assert(!code.match(//gi), "Do not give your h1 any style attributes.");' +- text: Your h1 element should be orange. + testString: 'assert($("h1").css("color") === "rgb(255, 165, 0)", "Your h1 element should be orange.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + +

Hello World!

+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/basic-css/Override Class Declarations with Inline Styles.md b/curriculum/challenges/01-responsive-web-design/basic-css/Override Class Declarations with Inline Styles.md new file mode 100644 index 0000000000..f26b17a617 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/basic-css/Override Class Declarations with Inline Styles.md @@ -0,0 +1,77 @@ +--- +id: bad87fee1348bd9aedf06756 +title: Override Class Declarations with Inline Styles +challengeType: 0 +videoUrl: 'https://scrimba.com/c/cGJDRha' +--- + +## Description +
+So we've proven that id declarations override class declarations, regardless of where they are declared in your style element CSS. +There are other ways that you can override CSS. Do you remember inline styles? +
+ +## Instructions +
+Use an inline style to try to make our h1 element white. Remember, in line styles look like this: +<h1 style="color: green;"> +Leave the blue-text and pink-text classes on your h1 element. +
+ +## Tests +
+ +```yml +- text: Your h1 element should have the class pink-text. + testString: 'assert($("h1").hasClass("pink-text"), "Your h1 element should have the class pink-text.");' +- text: Your h1 element should have the class blue-text. + testString: 'assert($("h1").hasClass("blue-text"), "Your h1 element should have the class blue-text.");' +- text: Your h1 element should have the id of orange-text. + testString: 'assert($("h1").attr("id") === "orange-text", "Your h1 element should have the id of orange-text.");' +- text: Give your h1 element an inline style. + testString: 'assert(document.querySelector("h1[style]"), "Give your h1 element an inline style.");' +- text: Your h1 element should be white. + testString: 'assert($("h1").css("color") === "rgb(255, 255, 255)", "Your h1 element should be white.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + +

Hello World!

+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/basic-css/Override Styles in Subsequent CSS.md b/curriculum/challenges/01-responsive-web-design/basic-css/Override Styles in Subsequent CSS.md new file mode 100644 index 0000000000..fc7b82157e --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/basic-css/Override Styles in Subsequent CSS.md @@ -0,0 +1,72 @@ +--- +id: bad87fee1348bd9aedf04756 +title: Override Styles in Subsequent CSS +challengeType: 0 +videoUrl: 'https://scrimba.com/c/cGJDQug' +--- + +## Description +
+Our "pink-text" class overrode our body element's CSS declaration! +We just proved that our classes will override the body element's CSS. So the next logical question is, what can we do to override our pink-text class? +
+ +## Instructions +
+Create an additional CSS class called blue-text that gives an element the color blue. Make sure it's below your pink-text class declaration. +Apply the blue-text class to your h1 element in addition to your pink-text class, and let's see which one wins. +Applying multiple class attributes to a HTML element is done with a space between them like this: +class="class1 class2" +Note: It doesn't matter which order the classes are listed in the HTML element. +However, the order of the class declarations in the <style> section are what is important. The second declaration will always take precedence over the first. Because .blue-text is declared second, it overrides the attributes of .pink-text +
+ +## Tests +
+ +```yml +- text: Your h1 element should have the class pink-text. + testString: 'assert($("h1").hasClass("pink-text"), "Your h1 element should have the class pink-text.");' +- text: Your h1 element should have the class blue-text. + testString: 'assert($("h1").hasClass("blue-text"), "Your h1 element should have the class blue-text.");' +- text: Both blue-text and pink-text should belong to the same h1 element. + testString: 'assert($(".pink-text").hasClass("blue-text"), "Both blue-text and pink-text should belong to the same h1 element.");' +- text: Your h1 element should be blue. + testString: 'assert($("h1").css("color") === "rgb(0, 0, 255)", "Your h1 element should be blue.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + +

Hello World!

+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/basic-css/Prioritize One Style Over Another.md b/curriculum/challenges/01-responsive-web-design/basic-css/Prioritize One Style Over Another.md new file mode 100644 index 0000000000..0238cdd7dd --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/basic-css/Prioritize One Style Over Another.md @@ -0,0 +1,64 @@ +--- +id: bad87fee1348bd9aedf08756 +title: Prioritize One Style Over Another +challengeType: 0 +videoUrl: 'https://scrimba.com/c/cZ8wnHv' +--- + +## Description +
+Sometimes your HTML elements will receive multiple styles that conflict with one another. +For example, your h1 element can't be both green and pink at the same time. +Let's see what happens when we create a class that makes text pink, then apply it to an element. Will our class override the body element's color: green; CSS property? +
+ +## Instructions +
+Create a CSS class called pink-text that gives an element the color pink. +Give your h1 element the class of pink-text. +
+ +## Tests +
+ +```yml +- text: Your h1 element should have the class pink-text. + testString: 'assert($("h1").hasClass("pink-text"), "Your h1 element should have the class pink-text.");' +- text: 'Your <style> should have a pink-text CSS class that changes the color.' + testString: 'assert(code.match(/\.pink-text\s*\{\s*color\s*:\s*.+\s*;\s*\}/g), "Your <style> should have a pink-text CSS class that changes the color.");' +- text: Your h1 element should be pink. + testString: 'assert($("h1").css("color") === "rgb(255, 192, 203)", "Your h1 element should be pink.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + +

Hello World!

+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/basic-css/Set the Font Family of an Element.md b/curriculum/challenges/01-responsive-web-design/basic-css/Set the Font Family of an Element.md new file mode 100644 index 0000000000..17977c516f --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/basic-css/Set the Font Family of an Element.md @@ -0,0 +1,92 @@ +--- +id: bad87fee1348bd9aede08807 +title: Set the Font Family of an Element +challengeType: 0 +videoUrl: 'https://scrimba.com/c/c3bvpCg' +--- + +## Description +
+You can set which font an element should use, by using the font-family property. +For example, if you wanted to set your h2 element's font to sans-serif, you would use the following CSS: +
h2 {
  font-family: sans-serif;
}
+
+ +## Instructions +
+Make all of your p elements use the monospace font. +
+ +## Tests +
+ +```yml +- text: Your p elements should use the font monospace. + testString: 'assert($("p").not(".red-text").css("font-family").match(/monospace/i), "Your p elements should use the font monospace.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + + +

CatPhotoApp

+
+

Click here to view more cat photos.

+ + A cute orange cat lying on its back. + +
+

Things cats love:

+
    +
  • cat nip
  • +
  • laser pointers
  • +
  • lasagna
  • +
+

Top 3 things cats hate:

+
    +
  1. flea treatment
  2. +
  3. thunder
  4. +
  5. other cats
  6. +
+
+ +
+ +
+ + +
+ + +
+
+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/basic-css/Set the id of an Element.md b/curriculum/challenges/01-responsive-web-design/basic-css/Set the id of an Element.md new file mode 100644 index 0000000000..a1d59ff15c --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/basic-css/Set the id of an Element.md @@ -0,0 +1,115 @@ +--- +id: bad87eee1348bd9aede07836 +title: Set the id of an Element +challengeType: 0 +videoUrl: 'https://scrimba.com/c/cN6MEc2' +--- + +## Description +
+In addition to classes, each HTML element can also have an id attribute. +There are several benefits to using id attributes: You can use an id to style a single element and later you'll learn that you can use them to select and modify specific elements with JavaScript. +id attributes should be unique. Browsers won't enforce this, but it is a widely agreed upon best practice. So please don't give more than one element the same id attribute. +Here's an example of how you give your h2 element the id of cat-photo-app: +<h2 id="cat-photo-app"> +
+ +## Instructions +
+Give your form element the id cat-photo-form. +
+ +## Tests +
+ +```yml +- text: Give your form element the id of cat-photo-form. + testString: 'assert($("form").attr("id") === "cat-photo-form", "Give your form element the id of cat-photo-form.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + + + +

CatPhotoApp

+
+

Click here to view more cat photos.

+ + A cute orange cat lying on its back. + +
+

Things cats love:

+
    +
  • cat nip
  • +
  • laser pointers
  • +
  • lasagna
  • +
+

Top 3 things cats hate:

+
    +
  1. flea treatment
  2. +
  3. thunder
  4. +
  5. other cats
  6. +
+
+ +
+ +
+ + +
+ + +
+
+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/basic-css/Size Your Images.md b/curriculum/challenges/01-responsive-web-design/basic-css/Size Your Images.md new file mode 100644 index 0000000000..b2e78a08a3 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/basic-css/Size Your Images.md @@ -0,0 +1,101 @@ +--- +id: bad87fee1348bd9acdf08812 +title: Size Your Images +challengeType: 0 +videoUrl: 'https://scrimba.com/c/cM9MmCP' +--- + +## Description +
+CSS has a property called width that controls an element's width. Just like with fonts, we'll use px (pixels) to specify the image's width. +For example, if we wanted to create a CSS class called larger-image that gave HTML elements a width of 500 pixels, we'd use: +
<style>
  .larger-image {
    width: 500px;
  }
</style>
+
+ +## Instructions +
+Create a class called smaller-image and use it to resize the image so that it's only 100 pixels wide. +Note
Due to browser implementation differences, you may need to be at 100% zoom to pass the tests on this challenge. +
+ +## Tests +
+ +```yml +- text: Your img element should have the class smaller-image. + testString: 'assert($("img[src="https://bit.ly/fcc-relaxing-cat"]").attr("class") === "smaller-image", "Your img element should have the class smaller-image.");' +- text: Your image should be 100 pixels wide. Browser zoom should be at 100%. + testString: 'assert($("img").width() === 100, "Your image should be 100 pixels wide. Browser zoom should be at 100%.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + + + +

CatPhotoApp

+
+

Click here to view more cat photos.

+ + A cute orange cat lying on its back. + +
+

Things cats love:

+
    +
  • cat nip
  • +
  • laser pointers
  • +
  • lasagna
  • +
+

Top 3 things cats hate:

+
    +
  1. flea treatment
  2. +
  3. thunder
  4. +
  5. other cats
  6. +
+
+ +
+ +
+ + +
+ + +
+
+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/basic-css/Specify How Fonts Should Degrade.md b/curriculum/challenges/01-responsive-web-design/basic-css/Specify How Fonts Should Degrade.md new file mode 100644 index 0000000000..b200bb6119 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/basic-css/Specify How Fonts Should Degrade.md @@ -0,0 +1,108 @@ +--- +id: bad87fee1348bd9aedf08808 +title: Specify How Fonts Should Degrade +challengeType: 0 +videoUrl: 'https://scrimba.com/c/cpVKBfQ' +--- + +## Description +
+There are several default fonts that are available in all browsers. These generic font families include monospace, serif and sans-serif +When one font isn't available, you can tell the browser to "degrade" to another font. +For example, if you wanted an element to use the Helvetica font, but degrade to the sans-serif font when Helvetica wasn't available, you will specify it as follows: +
p {
  font-family: Helvetica, sans-serif;
}
+Generic font family names are not case-sensitive. Also, they do not need quotes because they are CSS keywords. +
+ +## Instructions +
+To begin with, apply the monospace font to the h2 element, so that it now has two fonts - Lobster and monospace. +In the last challenge, you imported the Lobster font using the link tag. Now comment out that import of the Lobster font(using the HTML comments you learned before) from Google Fonts so that it isn't available anymore. Notice how your h2 element degrades to the monospace font. +Note
If you have the Lobster font installed on your computer, you won't see the degradation because your browser is able to find the font. +
+ +## Tests +
+ +```yml +- text: Your h2 element should use the font Lobster. + testString: 'assert($("h2").css("font-family").match(/^"?lobster/i), "Your h2 element should use the font Lobster.");' +- text: Your h2 element should degrade to the font monospace when Lobster is not available. + testString: 'assert(/\s*h2\s*\{\s*font-family\:\s*(\"|")?Lobster(\"|")?,\s*monospace\s*;\s*\}/gi.test(code), "Your h2 element should degrade to the font monospace when Lobster is not available.");' +- text: 'Comment out your call to Google for the Lobster font by putting <!-- in front of it.' + testString: 'assert(new RegExp("", "gi").test(code), "Be sure to close your comment by adding -->.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + + + +

CatPhotoApp

+
+

Click here to view more cat photos.

+ + A cute orange cat lying on its back. + +
+

Things cats love:

+
    +
  • cat nip
  • +
  • laser pointers
  • +
  • lasagna
  • +
+

Top 3 things cats hate:

+
    +
  1. flea treatment
  2. +
  3. thunder
  4. +
  5. other cats
  6. +
+
+ +
+ +
+ + +
+ + +
+
+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/basic-css/Style Multiple Elements with a CSS Class.md b/curriculum/challenges/01-responsive-web-design/basic-css/Style Multiple Elements with a CSS Class.md new file mode 100644 index 0000000000..f59cb9fa94 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/basic-css/Style Multiple Elements with a CSS Class.md @@ -0,0 +1,94 @@ +--- +id: bad87fee1348bd9aefe08806 +title: Style Multiple Elements with a CSS Class +challengeType: 0 +videoUrl: 'https://scrimba.com/c/cRkVbsQ' +--- + +## Description +
+Classes allow you to use the same CSS styles on multiple HTML elements. You can see this by applying your red-text class to the first p element. +
+ +## Instructions +
+ +
+ +## Tests +
+ +```yml +- text: Your h2 element should be red. + testString: 'assert($("h2").css("color") === "rgb(255, 0, 0)", "Your h2 element should be red.");' +- text: Your h2 element should have the class red-text. + testString: 'assert($("h2").hasClass("red-text"), "Your h2 element should have the class red-text.");' +- text: Your first p element should be red. + testString: 'assert($("p:eq(0)").css("color") === "rgb(255, 0, 0)", "Your first p element should be red.");' +- text: Your second and third p elements should not be red. + testString: 'assert(!($("p:eq(1)").css("color") === "rgb(255, 0, 0)") && !($("p:eq(2)").css("color") === "rgb(255, 0, 0)"), "Your second and third p elements should not be red.");' +- text: Your first p element should have the class red-text. + testString: 'assert($("p:eq(0)").hasClass("red-text"), "Your first p element should have the class red-text.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + + +

CatPhotoApp

+
+

Click here to view more cat photos.

+ + A cute orange cat lying on its back. + +
+

Things cats love:

+
    +
  • cat nip
  • +
  • laser pointers
  • +
  • lasagna
  • +
+

Top 3 things cats hate:

+
    +
  1. flea treatment
  2. +
  3. thunder
  4. +
  5. other cats
  6. +
+
+ +
+ +
+ + +
+ + +
+
+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/basic-css/Style the HTML Body Element.md b/curriculum/challenges/01-responsive-web-design/basic-css/Style the HTML Body Element.md new file mode 100644 index 0000000000..83c5de791b --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/basic-css/Style the HTML Body Element.md @@ -0,0 +1,59 @@ +--- +id: bad87fee1348bd9aedf08736 +title: Style the HTML Body Element +challengeType: 0 +videoUrl: 'https://scrimba.com/c/cB77PHW' +--- + +## Description +
+Now let's start fresh and talk about CSS inheritance. +Every HTML page has a body element. +
+ +## Instructions +
+We can prove that the body element exists here by giving it a background-color of black. +We can do this by adding the following to our style element: +
body {
  background-color: black;
}
+
+ +## Tests +
+ +```yml +- text: Give your body element the background-color of black. + testString: 'assert($("body").css("background-color") === "rgb(0, 0, 0)", "Give your body element the background-color of black.");' +- text: Make sure your CSS rule is properly formatted with both opening and closing curly brackets. + testString: 'assert(code.match(/ +``` + + + + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/basic-css/Understand Absolute versus Relative Units.md b/curriculum/challenges/01-responsive-web-design/basic-css/Understand Absolute versus Relative Units.md new file mode 100644 index 0000000000..4c4b1ed2b0 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/basic-css/Understand Absolute versus Relative Units.md @@ -0,0 +1,89 @@ +--- +id: bad82fee1322bd9aedf08721 +title: Understand Absolute versus Relative Units +challengeType: 0 +videoUrl: 'https://scrimba.com/c/cN66JSL' +--- + +## Description +
+The last several challenges all set an element's margin or padding with pixels (px). Pixels are a type of length unit, which is what tells the browser how to size or space an item. In addition to px, CSS has a number of different length unit options that you can use. +The two main types of length units are absolute and relative. Absolute units tie to physical units of length. For example, in and mm refer to inches and millimeters, respectively. Absolute length units approximate the actual measurement on a screen, but there are some differences depending on a screen's resolution. +Relative units, such as em or rem, are relative to another length value. For example, em is based on the size of an element's font. If you use it to set the font-size property itself, it's relative to the parent's font-size. +Note
There are several relative unit options that are tied to the size of the viewport. They are covered in the Responsive Web Design Principles section. +
+ +## Instructions +
+Add a padding property to the element with class red-box and set it to 1.5em. +
+ +## Tests +
+ +```yml +- text: Your red-box class should have a padding property. + testString: 'assert($(".red-box").css("padding-top") != "0px" && $(".red-box").css("padding-right") != "0px" && $(".red-box").css("padding-bottom") != "0px" && $(".red-box").css("padding-left") != "0px", "Your red-box class should have a padding property.");' +- text: Your red-box class should give elements 1.5em of padding. + testString: 'assert(code.match(/\.red-box\s*?{\s*?.*?\s*?.*?\s*?padding:\s*?1\.5em/gi), "Your red-box class should give elements 1.5em of padding.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + +
margin
+ +
+
padding
+
padding
+
+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/basic-css/Use Abbreviated Hex Code.md b/curriculum/challenges/01-responsive-web-design/basic-css/Use Abbreviated Hex Code.md new file mode 100644 index 0000000000..c6dad990f3 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/basic-css/Use Abbreviated Hex Code.md @@ -0,0 +1,88 @@ +--- +id: bad87fee1348bd9aedf08719 +title: Use Abbreviated Hex Code +challengeType: 0 +videoUrl: 'https://scrimba.com/c/cRkpKAm' +--- + +## Description +
+Many people feel overwhelmed by the possibilities of more than 16 million colors. And it's difficult to remember hex code. Fortunately, you can shorten it. +For example, red's hex code #FF0000 can be shortened to #F00. This shortened form gives one digit for red, one digit for green, and one digit for blue. +This reduces the total number of possible colors to around 4,000. But browsers will interpret #FF0000 and #F00 as exactly the same color. +
+ +## Instructions +
+Go ahead, try using the abbreviated hex codes to color the correct elements. +
ColorShort Hex Code
Cyan#0FF
Green#0F0
Red#F00
Fuchsia#F0F
+
+ +## Tests +
+ +```yml +- text: Give your h1 element with the text I am red! the color red. + testString: 'assert($(".red-text").css("color") === "rgb(255, 0, 0)", "Give your h1 element with the text I am red! the color red.");' +- text: 'Use the abbreviate hex code for the color red instead of the hex code #FF0000.' + testString: 'assert(code.match(/\.red-text\s*?{\s*?color:\s*?#F00\s*?;\s*?}/gi), "Use the abbreviate hex code for the color red instead of the hex code #FF0000.");' +- text: Give your h1 element with the text I am green! the color green. + testString: 'assert($(".green-text").css("color") === "rgb(0, 255, 0)", "Give your h1 element with the text I am green! the color green.");' +- text: 'Use the abbreviated hex code for the color green instead of the hex code #00FF00.' + testString: 'assert(code.match(/\.green-text\s*?{\s*?color:\s*?#0F0\s*?;\s*?}/gi), "Use the abbreviated hex code for the color green instead of the hex code #00FF00.");' +- text: Give your h1 element with the text I am cyan! the color cyan. + testString: 'assert($(".cyan-text").css("color") === "rgb(0, 255, 255)", "Give your h1 element with the text I am cyan! the color cyan.");' +- text: 'Use the abbreviated hex code for the color cyan instead of the hex code #00FFFF.' + testString: 'assert(code.match(/\.cyan-text\s*?{\s*?color:\s*?#0FF\s*?;\s*?}/gi), "Use the abbreviated hex code for the color cyan instead of the hex code #00FFFF.");' +- text: Give your h1 element with the text I am fuchsia! the color fuchsia. + testString: 'assert($(".fuchsia-text").css("color") === "rgb(255, 0, 255)", "Give your h1 element with the text I am fuchsia! the color fuchsia.");' +- text: 'Use the abbreviated hex code for the color fuchsia instead of the hex code #FF00FF.' + testString: 'assert(code.match(/\.fuchsia-text\s*?{\s*?color:\s*?#F0F\s*?;\s*?}/gi), "Use the abbreviated hex code for the color fuchsia instead of the hex code #FF00FF.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + + +

I am red!

+ +

I am fuchsia!

+ +

I am cyan!

+ +

I am green!

+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/basic-css/Use Attribute Selectors to Style Elements.md b/curriculum/challenges/01-responsive-web-design/basic-css/Use Attribute Selectors to Style Elements.md new file mode 100644 index 0000000000..fc85cf3c95 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/basic-css/Use Attribute Selectors to Style Elements.md @@ -0,0 +1,118 @@ +--- +id: 58c383d33e2e3259241f3076 +title: Use Attribute Selectors to Style Elements +challengeType: 0 +videoUrl: 'https://scrimba.com/c/cnpymfJ' +--- + +## Description +
+You have been giving id or class attributes to elements that you wish to specifically style. These are known as ID and class selectors. There are other CSS Selectors you can use to select custom groups of elements to style. +Let's bring out CatPhotoApp again to practice using CSS Selectors. +For this challenge, you will use the [attr=value] attribute selector to style the checkboxes in CatPhotoApp. This selector matches and styles elements with a specific attribute value. For example, the below code changes the margins of all elements with the attribute type and a corresponding value of radio: +
[type='radio'] {
  margin: 20px 0px 20px 0px;
}
+
+ +## Instructions +
+Using the type attribute selector, try to give the checkboxes in CatPhotoApp a top margin of 10px and a bottom margin of 15px. +
+ +## Tests +
+ +```yml +- text: The type attribute selector should be used to select the checkboxes. + testString: 'assert(code.match(/ + +

CatPhotoApp

+
+

Click here to view more cat photos.

+ + A cute orange cat lying on its back. + +
+

Things cats love:

+
    +
  • cat nip
  • +
  • laser pointers
  • +
  • lasagna
  • +
+

Top 3 things cats hate:

+
    +
  1. flea treatment
  2. +
  3. thunder
  4. +
  5. other cats
  6. +
+
+ +
+ +
+ + +
+ + +
+
+``` + + + + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/basic-css/Use CSS Selectors to Style Elements.md b/curriculum/challenges/01-responsive-web-design/basic-css/Use CSS Selectors to Style Elements.md new file mode 100644 index 0000000000..614c8fb049 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/basic-css/Use CSS Selectors to Style Elements.md @@ -0,0 +1,95 @@ +--- +id: bad87fee1348bd9aedf08805 +title: Use CSS Selectors to Style Elements +challengeType: 0 +videoUrl: 'https://scrimba.com/c/cJKMBT2' +--- + +## Description +
+With CSS, there are hundreds of CSS properties that you can use to change the way an element looks on your page. +When you entered <h2 style="color: red">CatPhotoApp</h2>, you were styling that individual h2 element with inline CSS, which stands for Cascading Style Sheets. +That's one way to specify the style of an element, but there's a better way to apply CSS. +At the top of your code, create a style block like this: +
<style>
</style>
+Inside that style block, you can create a CSS selector for all h2 elements. For example, if you wanted all h2 elements to be red, you would add a style rule that looks like this: +
<style>
  h2 {color: red;}
</style>
+Note that it's important to have both opening and closing curly braces ({ and }) around each element's style rule(s). You also need to make sure that your element's style definition is between the opening and closing style tags. Finally, be sure to add a semicolon to the end of each of your element's style rules. +
+ +## Instructions +
+Delete your h2 element's style attribute, and instead create a CSS style block. Add the necessary CSS to turn all h2 elements blue. +
+ +## Tests +
+ +```yml +- text: Remove the style attribute from your h2 element. + testString: 'assert(!$("h2").attr("style"), "Remove the style attribute from your h2 element.");' +- text: Create a style element. + testString: 'assert($("style") && $("style").length > 1, "Create a style element.");' +- text: Your h2 element should be blue. + testString: 'assert($("h2").css("color") === "rgb(0, 0, 255)", "Your h2 element should be blue.");' +- text: Ensure that your stylesheet h2 declaration is valid with a semicolon and closing brace. + testString: 'assert(code.match(/h2\s*\{\s*color\s*:.*;\s*\}/g), "Ensure that your stylesheet h2 declaration is valid with a semicolon and closing brace.");' +- text: Make sure all your style elements are valid and have a closing tag. + testString: 'assert(code.match(/<\/style>/g) && code.match(/<\/style>/g).length === (code.match(//g) || []).length, "Make sure all your style elements are valid and have a closing tag.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html +

CatPhotoApp

+
+

Click here to view more cat photos.

+ + A cute orange cat lying on its back. + +
+

Things cats love:

+
    +
  • cat nip
  • +
  • laser pointers
  • +
  • lasagna
  • +
+

Top 3 things cats hate:

+
    +
  1. flea treatment
  2. +
  3. thunder
  4. +
  5. other cats
  6. +
+
+ +
+ +
+ + +
+ + +
+
+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/basic-css/Use CSS Variables to change several elements at once.md b/curriculum/challenges/01-responsive-web-design/basic-css/Use CSS Variables to change several elements at once.md new file mode 100644 index 0000000000..85df031514 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/basic-css/Use CSS Variables to change several elements at once.md @@ -0,0 +1,256 @@ +--- +id: 5a9d725e424fe3d0e10cad10 +title: Use CSS Variables to change several elements at once +challengeType: 0 +videoUrl: 'https://scrimba.com/c/c6bDECm' +--- + +## Description +
+CSS Variables are a powerful way to change many CSS style properties at once by changing only one value. +Follow the instructions below to see how changing just three values can change the styling of many elements. +
+ +## Instructions +
+In the penguin class, change the black value to gray, the gray value to white, and the yellow value to orange. +
+ +## Tests +
+ +```yml +- text: penguin class should declare the --penguin-skin variable and assign it to gray. + testString: 'assert(code.match(/.penguin\s*?{[\s\S]*--penguin-skin\s*?:\s*?gray\s*?;[\s\S]*}/gi), "penguin class should declare the --penguin-skin variable and assign it to gray.");' +- text: penguin class should declare the --penguin-belly variable and assign it to white. + testString: 'assert(code.match(/.penguin\s*?{[\s\S]*--penguin-belly\s*?:\s*?white\s*?;[\s\S]*}/gi), "penguin class should declare the --penguin-belly variable and assign it to white.");' +- text: penguin class should declare the --penguin-beak variable and assign it to orange. + testString: 'assert(code.match(/.penguin\s*?{[\s\S]*--penguin-beak\s*?:\s*?orange\s*?;[\s\S]*}/gi), "penguin class should declare the --penguin-beak variable and assign it to orange.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+``` + +
+ + + +
+ +## Solution +
+ + +```js +var code = ".penguin {--penguin-skin: gray; --penguin-belly: white; --penguin-beak: orange;}" +``` + +
diff --git a/curriculum/challenges/01-responsive-web-design/basic-css/Use Clockwise Notation to Specify the Margin of an Element.md b/curriculum/challenges/01-responsive-web-design/basic-css/Use Clockwise Notation to Specify the Margin of an Element.md new file mode 100644 index 0000000000..3b110fb4fb --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/basic-css/Use Clockwise Notation to Specify the Margin of an Element.md @@ -0,0 +1,93 @@ +--- +id: bad87fee1348bd9afdf08726 +title: Use Clockwise Notation to Specify the Margin of an Element +challengeType: 0 +videoUrl: 'https://scrimba.com/c/cB7mBS9' +--- + +## Description +
+Let's try this again, but with margin this time. +Instead of specifying an element's margin-top, margin-right, margin-bottom, and margin-left properties individually, you can specify them all in one line, like this: +margin: 10px 20px 10px 20px; +These four values work like a clock: top, right, bottom, left, and will produce the exact same result as using the side-specific margin instructions. +
+ +## Instructions +
+Use Clockwise Notation to give the element with the blue-box class a margin of 40px on its top and left side, but only 20px on its bottom and right side. +
+ +## Tests +
+ +```yml +- text: Your blue-box class should give the top of elements 40px of margin. + testString: 'assert($(".blue-box").css("margin-top") === "40px", "Your blue-box class should give the top of elements 40px of margin.");' +- text: Your blue-box class should give the right of elements 20px of margin. + testString: 'assert($(".blue-box").css("margin-right") === "20px", "Your blue-box class should give the right of elements 20px of margin.");' +- text: Your blue-box class should give the bottom of elements 20px of margin. + testString: 'assert($(".blue-box").css("margin-bottom") === "20px", "Your blue-box class should give the bottom of elements 20px of margin.");' +- text: Your blue-box class should give the left of elements 40px of margin. + testString: 'assert($(".blue-box").css("margin-left") === "40px", "Your blue-box class should give the left of elements 40px of margin.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + +
margin
+ +
+
padding
+
padding
+
+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/basic-css/Use Clockwise Notation to Specify the Padding of an Element.md b/curriculum/challenges/01-responsive-web-design/basic-css/Use Clockwise Notation to Specify the Padding of an Element.md new file mode 100644 index 0000000000..3fa6ed9293 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/basic-css/Use Clockwise Notation to Specify the Padding of an Element.md @@ -0,0 +1,94 @@ +--- +id: bad87fee1348bd9aedf08826 +title: Use Clockwise Notation to Specify the Padding of an Element +challengeType: 0 +videoUrl: 'https://scrimba.com/c/cB7mBS9' +--- + +## Description +
+Instead of specifying an element's padding-top, padding-right, padding-bottom, and padding-left properties individually, you can specify them all in one line, like this: +padding: 10px 20px 10px 20px; +These four values work like a clock: top, right, bottom, left, and will produce the exact same result as using the side-specific padding instructions. +
+ +## Instructions +
+Use Clockwise Notation to give the ".blue-box" class a padding of 40px on its top and left side, but only 20px on its bottom and right side. +
+ +## Tests +
+ +```yml +- text: Your blue-box class should give the top of elements 40px of padding. + testString: 'assert($(".blue-box").css("padding-top") === "40px", "Your blue-box class should give the top of elements 40px of padding.");' +- text: Your blue-box class should give the right of elements 20px of padding. + testString: 'assert($(".blue-box").css("padding-right") === "20px", "Your blue-box class should give the right of elements 20px of padding.");' +- text: Your blue-box class should give the bottom of elements 20px of padding. + testString: 'assert($(".blue-box").css("padding-bottom") === "20px", "Your blue-box class should give the bottom of elements 20px of padding.");' +- text: Your blue-box class should give the left of elements 40px of padding. + testString: 'assert($(".blue-box").css("padding-left") === "40px", "Your blue-box class should give the left of elements 40px of padding.");' +- text: You should use the clockwise notation to set the padding of blue-box class. + testString: 'assert(!/padding-top|padding-right|padding-bottom|padding-left/.test(code), "You should use the clockwise notation to set the padding of blue-box class.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + +
margin
+ +
+
padding
+
padding
+
+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/basic-css/Use Hex Code for Specific Colors.md b/curriculum/challenges/01-responsive-web-design/basic-css/Use Hex Code for Specific Colors.md new file mode 100644 index 0000000000..0f3e994bea --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/basic-css/Use Hex Code for Specific Colors.md @@ -0,0 +1,59 @@ +--- +id: bad87fee1348bd9aedf08726 +title: Use Hex Code for Specific Colors +challengeType: 0 +videoUrl: 'https://scrimba.com/c/c8W9mHM' +--- + +## Description +
+Did you know there are other ways to represent colors in CSS? One of these ways is called hexadecimal code, or hex code for short. +We usually use decimals, or base 10 numbers, which use the symbols 0 to 9 for each digit. Hexadecimals (or hex) are base 16 numbers. This means it uses sixteen distinct symbols. Like decimals, the symbols 0-9 represent the values zero to nine. Then A,B,C,D,E,F represent the values ten to fifteen. Altogether, 0 to F can represent a digit in hexadecimal, giving us 16 total possible values. You can find more information about hexadecimal numbers here. +In CSS, we can use 6 hexadecimal digits to represent colors, two each for the red (R), green (G), and blue (B) components. For example, #000000 is black and is also the lowest possible value. You can find more information about the RGB color system here. +
body {
  color: #000000;
}
+
+ +## Instructions +
+Replace the word black in our body element's background-color with its hex code representation, #000000. +
+ +## Tests +
+ +```yml +- text: Give your body element the background-color of black. + testString: 'assert($("body").css("background-color") === "rgb(0, 0, 0)", "Give your body element the background-color of black.");' +- text: Use the hex code for the color black instead of the word black. + testString: 'assert(code.match(/body\s*{(([\s\S]*;\s*?)|\s*?)background.*\s*:\s*?#000(000)?((\s*})|(;[\s\S]*?}))/gi), "Use the hex code for the color black instead of the word black.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + +``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/basic-css/Use Hex Code to Mix Colors.md b/curriculum/challenges/01-responsive-web-design/basic-css/Use Hex Code to Mix Colors.md new file mode 100644 index 0000000000..4f733928ce --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/basic-css/Use Hex Code to Mix Colors.md @@ -0,0 +1,90 @@ +--- +id: bad87fee1348bd9aedf08721 +title: Use Hex Code to Mix Colors +challengeType: 0 +videoUrl: 'https://scrimba.com/c/cK89PhP' +--- + +## Description +
+To review, hex codes use 6 hexadecimal digits to represent colors, two each for red (R), green (G), and blue (B) components. +From these three pure colors (red, green, and blue), we can vary the amounts of each to create over 16 million other colors! +For example, orange is pure red, mixed with some green, and no blue. In hex code, this translates to being #FFA500. +The digit 0 is the lowest number in hex code, and represents a complete absence of color. +The digit F is the highest number in hex code, and represents the maximum possible brightness. +
+ +## Instructions +
+Replace the color words in our style element with their correct hex codes. +
ColorHex Code
Dodger Blue#1E90FF
Green#00FF00
Orange#FFA500
Red#FF0000
+
+ +## Tests +
+ +```yml +- text: Give your h1 element with the text I am red! the color red. + testString: 'assert($(".red-text").css("color") === "rgb(255, 0, 0)", "Give your h1 element with the text I am red! the color red.");' +- text: Use the hex code for the color red instead of the word red. + testString: 'assert(code.match(/\.red-text\s*?{\s*?color:\s*?#FF0000\s*?;\s*?}/gi), "Use the hex code for the color red instead of the word red.");' +- text: Give your h1 element with the text I am green! the color green. + testString: 'assert($(".green-text").css("color") === "rgb(0, 255, 0)", "Give your h1 element with the text I am green! the color green.");' +- text: Use the hex code for the color green instead of the word green. + testString: 'assert(code.match(/\.green-text\s*?{\s*?color:\s*?#00FF00\s*?;\s*?}/gi), "Use the hex code for the color green instead of the word green.");' +- text: Give your h1 element with the text I am dodger blue! the color dodger blue. + testString: 'assert($(".dodger-blue-text").css("color") === "rgb(30, 144, 255)", "Give your h1 element with the text I am dodger blue! the color dodger blue.");' +- text: Use the hex code for the color dodger blue instead of the word dodgerblue. + testString: 'assert(code.match(/\.dodger-blue-text\s*?{\s*?color:\s*?#1E90FF\s*?;\s*?}/gi), "Use the hex code for the color dodger blue instead of the word dodgerblue.");' +- text: Give your h1 element with the text I am orange! the color orange. + testString: 'assert($(".orange-text").css("color") === "rgb(255, 165, 0)", "Give your h1 element with the text I am orange! the color orange.");' +- text: Use the hex code for the color orange instead of the word orange. + testString: 'assert(code.match(/\.orange-text\s*?{\s*?color:\s*?#FFA500\s*?;\s*?}/gi), "Use the hex code for the color orange instead of the word orange.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + + +

I am red!

+ +

I am green!

+ +

I am dodger blue!

+ +

I am orange!

+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/basic-css/Use RGB to Mix Colors.md b/curriculum/challenges/01-responsive-web-design/basic-css/Use RGB to Mix Colors.md new file mode 100644 index 0000000000..f2e460651b --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/basic-css/Use RGB to Mix Colors.md @@ -0,0 +1,86 @@ +--- +id: bad82fee1348bd9aedf08721 +title: Use RGB to Mix Colors +challengeType: 0 +videoUrl: 'https://scrimba.com/c/cm24JU6' +--- + +## Description +
+Just like with hex code, you can mix colors in RGB by using combinations of different values. +
+ +## Instructions +
+Replace the hex codes in our style element with their correct RGB values. +
ColorRGB
Bluergb(0, 0, 255)
Redrgb(255, 0, 0)
Orchidrgb(218, 112, 214)
Siennargb(160, 82, 45)
+
+ +## Tests +
+ +```yml +- text: Give your h1 element with the text I am red! the color red. + testString: 'assert($(".red-text").css("color") === "rgb(255, 0, 0)", "Give your h1 element with the text I am red! the color red.");' +- text: Use rgb for the color red. + testString: 'assert(code.match(/\.red-text\s*?{\s*?color:\s*?rgb\(\s*?255\s*?,\s*?0\s*?,\s*?0\s*?\)\s*?;\s*?}/gi), "Use rgb for the color red.");' +- text: Give your h1 element with the text I am orchid! the color orchid. + testString: 'assert($(".orchid-text").css("color") === "rgb(218, 112, 214)", "Give your h1 element with the text I am orchid! the color orchid.");' +- text: Use rgb for the color orchid. + testString: 'assert(code.match(/\.orchid-text\s*?{\s*?color:\s*?rgb\(\s*?218\s*?,\s*?112\s*?,\s*?214\s*?\)\s*?;\s*?}/gi), "Use rgb for the color orchid.");' +- text: Give your h1 element with the text I am blue! the color blue. + testString: 'assert($(".blue-text").css("color") === "rgb(0, 0, 255)", "Give your h1 element with the text I am blue! the color blue.");' +- text: Use rgb for the color blue. + testString: 'assert(code.match(/\.blue-text\s*?{\s*?color:\s*?rgb\(\s*?0\s*?,\s*?0\s*?,\s*?255\s*?\)\s*?;\s*?}/gi), "Use rgb for the color blue.");' +- text: Give your h1 element with the text I am sienna! the color sienna. + testString: 'assert($(".sienna-text").css("color") === "rgb(160, 82, 45)", "Give your h1 element with the text I am sienna! the color sienna.");' +- text: Use rgb for the color sienna. + testString: 'assert(code.match(/\.sienna-text\s*?{\s*?color:\s*?rgb\(\s*?160\s*?,\s*?82\s*?,\s*?45\s*?\)\s*?;\s*?}/gi), "Use rgb for the color sienna.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + + +

I am red!

+ +

I am orchid!

+ +

I am sienna!

+ +

I am blue!

+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/basic-css/Use RGB values to Color Elements.md b/curriculum/challenges/01-responsive-web-design/basic-css/Use RGB values to Color Elements.md new file mode 100644 index 0000000000..37fd8426cf --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/basic-css/Use RGB values to Color Elements.md @@ -0,0 +1,64 @@ +--- +id: bad87fee1348bd9aede08718 +title: Use RGB values to Color Elements +challengeType: 0 +videoUrl: 'https://scrimba.com/c/cRkp2fr' +--- + +## Description +
+Another way you can represent colors in CSS is by using RGB values. +The RGB value for black looks like this: +rgb(0, 0, 0) +The RGB value for white looks like this: +rgb(255, 255, 255) +Instead of using six hexadecimal digits like you do with hex code, with RGB you specify the brightness of each color with a number between 0 and 255. +If you do the math, the two digits for one color equal 16 times 16, which gives us 256 total values. So RGB, which starts counting from zero, has the exact same number of possible values as hex code. +Here's an example of how you'd change the body background to orange using its RGB code. +
body {
  background-color: rgb(255, 165, 0);
}
+
+ +## Instructions +
+Let's replace the hex code in our body element's background color with the RGB value for black: rgb(0, 0, 0) +
+ +## Tests +
+ +```yml +- text: Your body element should have a black background. + testString: 'assert($("body").css("background-color") === "rgb(0, 0, 0)", "Your body element should have a black background.");' +- text: Use rgb to give your body element a color of black. + testString: 'assert(code.match(/rgb\s*\(\s*0\s*,\s*0\s*,\s*0\s*\)/ig), "Use rgb to give your body element a color of black.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + +``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/basic-css/Use a CSS Class to Style an Element.md b/curriculum/challenges/01-responsive-web-design/basic-css/Use a CSS Class to Style an Element.md new file mode 100644 index 0000000000..f5e566cca5 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/basic-css/Use a CSS Class to Style an Element.md @@ -0,0 +1,99 @@ +--- +id: bad87fee1348bd9aecf08806 +title: Use a CSS Class to Style an Element +challengeType: 0 +videoUrl: 'https://scrimba.com/c/c2MvDtV' +--- + +## Description +
+Classes are reusable styles that can be added to HTML elements. +Here's an example CSS class declaration: +
<style>
  .blue-text {
    color: blue;
  }
</style>
+You can see that we've created a CSS class called blue-text within the <style> tag. +You can apply a class to an HTML element like this: +<h2 class="blue-text">CatPhotoApp</h2> +Note that in your CSS style element, class names start with a period. In your HTML elements' class attribute, the class name does not include the period. +
+ +## Instructions +
+Inside your style element, change the h2 selector to .red-text and update the color's value from blue to red. +Give your h2 element the class attribute with a value of 'red-text'. +
+ +## Tests +
+ +```yml +- text: Your h2 element should be red. + testString: 'assert($("h2").css("color") === "rgb(255, 0, 0)", "Your h2 element should be red.");' +- text: Your h2 element should have the class red-text. + testString: 'assert($("h2").hasClass("red-text"), "Your h2 element should have the class red-text.");' +- text: Your stylesheet should declare a red-text class and have its color set to red. + testString: 'assert(code.match(/\.red-text\s*\{\s*color\s*:\s*red;\s*\}/g), "Your stylesheet should declare a red-text class and have its color set to red.");' +- text: 'Do not use inline style declarations like style="color: red" in your h2 element.' + testString: 'assert($("h2").attr("style") === undefined, "Do not use inline style declarations like style="color: red" in your h2 element.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + + +

CatPhotoApp

+
+

Click here to view more cat photos.

+ + A cute orange cat lying on its back. + +
+

Things cats love:

+
    +
  • cat nip
  • +
  • laser pointers
  • +
  • lasagna
  • +
+

Top 3 things cats hate:

+
    +
  1. flea treatment
  2. +
  3. thunder
  4. +
  5. other cats
  6. +
+
+ +
+ +
+ + +
+ + +
+
+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/basic-css/Use a custom CSS Variable.md b/curriculum/challenges/01-responsive-web-design/basic-css/Use a custom CSS Variable.md new file mode 100644 index 0000000000..5a3866c522 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/basic-css/Use a custom CSS Variable.md @@ -0,0 +1,270 @@ +--- +id: 5a9d727a424fe3d0e10cad12 +title: Use a custom CSS Variable +challengeType: 0 +videoUrl: 'https://scrimba.com/c/cM989ck' +--- + +## Description +
+After you create your variable, you can assign its value to other CSS properties by referencing the name you gave it. +
background: var(--penguin-skin);
+This will change the background of whatever element you are targeting to gray because that is the value of the --penguin-skin variable. +Note that styles will not be applied unless the variable names are an exact match. +
+ +## Instructions +
+Apply the --penguin-skin variable to the background property of the penguin-top, penguin-bottom, right-hand and left-hand classes. +
+ +## Tests +
+ +```yml +- text: Apply the --penguin-skin variable to the background property of the penguin-top class. + testString: 'assert(code.match(/.penguin-top\s*?{[\s\S]*background\s*?:\s*?var\s*?\(\s*?--penguin-skin\s*?\)\s*?;[\s\S]*}[\s\S]*.penguin-bottom\s{/gi), "Apply the --penguin-skin variable to the background property of the penguin-top class.");' +- text: Apply the --penguin-skin variable to the background property of the penguin-bottom class. + testString: 'assert(code.match(/.penguin-bottom\s*?{[\s\S]*background\s*?:\s*?var\s*?\(\s*?--penguin-skin\s*?\)\s*?;[\s\S]*}[\s\S]*.right-hand\s{/gi), "Apply the --penguin-skin variable to the background property of the penguin-bottom class.");' +- text: Apply the --penguin-skin variable to the background property of the right-hand class. + testString: 'assert(code.match(/.right-hand\s*?{[\s\S]*background\s*?:\s*?var\s*?\(\s*?--penguin-skin\s*?\)\s*?;[\s\S]*}[\s\S]*.left-hand\s{/gi), "Apply the --penguin-skin variable to the background property of the right-hand class.");' +- text: Apply the --penguin-skin variable to the background property of the left-hand class. + testString: 'assert(code.match(/.left-hand\s*?{[\s\S]*background\s*?:\s*?var\s*?\(\s*?--penguin-skin\s*?\)\s*?;[\s\S]*}/gi), "Apply the --penguin-skin variable to the background property of the left-hand class.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+``` + +
+ + + +
+ +## Solution +
+ + +```js +var code = ".penguin-top {background: var(--penguin-skin);} .penguin-bottom {background: var(--penguin-skin);} .right-hand {background: var(--penguin-skin);} .left-hand {background: var(--penguin-skin);}" +``` + +
diff --git a/curriculum/challenges/01-responsive-web-design/basic-css/Use a media query to change a variable.md b/curriculum/challenges/01-responsive-web-design/basic-css/Use a media query to change a variable.md new file mode 100644 index 0000000000..567ead35b9 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/basic-css/Use a media query to change a variable.md @@ -0,0 +1,284 @@ +--- +id: 5a9d72ad424fe3d0e10cad16 +title: Use a media query to change a variable +challengeType: 0 +videoUrl: 'https://scrimba.com/c/cWmL8UP' +--- + +## Description +
+CSS Variables can simplify the way you use media queries. +For instance, when your screen is smaller or larger than your media query break point, you can change the value of a variable, and it will apply its style wherever it is used. +
+ +## Instructions +
+In the :root selector of the media query, change it so --penguin-size is redefined and given a value of 200px. Also, redefine --penguin-skin and give it a value of black. Then resize the preview to see this change in action. +
+ +## Tests +
+ +```yml +- text: ':root should reassign the --penguin-size variable to 200px.' + testString: 'assert(code.match(/media\s*?\(\s*?max-width\s*?:\s*?350px\s*?\)\s*?{[\s\S]*:root\s*?{[\s\S]*--penguin-size\s*?:\s*?200px\s*?;[\s\S]*}[\s\S]*}/gi), ":root should reassign the --penguin-size variable to 200px.");' +- text: ':root should reassign the --penguin-skin variable to black.' + testString: 'assert(code.match(/media\s*?\(\s*?max-width\s*?:\s*?350px\s*?\)\s*?{[\s\S]*:root\s*?{[\s\S]*--penguin-skin\s*?:\s*?black\s*?;[\s\S]*}[\s\S]*}/gi), ":root should reassign the --penguin-skin variable to black.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+``` + +
+ + + +
+ +## Solution +
+ + +```js +var code = "@media (max-width: 350px) {:root {--penguin-size: 200px; --penguin-skin: black;}}" +``` + +
diff --git a/curriculum/challenges/01-responsive-web-design/basic-css/Use an id Attribute to Style an Element.md b/curriculum/challenges/01-responsive-web-design/basic-css/Use an id Attribute to Style an Element.md new file mode 100644 index 0000000000..91642ca577 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/basic-css/Use an id Attribute to Style an Element.md @@ -0,0 +1,121 @@ +--- +id: bad87dee1348bd9aede07836 +title: Use an id Attribute to Style an Element +challengeType: 0 +videoUrl: 'https://scrimba.com/c/cakyZfL' +--- + +## Description +
+One cool thing about id attributes is that, like classes, you can style them using CSS. +However, an id is not reusable and should only be applied to one element. An id also has a higher specificity (importance) than a class so if both are applied to the same element and have conflicting styles, the styles of the id will be applied. +Here's an example of how you can take your element with the id attribute of cat-photo-element and give it the background color of green. In your style element: +
#cat-photo-element {
  background-color: green;
}
+Note that inside your style element, you always reference classes by putting a . in front of their names. You always reference ids by putting a # in front of their names. +
+ +## Instructions +
+Try giving your form, which now has the id attribute of cat-photo-form, a green background. +
+ +## Tests +
+ +```yml +- text: Give your form element the id of cat-photo-form. + testString: 'assert($("form").attr("id") === "cat-photo-form", "Give your form element the id of cat-photo-form.");' +- text: Your form element should have the background-color of green. + testString: 'assert($("#cat-photo-form").css("background-color") === "rgb(0, 128, 0)", "Your form element should have the background-color of green.");' +- text: Make sure your form element has an id attribute. + testString: 'assert(code.match(//gi) && code.match(//gi).length > 0, "Make sure your form element has an id attribute.");' +- text: Do not give your form any class or style attributes. + testString: 'assert(!code.match(//gi) && !code.match(//gi), "Do not give your form any class or style attributes.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + + + +

CatPhotoApp

+
+

Click here to view more cat photos.

+ + A cute orange cat lying on its back. + +
+

Things cats love:

+
    +
  • cat nip
  • +
  • laser pointers
  • +
  • lasagna
  • +
+

Top 3 things cats hate:

+
    +
  1. flea treatment
  2. +
  3. thunder
  4. +
  5. other cats
  6. +
+
+ +
+ +
+ + +
+ + +
+
+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/basic-css/meta.json b/curriculum/challenges/01-responsive-web-design/basic-css/meta.json new file mode 100644 index 0000000000..40ca1dcb58 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/basic-css/meta.json @@ -0,0 +1,8 @@ +{ + "name": "Basic CSS", + "dashedName": "basic-css", + "order": 1, + "time": "5 hours", + "superBlock": "responsive-web-design", + "superOrder": 1 +} \ No newline at end of file diff --git a/curriculum/challenges/01-responsive-web-design/basic-html-and-html5/Add Images to Your Website.md b/curriculum/challenges/01-responsive-web-design/basic-html-and-html5/Add Images to Your Website.md new file mode 100644 index 0000000000..65f2e2ea0a --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/basic-html-and-html5/Add Images to Your Website.md @@ -0,0 +1,73 @@ +--- +id: bad87fee1348bd9aedf08812 +title: Add Images to Your Website +challengeType: 0 +guideUrl: 'https://guide.freecodecamp.org/certificates/add-images-to-your-website' +videoUrl: 'https://scrimba.com/p/pVMPUv/c8EbJf2' +--- + +## Description +
+You can add images to your website by using the img element, and point to a specific image's URL using the src attribute. +An example of this would be: +<img src="https://www.your-image-source.com/your-image.jpg"> +Note that img elements are self-closing. +All img elements must have an alt attribute. The text inside an alt attribute is used for screen readers to improve accessibility and is displayed if the image fails to load. +Note: If the image is purely decorative, using an empty alt attribute is a best practice. +Ideally the alt attribute should not contain special characters unless needed. +Let's add an alt attribute to our img example above: +<img src="https://www.your-image-source.com/your-image.jpg" alt="Author standing on a beach with two thumbs up."> +
+ +## Instructions +
+Let's try to add an image to our website: +Insert an img tag, before the h2 element. +Now set the src attribute so that it points to this url: +https://bit.ly/fcc-relaxing-cat +Finally don't forget to give your image an alt text. +
+ +## Tests +
+ +```yml +- text: Your page should have an image element. + testString: 'assert($("img").length > 0, "Your page should have an image element.");' +- text: Your image should have a src attribute that points to the kitten image. + testString: 'assert(new RegExp("\/\/bit.ly\/fcc-relaxing-cat|\/\/s3.amazonaws.com\/freecodecamp\/relaxing-cat.jpg", "gi").test($("img").attr("src")), "Your image should have a src attribute that points to the kitten image.");' +- text: Your image element must have an alt attribute. + testString: 'assert(code.match(/alt\s*?=\s*?(\"|\").*(\"|\")/), "Your image element must have an alt attribute.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html +

CatPhotoApp

+
+ + +

Kitty ipsum dolor sit amet, shed everywhere shed everywhere stretching attack your ankles chase the red dot, hairball run catnip eat the grass sniff.

+

Purr jump eat the grass rip the couch scratched sunbathe, shed everywhere rip the couch sleep in the sink fluffy fur catnip scratched.

+
+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/basic-html-and-html5/Add Placeholder Text to a Text Field.md b/curriculum/challenges/01-responsive-web-design/basic-html-and-html5/Add Placeholder Text to a Text Field.md new file mode 100644 index 0000000000..18881fc722 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/basic-html-and-html5/Add Placeholder Text to a Text Field.md @@ -0,0 +1,76 @@ +--- +id: bad87fee1348bd9aedf08830 +title: Add Placeholder Text to a Text Field +challengeType: 0 +guideUrl: 'https://guide.freecodecamp.org/certificates/add-placeholder-text-to-a-text-field' +videoUrl: 'https://scrimba.com/p/pVMPUv/cKdJDhg' +--- + +## Description +
+Placeholder text is what is displayed in your input element before your user has inputted anything. +You can create placeholder text like so: +<input type="text" placeholder="this is placeholder text"> +
+ +## Instructions +
+Set the placeholder value of your text input to "cat photo URL". +
+ +## Tests +
+ +```yml +- text: Add a placeholder attribute to the existing text input element. + testString: 'assert($("input[placeholder]").length > 0, "Add a placeholder attribute to the existing text input element.");' +- text: Set the value of your placeholder attribute to "cat photo URL". + testString: 'assert($("input") && $("input").attr("placeholder") && $("input").attr("placeholder").match(/cat\s+photo\s+URL/gi), "Set the value of your placeholder attribute to "cat photo URL".");' +- text: The finished input element should have valid syntax. + testString: 'assert($("input[type=text]").length > 0 && code.match(/\s]+))?)+\s*|\s*)\/?>/gi), "The finished input element should have valid syntax.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html +

CatPhotoApp

+
+

Click here to view more cat photos.

+ + A cute orange cat lying on its back. + +

Things cats love:

+
    +
  • cat nip
  • +
  • laser pointers
  • +
  • lasagna
  • +
+

Top 3 things cats hate:

+
    +
  1. flea treatment
  2. +
  3. thunder
  4. +
  5. other cats
  6. +
+ +
+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/basic-html-and-html5/Add a Submit Button to a Form.md b/curriculum/challenges/01-responsive-web-design/basic-html-and-html5/Add a Submit Button to a Form.md new file mode 100644 index 0000000000..fbdeb31fae --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/basic-html-and-html5/Add a Submit Button to a Form.md @@ -0,0 +1,80 @@ +--- +id: bad87fee1348bd9aedd08830 +title: Add a Submit Button to a Form +challengeType: 0 +guideUrl: 'https://guide.freecodecamp.org/certificates/add-a-submit-button-to-a-form' +videoUrl: 'https://scrimba.com/p/pVMPUv/cp2Nkhz' +--- + +## Description +
+Let's add a submit button to your form. Clicking this button will send the data from your form to the URL you specified with your form's action attribute. +Here's an example submit button: +<button type="submit">this button submits the form</button> +
+ +## Instructions +
+Add a button as the last element of your form element with a type of submit, and "Submit" as its text. +
+ +## Tests +
+ +```yml +- text: Your form should have a button inside it. + testString: 'assert($("form").children("button").length > 0, "Your form should have a button inside it.");' +- text: Your submit button should have the attribute type set to submit. + testString: 'assert($("button").attr("type") === "submit", "Your submit button should have the attribute type set to submit.");' +- text: Your submit button should only have the text "Submit". + testString: 'assert($("button").text().match(/^\s*submit\s*$/gi), "Your submit button should only have the text "Submit".");' +- text: Make sure your button element has a closing tag. + testString: 'assert(code.match(/<\/button>/g) && code.match(/
+ +## Challenge Seed +
+ +
+ +```html +

CatPhotoApp

+
+

Click here to view more cat photos.

+ + A cute orange cat lying on its back. + +

Things cats love:

+
    +
  • cat nip
  • +
  • laser pointers
  • +
  • lasagna
  • +
+

Top 3 things cats hate:

+
    +
  1. flea treatment
  2. +
  3. thunder
  4. +
  5. other cats
  6. +
+
+ +
+
+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/basic-html-and-html5/Check Radio Buttons and Checkboxes by Default.md b/curriculum/challenges/01-responsive-web-design/basic-html-and-html5/Check Radio Buttons and Checkboxes by Default.md new file mode 100644 index 0000000000..6c9c7cc88a --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/basic-html-and-html5/Check Radio Buttons and Checkboxes by Default.md @@ -0,0 +1,81 @@ +--- +id: bad87fee1348bd9aedd08835 +title: Check Radio Buttons and Checkboxes by Default +challengeType: 0 +videoUrl: 'https://scrimba.com/p/pVMPUv/cWk3Qh6' +--- + +## Description +
+You can set a checkbox or radio button to be checked by default using the checked attribute. +To do this, just add the word "checked" to the inside of an input element. For example: +<input type="radio" name="test-name" checked> +
+ +## Instructions +
+Set the first of your radio buttons and the first of your checkboxes to both be checked by default. +
+ +## Tests +
+ +```yml +- text: Your first radio button on your form should be checked by default. + testString: 'assert($("input[type="radio"]").prop("checked"), "Your first radio button on your form should be checked by default.");' +- text: Your first checkbox on your form should be checked by default. + testString: 'assert($("input[type="checkbox"]").prop("checked"), "Your first checkbox on your form should be checked by default.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html +

CatPhotoApp

+
+

Click here to view more cat photos.

+ + A cute orange cat lying on its back. + +

Things cats love:

+
    +
  • cat nip
  • +
  • laser pointers
  • +
  • lasagna
  • +
+

Top 3 things cats hate:

+
    +
  1. flea treatment
  2. +
  3. thunder
  4. +
  5. other cats
  6. +
+
+ +
+ + +
+ + +
+
+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/basic-html-and-html5/Comment out HTML.md b/curriculum/challenges/01-responsive-web-design/basic-html-and-html5/Comment out HTML.md new file mode 100644 index 0000000000..5530091086 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/basic-html-and-html5/Comment out HTML.md @@ -0,0 +1,65 @@ +--- +id: bad87fee1348bd9aedf08804 +title: Comment out HTML +challengeType: 0 +videoUrl: 'https://scrimba.com/p/pVMPUv/cGyGbca' +--- + +## Description +
+Remember that in order to start a comment, you need to use <!-- and to end a comment, you need to use --> +Here you'll need to end the comment before your h2 element begins. +
+ +## Instructions +
+Comment out your h1 element and your p element, but not your h2 element. +
+ +## Tests +
+ +```yml +- text: Comment out your h1 element so that it is not visible on your page. + testString: 'assert(($("h1").length === 0), "Comment out your h1 element so that it is not visible on your page.");' +- text: Leave your h2 element uncommented so that it is visible on your page. + testString: 'assert(($("h2").length > 0), "Leave your h2 element uncommented so that it is visible on your page.");' +- text: Comment out your p element so that it is not visible on your page. + testString: 'assert(($("p").length === 0), "Comment out your p element so that it is not visible on your page.");' +- text: 'Be sure to close each of your comments with -->.' + testString: 'assert(code.match(/[^fc]-->/g).length > 1, "Be sure to close each of your comments with -->.");' +- text: Do not change the order of the h1 h2 or p in the code. + testString: 'assert((code.match(/<([a-z0-9]){1,2}>/g)[0]==="

" && code.match(/<([a-z0-9]){1,2}>/g)[1]==="

" && code.match(/<([a-z0-9]){1,2}>/g)[2]==="

") , "Do not change the order of the h1 h2 or p in the code.");' + +``` + +

+ +## Challenge Seed +
+ +
+ +```html + +``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/basic-html-and-html5/Create a Bulleted Unordered List.md b/curriculum/challenges/01-responsive-web-design/basic-html-and-html5/Create a Bulleted Unordered List.md new file mode 100644 index 0000000000..7274e57950 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/basic-html-and-html5/Create a Bulleted Unordered List.md @@ -0,0 +1,68 @@ +--- +id: bad87fee1348bd9aedf08827 +title: Create a Bulleted Unordered List +challengeType: 0 +videoUrl: 'https://scrimba.com/p/pVMPUv/cDKVPuv' +--- + +## Description +
+HTML has a special element for creating unordered lists, or bullet point style lists. +Unordered lists start with an opening <ul> element, followed by any number of <li> elements. Finally, unordered lists close with a </ul> +For example: +
<ul>
  <li>milk</li>
  <li>cheese</li>
</ul>
+would create a bullet point style list of "milk" and "cheese". +
+ +## Instructions +
+Remove the last two p elements and create an unordered list of three things that cats love at the bottom of the page. +
+ +## Tests +
+ +```yml +- text: Create a ul element. + testString: 'assert($("ul").length > 0, "Create a ul element.");' +- text: You should have three li elements within your ul element. + testString: 'assert($("ul li").length > 2, "You should have three li elements within your ul element.");' +- text: Make sure your ul element has a closing tag. + testString: 'assert(code.match(/<\/ul>/gi) && code.match(/
+ +## Challenge Seed +
+ +
+ +```html +

CatPhotoApp

+
+

Click here to view more cat photos.

+ + A cute orange cat lying on its back. + +

Kitty ipsum dolor sit amet, shed everywhere shed everywhere stretching attack your ankles chase the red dot, hairball run catnip eat the grass sniff.

+

Purr jump eat the grass rip the couch scratched sunbathe, shed everywhere rip the couch sleep in the sink fluffy fur catnip scratched.

+
+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/basic-html-and-html5/Create a Form Element.md b/curriculum/challenges/01-responsive-web-design/basic-html-and-html5/Create a Form Element.md new file mode 100644 index 0000000000..350d4b1358 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/basic-html-and-html5/Create a Form Element.md @@ -0,0 +1,75 @@ +--- +id: bad87fee1348bd9aede08830 +title: Create a Form Element +challengeType: 0 +videoUrl: 'https://scrimba.com/p/pVMPUv/cmQ3Kfa' +--- + +## Description +
+You can build web forms that actually submit data to a server using nothing more than pure HTML. You can do this by specifying an action on your form element. +For example: +<form action="/url-where-you-want-to-submit-form-data"></form> +
+ +## Instructions +
+Nest your text field inside a form element, and add the action="/submit-cat-photo" attribute to the form element. +
+ +## Tests +
+ +```yml +- text: Nest your text input element within a form element. + testString: 'assert($("form") && $("form").children("input") && $("form").children("input").length > 0, "Nest your text input element within a form element.");' +- text: Make sure your form has an action attribute which is set to /submit-cat-photo + testString: 'assert($("form").attr("action") === "/submit-cat-photo", "Make sure your form has an action attribute which is set to /submit-cat-photo");' +- text: Make sure your form element has well-formed open and close tags. + testString: 'assert(code.match(/<\/form>/g) && code.match(/
/g) && code.match(/<\/form>/g).length === code.match(//g).length, "Make sure your form element has well-formed open and close tags.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html +

CatPhotoApp

+
+

Click here to view more cat photos.

+ + A cute orange cat lying on its back. + +

Things cats love:

+
    +
  • cat nip
  • +
  • laser pointers
  • +
  • lasagna
  • +
+

Top 3 things cats hate:

+
    +
  1. flea treatment
  2. +
  3. thunder
  4. +
  5. other cats
  6. +
+ +
+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/basic-html-and-html5/Create a Set of Checkboxes.md b/curriculum/challenges/01-responsive-web-design/basic-html-and-html5/Create a Set of Checkboxes.md new file mode 100644 index 0000000000..1d03728302 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/basic-html-and-html5/Create a Set of Checkboxes.md @@ -0,0 +1,86 @@ +--- +id: bad87fee1348bd9aedf08835 +title: Create a Set of Checkboxes +challengeType: 0 +videoUrl: 'https://scrimba.com/p/pVMPUv/cqrkJsp' +--- + +## Description +
+Forms commonly use checkboxes for questions that may have more than one answer. +Checkboxes are a type of input +Each of your checkboxes can be nested within its own label element. By wrapping an input element inside of a label element it will automatically associate the checkbox input with the label element surrounding it. +All related checkbox inputs should have the same name attribute. +It is considered best practice to explicitly define the relationship between a checkbox input and its corresponding label by setting the for attribute on the label element to match the id attribute of the associated input element. +Here's an example of a checkbox: +<label for="loving"><input id="loving" type="checkbox" name="personality"> Loving</label> +
+ +## Instructions +
+Add to your form a set of three checkboxes. Each checkbox should be nested within its own label element. All three should share the name attribute of personality. +
+ +## Tests +
+ +```yml +- text: Your page should have three checkbox elements. + testString: 'assert($("input[type="checkbox"]").length > 2, "Your page should have three checkbox elements.");' +- text: Each of your three checkbox elements should be nested in its own label element. + testString: 'assert($("label > input[type="checkbox"]:only-child").length > 2, "Each of your three checkbox elements should be nested in its own label element.");' +- text: Make sure each of your label elements has a closing tag. + testString: 'assert(code.match(/<\/label>/g) && code.match(/
+ +## Challenge Seed +
+ +
+ +```html +

CatPhotoApp

+
+

Click here to view more cat photos.

+ + A cute orange cat lying on its back. + +

Things cats love:

+
    +
  • cat nip
  • +
  • laser pointers
  • +
  • lasagna
  • +
+

Top 3 things cats hate:

+
    +
  1. flea treatment
  2. +
  3. thunder
  4. +
  5. other cats
  6. +
+ + +
+ + + +
+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/basic-html-and-html5/Create a Set of Radio Buttons.md b/curriculum/challenges/01-responsive-web-design/basic-html-and-html5/Create a Set of Radio Buttons.md new file mode 100644 index 0000000000..c76d5231e0 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/basic-html-and-html5/Create a Set of Radio Buttons.md @@ -0,0 +1,91 @@ +--- +id: bad87fee1348bd9aedf08834 +title: Create a Set of Radio Buttons +challengeType: 0 +videoUrl: 'https://scrimba.com/p/pVMPUv/cNWKvuR' +--- + +## Description +
+You can use radio buttons for questions where you want the user to only give you one answer out of multiple options. +Radio buttons are a type of input. +Each of your radio buttons can be nested within its own label element. By wrapping an input element inside of a label element it will automatically associate the radio button input with the label element surrounding it. +All related radio buttons should have the same name attribute to create a radio button group. By creating a radio group, selecting any single radio button will automatically deselect the other buttons within the same group ensuring only one answer is provided by the user. +Here's an example of a radio button: +
<label>
  <input type="radio" name="indoor-outdoor">Indoor
</label>
+It is considered best practice to set a for attribute on the label element, with a value that matches the value of the id attribute of the input element. This allows assistive technologies to create a linked relationship between the label and the child input element. For example: +
<label for="indoor">
  <input id="indoor" type="radio" name="indoor-outdoor">Indoor
</label>
+
+ +## Instructions +
+Add a pair of radio buttons to your form, each nested in its own label element. One should have the option of indoor and the other should have the option of outdoor. Both should share the name attribute of indoor-outdoor to create a radio group. +
+ +## Tests +
+ +```yml +- text: Your page should have two radio button elements. + testString: 'assert($("input[type="radio"]").length > 1, "Your page should have two radio button elements.");' +- text: Give your radio buttons the name attribute of indoor-outdoor. + testString: 'assert($("label > input[type="radio"]").filter("[name="indoor-outdoor"]").length > 1, "Give your radio buttons the name attribute of indoor-outdoor.");' +- text: Each of your two radio button elements should be nested in its own label element. + testString: 'assert($("label > input[type="radio"]:only-child").length > 1, "Each of your two radio button elements should be nested in its own label element.");' +- text: Make sure each of your label elements has a closing tag. + testString: 'assert((code.match(/<\/label>/g) && code.match(/
+ +## Challenge Seed +
+ +
+ +```html +

CatPhotoApp

+
+

Click here to view more cat photos.

+ + A cute orange cat lying on its back. + +

Things cats love:

+
    +
  • cat nip
  • +
  • laser pointers
  • +
  • lasagna
  • +
+

Top 3 things cats hate:

+
    +
  1. flea treatment
  2. +
  3. thunder
  4. +
  5. other cats
  6. +
+
+ + +
+
+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/basic-html-and-html5/Create a Text Field.md b/curriculum/challenges/01-responsive-web-design/basic-html-and-html5/Create a Text Field.md new file mode 100644 index 0000000000..23a18494eb --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/basic-html-and-html5/Create a Text Field.md @@ -0,0 +1,74 @@ +--- +id: bad87fee1348bd9aedf08829 +title: Create a Text Field +challengeType: 0 +videoUrl: 'https://scrimba.com/p/pVMPUv/c2EVnf6' +--- + +## Description +
+Now let's create a web form. +Input elements are a convenient way to get input from your user. +You can create a text input like this: +<input type="text"> +Note that input elements are self-closing. +
+ +## Instructions +
+Create an input element of type text below your lists. +
+ +## Tests +
+ +```yml +- text: Your app should have an input element of type text. + testString: 'assert($("input[type=text]").length > 0, "Your app should have an input element of type text.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html +

CatPhotoApp

+
+

Click here to view more cat photos.

+ + A cute orange cat lying on its back. + +

Things cats love:

+
    +
  • cat nip
  • +
  • laser pointers
  • +
  • lasagna
  • +
+

Top 3 things cats hate:

+
    +
  1. flea treatment
  2. +
  3. thunder
  4. +
  5. other cats
  6. +
+ + +
+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/basic-html-and-html5/Create an Ordered List.md b/curriculum/challenges/01-responsive-web-design/basic-html-and-html5/Create an Ordered List.md new file mode 100644 index 0000000000..dda1c9a982 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/basic-html-and-html5/Create an Ordered List.md @@ -0,0 +1,84 @@ +--- +id: bad87fee1348bd9aedf08828 +title: Create an Ordered List +challengeType: 0 +videoUrl: 'https://scrimba.com/p/pVMPUv/cQ3B8TM' +--- + +## Description +
+HTML has another special element for creating ordered lists, or numbered lists. +Ordered lists start with an opening <ol> element, followed by any number of <li> elements. Finally, ordered lists close with a </ol> +For example: +
<ol>
  <li>Garfield</li>
  <li>Sylvester</li>
</ol>
+would create a numbered list of "Garfield" and "Sylvester". +
+ +## Instructions +
+Create an ordered list of the top 3 things cats hate the most. +
+ +## Tests +
+ +```yml +- text: 'You should have an ordered list for "Top 3 things cats hate:"' + testString: 'assert((/Top 3 things cats hate:/i).test($("ol").prev().text()), "You should have an ordered list for "Top 3 things cats hate:"");' +- text: 'You should have an unordered list for "Things cats love:"' + testString: 'assert((/Things cats love:/i).test($("ul").prev().text()), "You should have an unordered list for "Things cats love:"");' +- text: You should have only one ul element. + testString: 'assert.equal($("ul").length, 1, "You should have only one ul element.");' +- text: You should have only one ol element. + testString: 'assert.equal($("ol").length, 1, "You should have only one ol element.");' +- text: You should have three li elements within your ul element. + testString: 'assert.equal($("ul li").length, 3, "You should have three li elements within your ul element.");' +- text: You should have three li elements within your ol element. + testString: 'assert.equal($("ol li").length, 3, "You should have three li elements within your ol element.");' +- text: Make sure your ul element has a closing tag. + testString: 'assert(code.match(/<\/ul>/g) && code.match(/<\/ul>/g).length === code.match(/
+ +## Challenge Seed +
+ +
+ +```html +

CatPhotoApp

+
+

Click here to view more cat photos.

+ + A cute orange cat lying on its back. + +

Things cats love:

+
    +
  • cat nip
  • +
  • laser pointers
  • +
  • lasagna
  • +
+

Top 3 things cats hate:

+ +
+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/basic-html-and-html5/Declare the Doctype of an HTML Document.md b/curriculum/challenges/01-responsive-web-design/basic-html-and-html5/Declare the Doctype of an HTML Document.md new file mode 100644 index 0000000000..ae9cb95a73 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/basic-html-and-html5/Declare the Doctype of an HTML Document.md @@ -0,0 +1,60 @@ +--- +id: 587d78aa367417b2b2512aed +title: Declare the Doctype of an HTML Document +challengeType: 0 +videoUrl: 'https://scrimba.com/p/pVMPUv/cra98AJ' +--- + +## Description +
+The challenges so far have covered specific HTML elements and their uses. However, there are a few elements that give overall structure to your page, and should be included in every HTML document. +At the top of your document, you need to tell the browser which version of HTML your page is using. HTML is an evolving language, and is updated regularly. Most major browsers support the latest specification, which is HTML5. However, older web pages may use previous versions of the language. +You tell the browser this information by adding the <!DOCTYPE ...> tag on the first line, where the "..." part is the version of HTML. For HTML5, you use <!DOCTYPE html>. +The ! and uppercase DOCTYPE is important, especially for older browsers. The html is not case sensitive. +Next, the rest of your HTML code needs to be wrapped in html tags. The opening <html> goes directly below the <!DOCTYPE html> line, and the closing </html> goes at the end of the page. +Here's an example of the page structure: +
<!DOCTYPE html>
<html>
  <!-- Your HTML code goes here -->
</html>
+
+ +## Instructions +
+Add a DOCTYPE tag for HTML5 to the top of the blank HTML document in the code editor. Under it, add opening and closing html tags, which wrap around an h1 element. The heading can include any text. +
+ +## Tests +
+ +```yml +- text: Your code should include a <!DOCTYPE html> tag. + testString: 'assert(code.match(//gi), "Your code should include a <!DOCTYPE html> tag.");' +- text: There should be one html element. + testString: 'assert($("html").length == 1, "There should be one html element.");' +- text: The html tags should wrap around one h1 element. + testString: 'assert(code.match(/\s*?

\s*?.*?\s*?<\/h1>\s*?<\/html>/gi), "The html tags should wrap around one h1 element.");' + +``` + +

+ +## Challenge Seed +
+ +
+ +```html + +``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/basic-html-and-html5/Define the Head and Body of an HTML Document.md b/curriculum/challenges/01-responsive-web-design/basic-html-and-html5/Define the Head and Body of an HTML Document.md new file mode 100644 index 0000000000..020f9102c7 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/basic-html-and-html5/Define the Head and Body of an HTML Document.md @@ -0,0 +1,70 @@ +--- +id: 587d78aa367417b2b2512aec +title: Define the Head and Body of an HTML Document +challengeType: 0 +videoUrl: 'https://scrimba.com/p/pVMPUv/cra9bfP' +--- + +## Description +
+You can add another level of organization in your HTML document within the html tags with the head and body elements. Any markup with information about your page would go into the head tag. Then any markup with the content of the page (what displays for a user) would go into the body tag. +Metadata elements, such as link, meta, title, and style, typically go inside the head element. +Here's an example of a page's layout: +
<!DOCTYPE html>
<html>
  <head>
    <!-- metadata elements -->
  </head>
  <body>
    <!-- page contents -->
  </body>
</html>
+
+ +## Instructions +
+Edit the markup so there's a head and a body. The head element should only include the title, and the body element should only include the h1 and p. +
+ +## Tests +
+ +```yml +- text: There should be only one head element on the page. + testString: 'assert($("head").length == 1, "There should be only one head element on the page.");' +- text: There should be only one body element on the page. + testString: 'assert($("body").length == 1, "There should be only one body element on the page.");' +- text: The head element should be a child of the html element. + testString: 'assert($("html").children("head").length == 1, "The head element should be a child of the html element.");' +- text: The body element should be a child of the html element. + testString: 'assert($("html").children("body").length == 1, "The body element should be a child of the html element.");' +- text: The head element should wrap around the title element. + testString: 'assert(code.match(/\s*?\s*?.*?\s*?<\/title>\s*?<\/head>/gi), "The <code>head</code> element should wrap around the <code>title</code> element.");' +- text: The <code>body</code> element should wrap around both the <code>h1</code> and <code>p</code> elements. + testString: 'assert($("body").children("h1").length == 1 && $("body").children("p").length == 1, "The <code>body</code> element should wrap around both the <code>h1</code> and <code>p</code> elements.");' + +``` + +</section> + +## Challenge Seed +<section id='challengeSeed'> + +<div id='html-seed'> + +```html +<!DOCTYPE html> +<html> + <title>The best page ever + +

The best page ever

+

Cat ipsum dolor sit amet, jump launch to pounce upon little yarn mouse, bare fangs at toy run hide in litter box until treats are fed. Go into a room to decide you didn't want to be in there anyway. I like big cats and i can not lie kitty ipsum dolor sit amet, shed everywhere shed everywhere stretching attack your ankles chase the red dot, hairball run catnip eat the grass sniff. Meow i could pee on this if i had the energy for slap owner's face at 5am until human fills food dish yet scamper. Knock dish off table head butt cant eat out of my own dish scratch the furniture. Make meme, make cute face. Sleep in the bathroom sink chase laser but pee in the shoe. Paw at your fat belly licks your face and eat grass, throw it back up kitty ipsum dolor sit amet, shed everywhere shed everywhere stretching attack your ankles chase the red dot, hairball run catnip eat the grass sniff.

+ + +``` + + + + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/basic-html-and-html5/Delete HTML Elements.md b/curriculum/challenges/01-responsive-web-design/basic-html-and-html5/Delete HTML Elements.md new file mode 100644 index 0000000000..756e5802b3 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/basic-html-and-html5/Delete HTML Elements.md @@ -0,0 +1,61 @@ +--- +id: bad87fed1348bd9aedf08833 +title: Delete HTML Elements +challengeType: 0 +videoUrl: 'https://scrimba.com/p/pVMPUv/ckK73C9' +--- + +## Description +
+Our phone doesn't have much vertical space. +Let's remove the unnecessary elements so we can start building our CatPhotoApp. +
+ +## Instructions +
+Delete your h1 element so we can simplify our view. +
+ +## Tests +
+ +```yml +- text: Delete your h1 element. + testString: 'assert(!code.match(/

/gi) && !code.match(/<\/h1>/gi), "Delete your h1 element.");' +- text: Leave your h2 element on the page. + testString: 'assert(code.match(/

[\w\W]*<\/h2>/gi), "Leave your h2 element on the page.");' +- text: Leave your p element on the page. + testString: 'assert(code.match(/

[\w\W]*<\/p>/gi), "Leave your p element on the page.");' + +``` + +

+ +## Challenge Seed +
+ +
+ +```html +

Hello World

+ +

CatPhotoApp

+ +

Kitty ipsum dolor sit amet, shed everywhere shed everywhere stretching attack your ankles chase the red dot, hairball run catnip eat the grass sniff.

+``` + +
+ + + +
+ +## Solution +
+ + +```js +var code = "

CatPhotoApp

Kitty ipsum dolor sit amet, shed everywhere shed everywhere stretching attack your ankles chase the red dot, hairball run catnip eat the grass sniff.

" +``` + +
diff --git a/curriculum/challenges/01-responsive-web-design/basic-html-and-html5/Fill in the Blank with Placeholder Text.md b/curriculum/challenges/01-responsive-web-design/basic-html-and-html5/Fill in the Blank with Placeholder Text.md new file mode 100644 index 0000000000..6520fa8e4b --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/basic-html-and-html5/Fill in the Blank with Placeholder Text.md @@ -0,0 +1,56 @@ +--- +id: bad87fee1348bd9aedf08833 +title: Fill in the Blank with Placeholder Text +challengeType: 0 +videoUrl: 'https://scrimba.com/p/pVMPUv/cgR7Dc7' +--- + +## Description +
+Web developers traditionally use lorem ipsum text as placeholder text. The 'lorem ipsum' text is randomly scraped from a famous passage by Cicero of Ancient Rome. +Lorem ipsum text has been used as placeholder text by typesetters since the 16th century, and this tradition continues on the web. +Well, 5 centuries is long enough. Since we're building a CatPhotoApp, let's use something called kitty ipsum text. +
+ +## Instructions +
+Replace the text inside your p element with the first few words of this kitty ipsum text: Kitty ipsum dolor sit amet, shed everywhere shed everywhere stretching attack your ankles chase the red dot, hairball run catnip eat the grass sniff. +
+ +## Tests +
+ +```yml +- text: Your p element should contain the first few words of the provided kitty ipsum text. + testString: 'assert.isTrue((/Kitty(\s)+ipsum/gi).test($("p").text()), "Your p element should contain the first few words of the provided kitty ipsum text.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html +

Hello World

+ +

CatPhotoApp

+ +

Hello Paragraph

+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/basic-html-and-html5/Headline with the h2 Element.md b/curriculum/challenges/01-responsive-web-design/basic-html-and-html5/Headline with the h2 Element.md new file mode 100644 index 0000000000..d05c447473 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/basic-html-and-html5/Headline with the h2 Element.md @@ -0,0 +1,58 @@ +--- +id: bad87fee1348bd9aedf0887a +title: Headline with the h2 Element +challengeType: 0 +videoUrl: 'https://scrimba.com/p/pVMPUv/cE8Gqf3' +--- + +## Description +
+Over the next few lessons, we'll build an HTML5 cat photo web app piece-by-piece. +The h2 element you will be adding in this step will add a level two heading to the web page. +This element tells the browser about the structure of your website. h1 elements are often used for main headings, while h2 elements are generally used for subheadings. There are also h3, h4, h5 and h6 elements to indicate different levels of subheadings. +
+ +## Instructions +
+Add an h2 tag that says "CatPhotoApp" to create a second HTML element below your "Hello World" h1 element. +
+ +## Tests +
+ +```yml +- text: Create an h2 element. + testString: 'assert(($("h2").length > 0), "Create an h2 element.");' +- text: Make sure your h2 element has a closing tag. + testString: 'assert(code.match(/<\/h2>/g) && code.match(/<\/h2>/g).length === code.match(/

/g).length, "Make sure your h2 element has a closing tag.");' +- text: Your h2 element should have the text "CatPhotoApp". + testString: 'assert.isTrue((/cat(\s)?photo(\s)?app/gi).test($("h2").text()), "Your h2 element should have the text "CatPhotoApp".");' +- text: Your h1 element should have the text "Hello World". + testString: 'assert.isTrue((/hello(\s)+world/gi).test($("h1").text()), "Your h1 element should have the text "Hello World".");' + +``` + +

+ +## Challenge Seed +
+ +
+ +```html +

Hello World

+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/basic-html-and-html5/Inform with the Paragraph Element.md b/curriculum/challenges/01-responsive-web-design/basic-html-and-html5/Inform with the Paragraph Element.md new file mode 100644 index 0000000000..b142131e28 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/basic-html-and-html5/Inform with the Paragraph Element.md @@ -0,0 +1,57 @@ +--- +id: bad87fee1348bd9aedf08801 +title: Inform with the Paragraph Element +challengeType: 0 +videoUrl: 'https://scrimba.com/p/pVMPUv/ceZ7DtN' +--- + +## Description +
+p elements are the preferred element for paragraph text on websites. p is short for "paragraph". +You can create a paragraph element like this: +<p>I'm a p tag!</p> +
+ +## Instructions +
+Create a p element below your h2 element, and give it the text "Hello Paragraph". +
+ +## Tests +
+ +```yml +- text: Create a p element. + testString: 'assert(($("p").length > 0), "Create a p element.");' +- text: Your p element should have the text "Hello Paragraph". + testString: 'assert.isTrue((/hello(\s)+paragraph/gi).test($("p").text()), "Your p element should have the text "Hello Paragraph".");' +- text: Make sure your p element has a closing tag. + testString: 'assert(code.match(/<\/p>/g) && code.match(/<\/p>/g).length === code.match(/

p element has a closing tag.");' + +``` + +

+ +## Challenge Seed +
+ +
+ +```html +

Hello World

+

CatPhotoApp

+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/basic-html-and-html5/Introduction to HTML5 Elements.md b/curriculum/challenges/01-responsive-web-design/basic-html-and-html5/Introduction to HTML5 Elements.md new file mode 100644 index 0000000000..98d6791f2d --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/basic-html-and-html5/Introduction to HTML5 Elements.md @@ -0,0 +1,68 @@ +--- +id: bad87fee1348bd9aecf08801 +title: Introduction to HTML5 Elements +challengeType: 0 +videoUrl: 'https://scrimba.com/p/pVMPUv/c4Ep9Am' +--- + +## Description +
+HTML5 introduces more descriptive HTML tags. These include header, footer, nav, video, article, section and others. +These tags make your HTML easier to read, and also help with Search Engine Optimization (SEO) and accessibility. +The main HTML5 tag helps search engines and other developers find the main content of your page. +Note
Many of the new HTML5 tags and their benefits are covered in the Applied Accessibility section. +
+ +## Instructions +
+Create a second p element after the existing p element with the following kitty ipsum text: Purr jump eat the grass rip the couch scratched sunbathe, shed everywhere rip the couch sleep in the sink fluffy fur catnip scratched. +Wrap the paragraphs with an opening and closing main tag. +
+ +## Tests +
+ +```yml +- text: You need 2 p elements with Kitty Ipsum text. + testString: 'assert($("p").length > 1, "You need 2 p elements with Kitty Ipsum text.");' +- text: Make sure each of your p elements has a closing tag. + testString: 'assert(code.match(/<\/p>/g) && code.match(/<\/p>/g).length === code.match(/

p elements has a closing tag.");' +- text: Your p element should contain the first few words of the provided additional kitty ipsum text. + testString: 'assert.isTrue((/Purr\s+jump\s+eat/gi).test($("p").text()), "Your p element should contain the first few words of the provided additional kitty ipsum text.");' +- text: Your code should have one main element. + testString: 'assert($("main").length === 1, "Your code should have one main element.");' +- text: The main element should have two paragraph elements as children. + testString: 'assert($("main").children("p").length === 2, "The main element should have two paragraph elements as children.");' +- text: The opening main tag should come before the first paragraph tag. + testString: 'assert(code.match(/

\s*?

/g), "The opening main tag should come before the first paragraph tag.");' +- text: The closing main tag should come after the second closing paragraph tag. + testString: 'assert(code.match(/<\/p>\s*?<\/main>/g), "The closing main tag should come after the second closing paragraph tag.");' + +``` + +

+ +## Challenge Seed +
+ +
+ +```html +

CatPhotoApp

+ +

Kitty ipsum dolor sit amet, shed everywhere shed everywhere stretching attack your ankles chase the red dot, hairball run catnip eat the grass sniff.

+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/basic-html-and-html5/Link to External Pages with Anchor Elements.md b/curriculum/challenges/01-responsive-web-design/basic-html-and-html5/Link to External Pages with Anchor Elements.md new file mode 100644 index 0000000000..463d0feaa3 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/basic-html-and-html5/Link to External Pages with Anchor Elements.md @@ -0,0 +1,66 @@ +--- +id: bad87fee1348bd9aedf08816 +title: Link to External Pages with Anchor Elements +challengeType: 0 +videoUrl: 'https://scrimba.com/p/pVMPUv/c8EkncB' +--- + +## Description +
+You can use anchor elements to link to content outside of your web page. +anchor elements need a destination web address called an href attribute. They also need anchor text. Here's an example: +<a href="https://freecodecamp.org">this links to freecodecamp.org</a> +Then your browser will display the text "this links to freecodecamp.org" as a link you can click. And that link will take you to the web address https://www.freecodecamp.org. +
+ +## Instructions +
+Create an a element that links to http://freecatphotoapp.com and has "cat photos" as its anchor text. +
+ +## Tests +
+ +```yml +- text: Your a element should have the anchor text of "cat photos". + testString: 'assert((/cat photos/gi).test($("a").text()), "Your a element should have the anchor text of "cat photos".");' +- text: 'You need an a element that links to http://freecatphotoapp.com' + testString: 'assert(/http:\/\/(www\.)?freecatphotoapp\.com/gi.test($("a").attr("href")), "You need an a element that links to http://freecatphotoapp.com");' +- text: Make sure your a element has a closing tag. + testString: 'assert(code.match(/<\/a>/g) && code.match(/<\/a>/g).length === code.match(/a element has a closing tag.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html +

CatPhotoApp

+
+ + + + A cute orange cat lying on its back. + +

Kitty ipsum dolor sit amet, shed everywhere shed everywhere stretching attack your ankles chase the red dot, hairball run catnip eat the grass sniff.

+

Purr jump eat the grass rip the couch scratched sunbathe, shed everywhere rip the couch sleep in the sink fluffy fur catnip scratched.

+
+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/basic-html-and-html5/Link to Internal Sections of a Page with Anchor Elements.md b/curriculum/challenges/01-responsive-web-design/basic-html-and-html5/Link to Internal Sections of a Page with Anchor Elements.md new file mode 100644 index 0000000000..5420e7b444 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/basic-html-and-html5/Link to Internal Sections of a Page with Anchor Elements.md @@ -0,0 +1,80 @@ +--- +id: bad88fee1348bd9aedf08816 +title: Link to Internal Sections of a Page with Anchor Elements +challengeType: 0 +videoUrl: 'https://scrimba.com/p/pVMPUv/cyrDRUL' +--- + +## Description +
+Anchor elements can also be used to create internal links to jump to different sections within a webpage. +To create an internal link, you assign a link's href attribute to a hash symbol # plus the value of the id attribute for the element that you want to internally link to, usually further down the page. You then need to add the same id attribute to the element you are linking to. An id is an attribute that uniquely describes an element. +Below is an example of an internal anchor link and its target element: +
<a href="#contacts-header">Contacts</a>
...
<h2 id="contacts-header">Contacts</h2>
+When users click the Contacts link, they'll be taken to the section of the webpage with the Contacts header element. +
+ +## Instructions +
+Change your external link to an internal link by changing the href attribute to "#footer" and the text from "cat photos" to "Jump to Bottom". +Remove the target="_blank" attribute from the anchor tag since this causes the linked document to open in a new window tab. +Then add an id attribute with a value of "footer" to the <footer> element at the bottom of the page. +
+ +## Tests +
+ +```yml +- text: There should be only one anchor tag on your page. + testString: 'assert($("a").length == 1, "There should be only one anchor tag on your page.");' +- text: There should be only one footer tag on your page. + testString: 'assert($("footer").length == 1, "There should be only one footer tag on your page.");' +- text: 'The a tag should have an href attribute set to "#footer".' + testString: 'assert($("a").eq(0).attr("href") == "#footer", "The a tag should have an href attribute set to "#footer".");' +- text: The a tag should not have a target attribute + testString: 'assert(typeof $("a").eq(0).attr("target") == typeof undefined || $("a").eq(0).attr("target") == true, "The a tag should not have a target attribute");' +- text: The a text should be "Jump to Bottom". + testString: 'assert($("a").eq(0).text().match(/Jump to Bottom/gi), "The a text should be "Jump to Bottom".");' +- text: The footer tag should have an id attribute set to "footer". + testString: 'assert($("footer").eq(0).attr("id") == "footer", "The footer tag should have an id attribute set to "footer".");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html +

CatPhotoApp

+
+ + cat photos + + A cute orange cat lying on its back. + +

Kitty ipsum dolor sit amet, shed everywhere shed everywhere stretching attack your ankles chase the red dot, hairball run catnip eat the grass sniff. Purr jump eat the grass rip the couch scratched sunbathe, shed everywhere rip the couch sleep in the sink fluffy fur catnip scratched. Kitty ipsum dolor sit amet, shed everywhere shed everywhere stretching attack your ankles chase the red dot, hairball run catnip eat the grass sniff.

+

Purr jump eat the grass rip the couch scratched sunbathe, shed everywhere rip the couch sleep in the sink fluffy fur catnip scratched. Kitty ipsum dolor sit amet, shed everywhere shed everywhere stretching attack your ankles chase the red dot, hairball run catnip eat the grass sniff. Purr jump eat the grass rip the couch scratched sunbathe, shed everywhere rip the couch sleep in the sink fluffy fur catnip scratched.

+

Meowwww loved it, hated it, loved it, hated it yet spill litter box, scratch at owner, destroy all furniture, especially couch or lay on arms while you're using the keyboard. Missing until dinner time toy mouse squeak roll over. With tail in the air lounge in doorway. Man running from cops stops to pet cats, goes to jail.

+

Intently stare at the same spot poop in the plant pot but kitten is playing with dead mouse. Get video posted to internet for chasing red dot leave fur on owners clothes meow to be let out and mesmerizing birds leave fur on owners clothes or favor packaging over toy so purr for no reason. Meow to be let out play time intently sniff hand run outside as soon as door open yet destroy couch.

+ +
+ + +``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/basic-html-and-html5/Make Dead Links Using the Hash Symbol.md b/curriculum/challenges/01-responsive-web-design/basic-html-and-html5/Make Dead Links Using the Hash Symbol.md new file mode 100644 index 0000000000..ac7094bff5 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/basic-html-and-html5/Make Dead Links Using the Hash Symbol.md @@ -0,0 +1,60 @@ +--- +id: bad87fee1348bd9aedf08817 +title: Make Dead Links Using the Hash Symbol +challengeType: 0 +videoUrl: 'https://scrimba.com/p/pVMPUv/cMdkytL' +--- + +## Description +
+Sometimes you want to add a elements to your website before you know where they will link. +This is also handy when you're changing the behavior of a link using JavaScript, which we'll learn about later. +
+ +## Instructions +
+The current value of the href attribute is a link that points to "http://freecatphotoapp.com". Replace the href attribute value with a #, also known as a hash symbol, to create a dead link. +For example: href="#" +
+ +## Tests +
+ +```yml +- text: 'Your a element should be a dead link with the value of the href attribute set to "#".' + testString: 'assert($("a").attr("href") === "#", "Your a element should be a dead link with the value of the href attribute set to "#".");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html +

CatPhotoApp

+
+

Click here to view more cat photos.

+ + A cute orange cat lying on its back. + +

Kitty ipsum dolor sit amet, shed everywhere shed everywhere stretching attack your ankles chase the red dot, hairball run catnip eat the grass sniff.

+

Purr jump eat the grass rip the couch scratched sunbathe, shed everywhere rip the couch sleep in the sink fluffy fur catnip scratched.

+
+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/basic-html-and-html5/Nest Many Elements within a Single div Element.md b/curriculum/challenges/01-responsive-web-design/basic-html-and-html5/Nest Many Elements within a Single div Element.md new file mode 100644 index 0000000000..fe7fe243f5 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/basic-html-and-html5/Nest Many Elements within a Single div Element.md @@ -0,0 +1,87 @@ +--- +id: bad87fee1348bd9aede08835 +title: Nest Many Elements within a Single div Element +challengeType: 0 +videoUrl: 'https://scrimba.com/p/pVMPUv/cNW4kC3' +--- + +## Description +
+The div element, also known as a division element, is a general purpose container for other elements. +The div element is probably the most commonly used HTML element of all. +Just like any other non-self-closing element, you can open a div element with <div> and close it on another line with </div>. +
+ +## Instructions +
+Nest your "Things cats love" and "Things cats hate" lists all within a single div element. +Hint: Try putting your opening div tag above your "Things cats love" p element and your closing div tag after your closing ol tag so that both of your lists are within one div. +
+ +## Tests +
+ +```yml +- text: Nest your p elements inside your div element. + testString: 'assert($("div").children("p").length > 1, "Nest your p elements inside your div element.");' +- text: Nest your ul element inside your div element. + testString: 'assert($("div").children("ul").length > 0, "Nest your ul element inside your div element.");' +- text: Nest your ol element inside your div element. + testString: 'assert($("div").children("ol").length > 0, "Nest your ol element inside your div element.");' +- text: Make sure your div element has a closing tag. + testString: 'assert(code.match(/<\/div>/g) && code.match(/<\/div>/g).length === code.match(/
/g).length, "Make sure your div element has a closing tag.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html +

CatPhotoApp

+
+

Click here to view more cat photos.

+ + A cute orange cat lying on its back. + +

Things cats love:

+
    +
  • cat nip
  • +
  • laser pointers
  • +
  • lasagna
  • +
+

Top 3 things cats hate:

+
    +
  1. flea treatment
  2. +
  3. thunder
  4. +
  5. other cats
  6. +
+ +
+ +
+ + +
+ + +
+
+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/basic-html-and-html5/Nest an Anchor Element within a Paragraph.md b/curriculum/challenges/01-responsive-web-design/basic-html-and-html5/Nest an Anchor Element within a Paragraph.md new file mode 100644 index 0000000000..d90ce4ba02 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/basic-html-and-html5/Nest an Anchor Element within a Paragraph.md @@ -0,0 +1,81 @@ +--- +id: bad87fee1348bd9aede08817 +title: Nest an Anchor Element within a Paragraph +challengeType: 0 +videoUrl: 'https://scrimba.com/p/pVMPUv/cb6k8Cb' +--- + +## Description +
+You can nest links within other text elements. +
<p>
Here's a <a target="_blank" href="http://freecodecamp.org"> link to freecodecamp.org</a> for you to follow.
</p>
+Let's break down the example: +Normal text is wrapped in the p element:
<p> Here's a ... for you to follow. </p> +Next is the anchor element <a> (which requires a closing tag </a>):
<a> ... </a> +target is an anchor tag attribute that specifies where to open the link and the value "_blank" specifies to open the link in a new tab +href is an anchor tag attribute that contains the URL address of the link:
<a href="http://freecodecamp.org"> ... </a> +The text, "link to freecodecamp.org", within the anchor element called anchor text, will display a link to click:
<a href=" ... ">link to freecodecamp.org</a> +The final output of the example will look like this:

Here's a link to freecodecamp.org for you to follow.

+
+ +## Instructions +
+Now nest your existing a element within a new p element (just after the existing main element). The new paragraph should have text that says "View more cat photos", where "cat photos" is a link, and the rest of the text is plain text. +
+ +## Tests +
+ +```yml +- text: 'You need an a element that links to "http://freecatphotoapp.com".' + testString: 'assert(($("a[href=\"http://freecatphotoapp.com\"]").length > 0 || $("a[href=\"http://www.freecatphotoapp.com\"]").length > 0), "You need an a element that links to "http://freecatphotoapp.com".");' +- text: Your a element should have the anchor text of "cat photos" + testString: 'assert($("a").text().match(/cat\sphotos/gi), "Your a element should have the anchor text of "cat photos"");' +- text: Create a new p element around your a element. There should be at least 3 total p tags in your HTML code. + testString: 'assert($("p") && $("p").length > 2, "Create a new p element around your a element. There should be at least 3 total p tags in your HTML code.");' +- text: Your a element should be nested within your new p element. + testString: 'assert(($("a[href=\"http://freecatphotoapp.com\"]").parent().is("p") || $("a[href=\"http://www.freecatphotoapp.com\"]").parent().is("p")), "Your a element should be nested within your new p element.");' +- text: Your p element should have the text "View more " (with a space after it). + testString: 'assert(($("a[href=\"http://freecatphotoapp.com\"]").parent().text().match(/View\smore\s/gi) || $("a[href=\"http://www.freecatphotoapp.com\"]").parent().text().match(/View\smore\s/gi)), "Your p element should have the text "View more " (with a space after it).");' +- text: Your a element should not have the text "View more". + testString: 'assert(!$("a").text().match(/View\smore/gi), "Your a element should not have the text "View more".");' +- text: Make sure each of your p elements has a closing tag. + testString: 'assert(code.match(/<\/p>/g) && code.match(/

/g).length === code.match(/

p elements has a closing tag.");' +- text: Make sure each of your a elements has a closing tag. + testString: 'assert(code.match(/<\/a>/g) && code.match(//g).length === code.match(/a elements has a closing tag.");' + +``` + +

+ +## Challenge Seed +
+ +
+ +```html +

CatPhotoApp

+
+ + cat photos + + A cute orange cat lying on its back. + +

Kitty ipsum dolor sit amet, shed everywhere shed everywhere stretching attack your ankles chase the red dot, hairball run catnip eat the grass sniff.

+

Purr jump eat the grass rip the couch scratched sunbathe, shed everywhere rip the couch sleep in the sink fluffy fur catnip scratched.

+
+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/basic-html-and-html5/Say Hello to HTML Elements.md b/curriculum/challenges/01-responsive-web-design/basic-html-and-html5/Say Hello to HTML Elements.md new file mode 100644 index 0000000000..6c4ca7c15e --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/basic-html-and-html5/Say Hello to HTML Elements.md @@ -0,0 +1,59 @@ +--- +id: bd7123c8c441eddfaeb5bdef +title: Say Hello to HTML Elements +challengeType: 0 +videoUrl: 'https://scrimba.com/p/pVMPUv/cE8Gpt2' +--- + +## Description +
+Welcome to freeCodeCamp's HTML coding challenges. These will walk you through web development step-by-step. +First, you'll start by building a simple web page using HTML. You can edit code in your code editor, which is embedded into this web page. +Do you see the code in your code editor that says <h1>Hello</h1>? That's an HTML element. +Most HTML elements have an opening tag and a closing tag. +Opening tags look like this: +<h1> +Closing tags look like this: +</h1> +The only difference between opening and closing tags is the forward slash after the opening bracket of a closing tag. +Each challenge has tests you can run at any time by clicking the "Run tests" button. When you pass all tests, you'll be prompted to submit your solution and go to the next coding challenge. +
+ +## Instructions +
+To pass the test on this challenge, change your h1 element's text to say "Hello World". +
+ +## Tests +
+ +```yml +- text: Your h1 element should have the text "Hello World". + testString: 'assert.isTrue((/hello(\s)+world/gi).test($("h1").text()), "Your h1 element should have the text "Hello World".");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html +

Hello

+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/basic-html-and-html5/Turn an Image into a Link.md b/curriculum/challenges/01-responsive-web-design/basic-html-and-html5/Turn an Image into a Link.md new file mode 100644 index 0000000000..cdf33ca02d --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/basic-html-and-html5/Turn an Image into a Link.md @@ -0,0 +1,66 @@ +--- +id: bad87fee1348bd9aedf08820 +title: Turn an Image into a Link +challengeType: 0 +videoUrl: 'https://scrimba.com/p/pVMPUv/cRdBnUr' +--- + +## Description +
+You can make elements into links by nesting them within an a element. +Nest your image within an a element. Here's an example: +<a href="#"><img src="https://bit.ly/fcc-running-cats" alt="Three kittens running towards the camera."></a> +Remember to use # as your a element's href property in order to turn it into a dead link. +
+ +## Instructions +
+Place the existing image element within an anchor element. +Once you've done this, hover over your image with your cursor. Your cursor's normal pointer should become the link clicking pointer. The photo is now a link. +
+ +## Tests +
+ +```yml +- text: Nest the existing img element within an a element. + testString: 'assert($("a").children("img").length > 0, "Nest the existing img element within an a element.");' +- text: 'Your a element should be a dead link with a href attribute set to #.' + testString: 'assert(new RegExp("#").test($("a").children("img").parent().attr("href")), "Your a element should be a dead link with a href attribute set to #.");' +- text: Make sure each of your a elements has a closing tag. + testString: 'assert(code.match(/<\/a>/g) && code.match(//g).length === code.match(/a elements has a closing tag.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html +

CatPhotoApp

+
+

Click here to view more cat photos.

+ + A cute orange cat lying on its back. + +

Kitty ipsum dolor sit amet, shed everywhere shed everywhere stretching attack your ankles chase the red dot, hairball run catnip eat the grass sniff.

+

Purr jump eat the grass rip the couch scratched sunbathe, shed everywhere rip the couch sleep in the sink fluffy fur catnip scratched.

+
+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/basic-html-and-html5/Uncomment HTML.md b/curriculum/challenges/01-responsive-web-design/basic-html-and-html5/Uncomment HTML.md new file mode 100644 index 0000000000..5817efbd7f --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/basic-html-and-html5/Uncomment HTML.md @@ -0,0 +1,64 @@ +--- +id: bad87fee1348bd9aedf08802 +title: Uncomment HTML +challengeType: 0 +videoUrl: 'https://scrimba.com/p/pVMPUv/cBmG9T7' +--- + +## Description +
+Commenting is a way that you can leave comments for other developers within your code without affecting the resulting output that is displayed to the end user. +Commenting is also a convenient way to make code inactive without having to delete it entirely. +Comments in HTML starts with <!--, and ends with a --> +
+ +## Instructions +
+Uncomment your h1, h2 and p elements. +
+ +## Tests +
+ +```yml +- text: Make your h1 element visible on your page by uncommenting it. + testString: 'assert($("h1").length > 0, "Make your h1 element visible on your page by uncommenting it.");' +- text: Make your h2 element visible on your page by uncommenting it. + testString: 'assert($("h2").length > 0, "Make your h2 element visible on your page by uncommenting it.");' +- text: Make your p element visible on your page by uncommenting it. + testString: 'assert($("p").length > 0, "Make your p element visible on your page by uncommenting it.");' +- text: 'Be sure to delete all trailing comment tags, i.e. -->.' + testString: 'assert(!/[^fc]-->/gi.test(code.replace(/ * +``` + + + + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/basic-html-and-html5/Use HTML5 to Require a Field.md b/curriculum/challenges/01-responsive-web-design/basic-html-and-html5/Use HTML5 to Require a Field.md new file mode 100644 index 0000000000..efc229cef8 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/basic-html-and-html5/Use HTML5 to Require a Field.md @@ -0,0 +1,74 @@ +--- +id: bad87fee1348bd9aedc08830 +title: Use HTML5 to Require a Field +challengeType: 0 +videoUrl: 'https://scrimba.com/p/pVMPUv/cMd4EcQ' +--- + +## Description +
+You can require specific form fields so that your user will not be able to submit your form until he or she has filled them out. +For example, if you wanted to make a text input field required, you can just add the attribute required within your input element, like this: <input type="text" required> +
+ +## Instructions +
+Make your text input a required field, so that your user can't submit the form without completing this field. +Then try to submit the form without inputting any text. See how your HTML5 form notifies you that the field is required? +
+ +## Tests +
+ +```yml +- text: Your text input element should have the required attribute. + testString: 'assert($("input").prop("required"), "Your text input element should have the required attribute.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html +

CatPhotoApp

+
+

Click here to view more cat photos.

+ + A cute orange cat lying on its back. + +

Things cats love:

+
    +
  • cat nip
  • +
  • laser pointers
  • +
  • lasagna
  • +
+

Top 3 things cats hate:

+
    +
  1. flea treatment
  2. +
  3. thunder
  4. +
  5. other cats
  6. +
+
+ + +
+
+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/basic-html-and-html5/meta.json b/curriculum/challenges/01-responsive-web-design/basic-html-and-html5/meta.json new file mode 100644 index 0000000000..2ab22f5d11 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/basic-html-and-html5/meta.json @@ -0,0 +1,8 @@ +{ + "name": "Basic HTML and HTML5", + "dashedName": "basic-html-and-html5", + "order": 0, + "time": "5 hours", + "superBlock": "responsive-web-design", + "superOrder": 1 +} \ No newline at end of file diff --git a/curriculum/challenges/01-responsive-web-design/css-flexbox/Add Flex Superpowers to the Tweet Embed.md b/curriculum/challenges/01-responsive-web-design/css-flexbox/Add Flex Superpowers to the Tweet Embed.md new file mode 100644 index 0000000000..76eab0feb5 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/css-flexbox/Add Flex Superpowers to the Tweet Embed.md @@ -0,0 +1,151 @@ +--- +id: 587d78ab367417b2b2512af1 +title: Add Flex Superpowers to the Tweet Embed +challengeType: 0 +videoUrl: 'https://scrimba.com/p/pVaDAv/c9W7MhM' +--- + +## Description +
+To the right is the tweet embed that will be used as the practical example. Some of the elements would look better with a different layout. The last challenge demonstrated display: flex. Here you'll add it to several components in the tweet embed to start adjusting their positioning. +
+ +## Instructions +
+Add the CSS property display: flex to all of the following items - note that the selectors are already set up in the CSS: +header, the header's .profile-name, the header's .follow-btn, the header's h3 and h4, the footer, and the footer's .stats. +
+ +## Tests +
+ +```yml +- text: Your header should have a display property set to flex. + testString: 'assert($("header").css("display") == "flex", "Your header should have a display property set to flex.");' +- text: Your footer should have a display property set to flex. + testString: 'assert($("footer").css("display") == "flex", "Your footer should have a display property set to flex.");' +- text: Your h3 should have a display property set to flex. + testString: 'assert($("h3").css("display") == "flex", "Your h3 should have a display property set to flex.");' +- text: Your h4 should have a display property set to flex. + testString: 'assert($("h4").css("display") == "flex", "Your h4 should have a display property set to flex.");' +- text: Your .profile-name should have a display property set to flex. + testString: 'assert($(".profile-name").css("display") == "flex", "Your .profile-name should have a display property set to flex.");' +- text: Your .follow-btn should have a display property set to flex. + testString: 'assert($(".follow-btn").css("display") == "flex", "Your .follow-btn should have a display property set to flex.");' +- text: Your .stats should have a display property set to flex. + testString: 'assert($(".stats").css("display") == "flex", "Your .stats should have a display property set to flex.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + +
+ Quincy Larson's profile picture +
+

Quincy Larson

+

@ossia

+
+ +
+
+

I meet so many people who are in search of that one trick that will help them work smart. Even if you work smart, you still have to work hard.

+ 1:32 PM - 12 Jan 2018 +
+
+ +``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/css-flexbox/Align Elements Using the align-items Property.md b/curriculum/challenges/01-responsive-web-design/css-flexbox/Align Elements Using the align-items Property.md new file mode 100644 index 0000000000..9bef257151 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/css-flexbox/Align Elements Using the align-items Property.md @@ -0,0 +1,78 @@ +--- +id: 587d78ad367417b2b2512af8 +title: Align Elements Using the align-items Property +challengeType: 0 +videoUrl: 'https://scrimba.com/p/pVaDAv/c8aggtk' +--- + +## Description +
+The align-items property is similar to justify-content. Recall that the justify-content property aligned flex items along the main axis. For rows, the main axis is a horizontal line and for columns it is a vertical line. +Flex containers also have a cross axis which is the opposite of the main axis. For rows, the cross axis is vertical and for columns, the cross axis is horizontal. +CSS offers the align-items property to align flex items along the cross axis. For a row, it tells CSS how to push the items in the entire row up or down within the container. And for a column, how to push all the items left or right within the container. +The different values available for align-items include: + +
+ +## Instructions +
+An example helps show this property in action. Add the CSS property align-items to the #box-container element, and give it a value of center. +Bonus
Try the other options for the align-items property in the code editor to see their differences. But note that a value of center is the only one that will pass this challenge. +
+ +## Tests +
+ +```yml +- text: 'The #box-container element should have an align-items property set to a value of center.' + testString: 'assert($("#box-container").css("align-items") == "center", "The #box-container element should have an align-items property set to a value of center.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + + +
+

Hello

+

Goodbye

+
+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/css-flexbox/Align Elements Using the justify-content Property.md b/curriculum/challenges/01-responsive-web-design/css-flexbox/Align Elements Using the justify-content Property.md new file mode 100644 index 0000000000..56a9ca40eb --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/css-flexbox/Align Elements Using the justify-content Property.md @@ -0,0 +1,78 @@ +--- +id: 587d78ac367417b2b2512af6 +title: Align Elements Using the justify-content Property +challengeType: 0 +videoUrl: 'https://scrimba.com/p/pVaDAv/c43gnHm' +--- + +## Description +
+Sometimes the flex items within a flex container do not fill all the space in the container. It is common to want to tell CSS how to align and space out the flex items a certain way. Fortunately, the justify-content property has several options to do this. But first, there is some important terminology to understand before reviewing those options. +Here is a useful image showing a row to illustrate the concepts below. +Recall that setting a flex container as a row places the flex items side-by-side from left-to-right. A flex container set as a column places the flex items in a vertical stack from top-to-bottom. For each, the direction the flex items are arranged is called the main axis. For a row, this is a horizontal line that cuts through each item. And for a column, the main axis is a vertical line through the items. +There are several options for how to space the flex items along the line that is the main axis. One of the most commonly used is justify-content: center;, which aligns all the flex items to the center inside the flex container. Others options include: + +
+ +## Instructions +
+An example helps show this property in action. Add the CSS property justify-content to the #box-container element, and give it a value of center. +Bonus
Try the other options for the justify-content property in the code editor to see their differences. But note that a value of center is the only one that will pass this challenge. +
+ +## Tests +
+ +```yml +- text: 'The #box-container element should have a justify-content property set to a value of center.' + testString: 'assert($("#box-container").css("justify-content") == "center", "The #box-container element should have a justify-content property set to a value of center.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + + +
+
+
+
+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/css-flexbox/Apply the flex-direction Property to Create Rows in the Tweet Embed.md b/curriculum/challenges/01-responsive-web-design/css-flexbox/Apply the flex-direction Property to Create Rows in the Tweet Embed.md new file mode 100644 index 0000000000..88e174c64a --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/css-flexbox/Apply the flex-direction Property to Create Rows in the Tweet Embed.md @@ -0,0 +1,144 @@ +--- +id: 587d78ab367417b2b2512af3 +title: Apply the flex-direction Property to Create Rows in the Tweet Embed +challengeType: 0 +videoUrl: 'https://scrimba.com/p/pVaDAv/cJb8yuq' +--- + +## Description +
+The header and footer in the tweet embed example have child items that could be arranged as rows using the flex-direction property. This tells CSS to align the children horizontally. +
+ +## Instructions +
+Add the CSS property flex-direction to both the header and footer and set the value to row. +
+ +## Tests +
+ +```yml +- text: The header should have a flex-direction property set to row. + testString: 'assert(code.match(/header\s*?{[^}]*?flex-direction:\s*?row;/g), "The header should have a flex-direction property set to row.");' +- text: The footer should have a flex-direction property set to row. + testString: 'assert(code.match(/footer\s*?{[^}]*?flex-direction:\s*?row;/g), "The footer should have a flex-direction property set to row.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + +
+ Quincy Larson's profile picture +
+

Quincy Larson

+

@ossia

+
+ +
+
+

I meet so many people who are in search of that one trick that will help them work smart. Even if you work smart, you still have to work hard.

+ 1:32 PM - 12 Jan 2018 +
+
+ +``` + +
+ + + +
+ +## Solution +
+ + +```js +var code = "header {flex-direction: row;} footer {flex-direction: row;}" +``` + +
diff --git a/curriculum/challenges/01-responsive-web-design/css-flexbox/Apply the flex-direction Property to Create a Column in the Tweet Embed.md b/curriculum/challenges/01-responsive-web-design/css-flexbox/Apply the flex-direction Property to Create a Column in the Tweet Embed.md new file mode 100644 index 0000000000..ed011108a9 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/css-flexbox/Apply the flex-direction Property to Create a Column in the Tweet Embed.md @@ -0,0 +1,137 @@ +--- +id: 587d78ac367417b2b2512af5 +title: Apply the flex-direction Property to Create a Column in the Tweet Embed +challengeType: 0 +videoUrl: 'https://scrimba.com/p/pVaDAv/cnzdVC9' +--- + +## Description +
+The tweet embed header and footer used the flex-direction property earlier with a row value. Similarly, the items inside the .profile-name element would work well stacked as a column. +
+ +## Instructions +
+Add the CSS property flex-direction to the header's .profile-name element and set the value to column. +
+ +## Tests +
+ +```yml +- text: The .profile-name element should have a flex-direction property set to column. + testString: 'assert($(".profile-name").css("flex-direction") == "column", "The .profile-name element should have a flex-direction property set to column.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + +
+ Quincy Larson's profile picture +
+

Quincy Larson

+

@ossia

+
+ +
+
+

I meet so many people who are in search of that one trick that will help them work smart. Even if you work smart, you still have to work hard.

+ 1:32 PM - 12 Jan 2018 +
+
+ +``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/css-flexbox/Use display: flex to Position Two Boxes.md b/curriculum/challenges/01-responsive-web-design/css-flexbox/Use display: flex to Position Two Boxes.md new file mode 100644 index 0000000000..8d203260c5 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/css-flexbox/Use display: flex to Position Two Boxes.md @@ -0,0 +1,74 @@ +--- +id: 587d78ab367417b2b2512af0 +title: 'Use display: flex to Position Two Boxes' +challengeType: 0 +videoUrl: 'https://scrimba.com/p/pVaDAv/cgz3QS7' +--- + +## Description +
+This section uses alternating challenge styles to show how to use CSS to position elements in a flexible way. First, a challenge will explain theory, then a practical challenge using a simple tweet component will apply the flexbox concept. +Placing the CSS property display: flex; on an element allows you to use other flex properties to build a responsive page. +
+ +## Instructions +
+Add the CSS property display to #box-container and set its value to flex. +
+ +## Tests +
+ +```yml +- text: '#box-container should have the display property set to a value of flex.' + testString: 'assert($("#box-container").css("display") == "flex", "#box-container should have the display property set to a value of flex.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + +
+
+
+
+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/css-flexbox/Use the align-items Property in the Tweet Embed.md b/curriculum/challenges/01-responsive-web-design/css-flexbox/Use the align-items Property in the Tweet Embed.md new file mode 100644 index 0000000000..27630cc811 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/css-flexbox/Use the align-items Property in the Tweet Embed.md @@ -0,0 +1,140 @@ +--- +id: 587d78ad367417b2b2512af9 +title: Use the align-items Property in the Tweet Embed +challengeType: 0 +videoUrl: 'https://scrimba.com/p/pVaDAv/cd3PNfq' +--- + +## Description +
+The last challenge introduced the align-items property and gave an example. This property can be applied to a few tweet embed elements to align the flex items inside them. +
+ +## Instructions +
+Add the CSS property align-items to the header's .follow-btn element. Set the value to center. +
+ +## Tests +
+ +```yml +- text: The .follow-btn element should have the align-items property set to a value of center. + testString: 'assert($(".follow-btn").css("align-items") == "center", "The .follow-btn element should have the align-items property set to a value of center.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + +
+ Quincy Larson's profile picture +
+

Quincy Larson

+

@ossia

+
+ +
+
+

I meet so many people who are in search of that one trick that will help them work smart. Even if you work smart, you still have to work hard.

+ 1:32 PM - 12 Jan 2018 +
+
+ +``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/css-flexbox/Use the align-self Property.md b/curriculum/challenges/01-responsive-web-design/css-flexbox/Use the align-self Property.md new file mode 100644 index 0000000000..350ac1cf51 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/css-flexbox/Use the align-self Property.md @@ -0,0 +1,76 @@ +--- +id: 587d78af367417b2b2512b00 +title: Use the align-self Property +challengeType: 0 +videoUrl: 'https://scrimba.com/p/pVaDAv/cMbvzfv' +--- + +## Description +
+The final property for flex items is align-self. This property allows you to adjust each item's alignment individually, instead of setting them all at once. This is useful since other common adjustment techniques using the CSS properties float, clear, and vertical-align do not work on flex items. +align-self accepts the same values as align-items and will override any value set by the align-items property. +
+ +## Instructions +
+Add the CSS property align-self to both #box-1 and #box-2. Give #box-1 a value of center and give #box-2 a value of flex-end. +
+ +## Tests +
+ +```yml +- text: 'The #box-1 element should have the align-self property set to a value of center.' + testString: 'assert($("#box-1").css("align-self") == "center", "The #box-1 element should have the align-self property set to a value of center.");' +- text: 'The #box-2 element should have the align-self property set to a value of flex-end.' + testString: 'assert($("#box-2").css("align-self") == "flex-end", "The #box-2 element should have the align-self property set to a value of flex-end.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + + +
+
+
+
+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/css-flexbox/Use the flex Shorthand Property.md b/curriculum/challenges/01-responsive-web-design/css-flexbox/Use the flex Shorthand Property.md new file mode 100644 index 0000000000..455419911c --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/css-flexbox/Use the flex Shorthand Property.md @@ -0,0 +1,78 @@ +--- +id: 587d78ae367417b2b2512afe +title: Use the flex Shorthand Property +challengeType: 0 +videoUrl: 'https://scrimba.com/p/pVaDAv/cbpW2tE' +--- + +## Description +
+There is a shortcut available to set several flex properties at once. The flex-grow, flex-shrink, and flex-basis properties can all be set together by using the flex property. +For example, flex: 1 0 10px; will set the item to flex-grow: 1;, flex-shrink: 0;, and flex-basis: 10px;. +The default property settings are flex: 0 1 auto;. +
+ +## Instructions +
+Add the CSS property flex to both #box-1 and #box-2. Give #box-1 the values so its flex-grow is 2, its flex-shrink is 2, and its flex-basis is 150px. Give #box-2 the values so its flex-grow is 1, its flex-shrink is 1, and its flex-basis is 150px. +These values will cause #box-1 to grow to fill the extra space at twice the rate of #box-2 when the container is greater than 300px and shrink at twice the rate of #box-2 when the container is less than 300px. 300px is the combined size of the flex-basis values of the two boxes. +
+ +## Tests +
+ +```yml +- text: 'The #box-1 element should have the flex property set to a value of 2 2 150px.' + testString: 'assert($("#box-1").css("flex-grow") == "2" && $("#box-1").css("flex-shrink") == "2" && $("#box-1").css("flex-basis") == "150px", "The #box-1 element should have the flex property set to a value of 2 2 150px.");' +- text: 'The #box-2 element should have the flex property set to a value of 1 1 150px.' + testString: 'assert($("#box-2").css("flex-grow") == "1" && $("#box-2").css("flex-shrink") == "1" && $("#box-2").css("flex-basis") == "150px", "The #box-2 element should have the flex property set to a value of 1 1 150px.");' +- text: 'Your code should use the flex property for #box-1 and #box-2.' + testString: 'assert(code.match(/flex:\s*?\d\s+?\d\s+?150px;/g).length == 2, "Your code should use the flex property for #box-1 and #box-2.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + + +
+
+
+
+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/css-flexbox/Use the flex-basis Property to Set the Initial Size of an Item.md b/curriculum/challenges/01-responsive-web-design/css-flexbox/Use the flex-basis Property to Set the Initial Size of an Item.md new file mode 100644 index 0000000000..30dbd1457b --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/css-flexbox/Use the flex-basis Property to Set the Initial Size of an Item.md @@ -0,0 +1,79 @@ +--- +id: 587d78ae367417b2b2512afd +title: Use the flex-basis Property to Set the Initial Size of an Item +challengeType: 0 +videoUrl: 'https://scrimba.com/p/pVaDAv/c3d9nCa' +--- + +## Description +
+The flex-basis property specifies the initial size of the item before CSS makes adjustments with flex-shrink or flex-grow. +The units used by the flex-basis property are the same as other size properties (px, em, %, etc.). The value auto sizes items based on the content. +
+ +## Instructions +
+Set the initial size of the boxes using flex-basis. Add the CSS property flex-basis to both #box-1 and #box-2. Give #box-1 a value of 10em and #box-2 a value of 20em. +
+ +## Tests +
+ +```yml +- text: 'The #box-1 element should have a flex-basis property.' + testString: 'assert($("#box-1").css("flex-basis") != "auto", "The #box-1 element should have a flex-basis property.");' +- text: 'The #box-1 element should have a flex-basis value of 10em.' + testString: 'assert(code.match(/#box-1\s*?{\s*?.*?\s*?.*?\s*?flex-basis:\s*?10em;/g), "The #box-1 element should have a flex-basis value of 10em.");' +- text: 'The #box-2 element should have the flex-basis property.' + testString: 'assert($("#box-2").css("flex-basis") != "auto", "The #box-2 element should have the flex-basis property.");' +- text: 'The #box-2 element should have a flex-basis value of 20em.' + testString: 'assert(code.match(/#box-2\s*?{\s*?.*?\s*?.*?\s*?flex-basis:\s*?20em;/g), "The #box-2 element should have a flex-basis value of 20em.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + + +
+
+
+
+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/css-flexbox/Use the flex-direction Property to Make a Column.md b/curriculum/challenges/01-responsive-web-design/css-flexbox/Use the flex-direction Property to Make a Column.md new file mode 100644 index 0000000000..1ceeddf97d --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/css-flexbox/Use the flex-direction Property to Make a Column.md @@ -0,0 +1,72 @@ +--- +id: 587d78ac367417b2b2512af4 +title: Use the flex-direction Property to Make a Column +challengeType: 0 +videoUrl: 'https://scrimba.com/p/pVaDAv/cZmWeA4' +--- + +## Description +
+The last two challenges used the flex-direction property set to row. This property can also create a column by vertically stacking the children of a flex container. +
+ +## Instructions +
+Add the CSS property flex-direction to the #box-container element, and give it a value of column. +
+ +## Tests +
+ +```yml +- text: 'The #box-container element should have a flex-direction property set to column.' + testString: 'assert($("#box-container").css("flex-direction") == "column", "The #box-container element should have a flex-direction property set to column.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + + +
+
+
+
+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/css-flexbox/Use the flex-direction Property to Make a Row.md b/curriculum/challenges/01-responsive-web-design/css-flexbox/Use the flex-direction Property to Make a Row.md new file mode 100644 index 0000000000..def4666fde --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/css-flexbox/Use the flex-direction Property to Make a Row.md @@ -0,0 +1,74 @@ +--- +id: 587d78ab367417b2b2512af2 +title: Use the flex-direction Property to Make a Row +challengeType: 0 +videoUrl: 'https://scrimba.com/p/pVaDAv/cBEkbfJ' +--- + +## Description +
+Adding display: flex to an element turns it into a flex container. This makes it possible to align any children of that element into rows or columns. You do this by adding the flex-direction property to the parent item and setting it to row or column. Creating a row will align the children horizontally, and creating a column will align the children vertically. +Other options for flex-direction are row-reverse and column-reverse. +Note
The default value for the flex-direction property is row. +
+ +## Instructions +
+Add the CSS property flex-direction to the #box-container element, and give it a value of row-reverse. +
+ +## Tests +
+ +```yml +- text: 'The #box-container element should have a flex-direction property set to row-reverse.' + testString: 'assert($("#box-container").css("flex-direction") == "row-reverse", "The #box-container element should have a flex-direction property set to row-reverse.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + + +
+
+
+
+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/css-flexbox/Use the flex-grow Property to Expand Items.md b/curriculum/challenges/01-responsive-web-design/css-flexbox/Use the flex-grow Property to Expand Items.md new file mode 100644 index 0000000000..b3441dc582 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/css-flexbox/Use the flex-grow Property to Expand Items.md @@ -0,0 +1,75 @@ +--- +id: 587d78ae367417b2b2512afc +title: Use the flex-grow Property to Expand Items +challengeType: 0 +videoUrl: 'https://scrimba.com/p/pVaDAv/c2p78cg' +--- + +## Description +
+The opposite of flex-shrink is the flex-grow property. Recall that flex-shrink controls the size of the items when the container shrinks. The flex-grow property controls the size of items when the parent container expands. +Using a similar example from the last challenge, if one item has a flex-grow value of 1 and the other has a flex-grow value of 3, the one with the value of 3 will grow three times as much as the other. +
+ +## Instructions +
+Add the CSS property flex-grow to both #box-1 and #box-2. Give #box-1 a value of 1 and #box-2 a value of 2. +
+ +## Tests +
+ +```yml +- text: 'The #box-1 element should have the flex-grow property set to a value of 1.' + testString: 'assert($("#box-1").css("flex-grow") == "1", "The #box-1 element should have the flex-grow property set to a value of 1.");' +- text: 'The #box-2 element should have the flex-grow property set to a value of 2.' + testString: 'assert($("#box-2").css("flex-grow") == "2", "The #box-2 element should have the flex-grow property set to a value of 2.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + + +
+
+
+
+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/css-flexbox/Use the flex-shrink Property to Shrink Items.md b/curriculum/challenges/01-responsive-web-design/css-flexbox/Use the flex-shrink Property to Shrink Items.md new file mode 100644 index 0000000000..641c5d1b4b --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/css-flexbox/Use the flex-shrink Property to Shrink Items.md @@ -0,0 +1,77 @@ +--- +id: 587d78ad367417b2b2512afb +title: Use the flex-shrink Property to Shrink Items +challengeType: 0 +videoUrl: 'https://scrimba.com/p/pVaDAv/cd3PBfr' +--- + +## Description +
+So far, all the properties in the challenges apply to the flex container (the parent of the flex items). However, there are several useful properties for the flex items. +The first is the flex-shrink property. When it's used, it allows an item to shrink if the flex container is too small. Items shrink when the width of the parent container is smaller than the combined widths of all the flex items within it. +The flex-shrink property takes numbers as values. The higher the number, the more it will shrink compared to the other items in the container. For example, if one item has a flex-shrink value of 1 and the other has a flex-shrink value of 3, the one with the value of 3 will shrink three times as much as the other. +
+ +## Instructions +
+Add the CSS property flex-shrink to both #box-1 and #box-2. Give #box-1 a value of 1 and #box-2 a value of 2. +
+ +## Tests +
+ +```yml +- text: 'The #box-1 element should have the flex-shrink property set to a value of 1.' + testString: 'assert($("#box-1").css("flex-shrink") == "1", "The #box-1 element should have the flex-shrink property set to a value of 1.");' +- text: 'The #box-2 element should have the flex-shrink property set to a value of 2.' + testString: 'assert($("#box-2").css("flex-shrink") == "2", "The #box-2 element should have the flex-shrink property set to a value of 2.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + + +
+
+
+
+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/css-flexbox/Use the flex-wrap Property to Wrap a Row or Column.md b/curriculum/challenges/01-responsive-web-design/css-flexbox/Use the flex-wrap Property to Wrap a Row or Column.md new file mode 100644 index 0000000000..751d041bd4 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/css-flexbox/Use the flex-wrap Property to Wrap a Row or Column.md @@ -0,0 +1,100 @@ +--- +id: 587d78ad367417b2b2512afa +title: Use the flex-wrap Property to Wrap a Row or Column +challengeType: 0 +videoUrl: 'https://scrimba.com/p/pVaDAv/cQv9ZtG' +--- + +## Description +
+CSS flexbox has a feature to split a flex item into multiple rows (or columns). By default, a flex container will fit all flex items together. For example, a row will all be on one line. +However, using the flex-wrap property, it tells CSS to wrap items. This means extra items move into a new row or column. The break point of where the wrapping happens depends on the size of the items and the size of the container. +CSS also has options for the direction of the wrap: + +
+ +## Instructions +
+The current layout has too many boxes for one row. Add the CSS property flex-wrap to the #box-container element, and give it a value of wrap. +
+ +## Tests +
+ +```yml +- text: 'The #box-container element should have the flex-wrap property set to a value of wrap.' + testString: 'assert($("#box-container").css("flex-wrap") == "wrap", "The #box-container element should have the flex-wrap property set to a value of wrap.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + + +
+
+
+
+
+
+
+
+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/css-flexbox/Use the justify-content Property in the Tweet Embed.md b/curriculum/challenges/01-responsive-web-design/css-flexbox/Use the justify-content Property in the Tweet Embed.md new file mode 100644 index 0000000000..4b93bb7487 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/css-flexbox/Use the justify-content Property in the Tweet Embed.md @@ -0,0 +1,140 @@ +--- +id: 587d78ac367417b2b2512af7 +title: Use the justify-content Property in the Tweet Embed +challengeType: 0 +videoUrl: 'https://scrimba.com/p/pVaDAv/c43GgTa' +--- + +## Description +
+The last challenge showed an example of the justify-content property. For the tweet embed, this property can be applied to align the items in the .profile-name element. +
+ +## Instructions +
+Add the CSS property justify-content to the header's .profile-name element and set the value to any of the options from the last challenge. +
+ +## Tests +
+ +```yml +- text: 'The .profile-name element should have the justify-content property set to any of these values: center, flex-start, flex-end, space-between, or space-around.' + testString: 'assert(code.match(/header\s.profile-name\s*{\s*?.*?\s*?.*?\s*?\s*?.*?\s*?justify-content\s*:\s*(center|flex-start|flex-end|space-between|space-around)\s*;/g), "The .profile-name element should have the justify-content property set to any of these values: center, flex-start, flex-end, space-between, or space-around.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + +
+ Quincy Larson's profile picture +
+

Quincy Larson

+

@ossia

+
+ +
+
+

I meet so many people who are in search of that one trick that will help them work smart. Even if you work smart, you still have to work hard.

+ 1:32 PM - 12 Jan 2018 +
+
+ +``` + +
+ + + +
+ +## Solution +
+ + +```js +var code = "header .profile-name {display: flex; flex-direction: column; justify-content: center; margin-left: 10px;}" +``` + +
diff --git a/curriculum/challenges/01-responsive-web-design/css-flexbox/Use the order Property to Rearrange Items.md b/curriculum/challenges/01-responsive-web-design/css-flexbox/Use the order Property to Rearrange Items.md new file mode 100644 index 0000000000..7e1453ee8a --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/css-flexbox/Use the order Property to Rearrange Items.md @@ -0,0 +1,75 @@ +--- +id: 587d78ae367417b2b2512aff +title: Use the order Property to Rearrange Items +challengeType: 0 +videoUrl: 'https://scrimba.com/p/pVaDAv/cMbvNAG' +--- + +## Description +
+The order property is used to tell CSS the order of how flex items appear in the flex container. By default, items will appear in the same order they come in the source HTML. The property takes numbers as values, and negative numbers can be used. +
+ +## Instructions +
+Add the CSS property order to both #box-1 and #box-2. Give #box-1 a value of 2 and give #box-2 a value of 1. +
+ +## Tests +
+ +```yml +- text: 'The #box-1 element should have the order property set to a value of 2.' + testString: 'assert($("#box-1").css("order") == "2", "The #box-1 element should have the order property set to a value of 2.");' +- text: 'The #box-2 element should have the order property set to a value of 1.' + testString: 'assert($("#box-2").css("order") == "1", "The #box-2 element should have the order property set to a value of 1.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + + +
+
+
+
+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/css-flexbox/meta.json b/curriculum/challenges/01-responsive-web-design/css-flexbox/meta.json new file mode 100644 index 0000000000..92fd8d3bcb --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/css-flexbox/meta.json @@ -0,0 +1,8 @@ +{ + "name": "CSS Flexbox", + "dashedName": "css-flexbox", + "order": 5, + "time": "5 hours", + "superBlock": "responsive-web-design", + "superOrder": 1 +} \ No newline at end of file diff --git a/curriculum/challenges/01-responsive-web-design/css-grid/Add Columns with grid-template-columns.md b/curriculum/challenges/01-responsive-web-design/css-grid/Add Columns with grid-template-columns.md new file mode 100644 index 0000000000..ff800a87bc --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/css-grid/Add Columns with grid-template-columns.md @@ -0,0 +1,80 @@ +--- +id: 5a9036d038fddaf9a66b5d32 +title: Add Columns with grid-template-columns +challengeType: 0 +videoUrl: 'https://scrimba.com/p/pByETK/c7NzDHv' +--- + +## Description +
+Simply creating a grid element doesn't get you very far. You need to define the structure of the grid as well. To add some columns to the grid, use the grid-template-columns property on a grid container as demonstrated below: +
.container {
  display: grid;
  grid-template-columns: 50px 50px;
}
+This will give your grid two columns that are 50px wide each. +The number of parameters given to the grid-template-columns property indicates the number of columns in the grid, and the value of each parameter indicates the width of each column. +
+ +## Instructions +
+Give the grid container three columns that are 100px wide each. +
+ +## Tests +
+ +```yml +- text: container class should have a grid-template-columns property with three units of 100px. + testString: 'assert(code.match(/.container\s*?{[\s\S]*grid-template-columns\s*?:\s*?100px\s*?100px\s*?100px\s*?;[\s\S]*}/gi), "container class should have a grid-template-columns property with three units of 100px.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + + +
+
1
+
2
+
3
+
4
+
5
+
+``` + +
+ + + +
+ +## Solution +
+ + +```js +var code = ".container {grid-template-columns: 100px 100px 100px;}" +``` + +
diff --git a/curriculum/challenges/01-responsive-web-design/css-grid/Add Gaps Faster with grid-gap.md b/curriculum/challenges/01-responsive-web-design/css-grid/Add Gaps Faster with grid-gap.md new file mode 100644 index 0000000000..4d7a6960ad --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/css-grid/Add Gaps Faster with grid-gap.md @@ -0,0 +1,79 @@ +--- +id: 5a9036ee38fddaf9a66b5d37 +title: Add Gaps Faster with grid-gap +challengeType: 0 +videoUrl: 'https://scrimba.com/p/pByETK/ca2qVtv' +--- + +## Description +
+grid-gap is a shorthand property for grid-row-gap and grid-column-gap from the previous two challenges that's more convenient to use. If grid-gap has one value, it will create a gap between all rows and columns. However, if there are two values, it will use the first one to set the gap between the rows and the second value for the columns. +
+ +## Instructions +
+Use grid-gap to introduce a 10px gap between the rows and 20px gap between the columns. +
+ +## Tests +
+ +```yml +- text: container class should have a grid-gap property that introduces 10px gap between the rows and 20px gap between the columns. + testString: 'assert(code.match(/.container\s*?{[\s\S]*grid-gap\s*?:\s*?10px\s+?20px\s*?;[\s\S]*}/gi), "container class should have a grid-gap property that introduces 10px gap between the rows and 20px gap between the columns.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + +
+
1
+
2
+
3
+
4
+
5
+
+``` + +
+ + + +
+ +## Solution +
+ + +```js +var code = ".container {grid-gap: 10px 20px;}" +``` + +
diff --git a/curriculum/challenges/01-responsive-web-design/css-grid/Add Rows with grid-template-rows.md b/curriculum/challenges/01-responsive-web-design/css-grid/Add Rows with grid-template-rows.md new file mode 100644 index 0000000000..1331a2c0e4 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/css-grid/Add Rows with grid-template-rows.md @@ -0,0 +1,78 @@ +--- +id: 5a9036e138fddaf9a66b5d33 +title: Add Rows with grid-template-rows +challengeType: 0 +videoUrl: 'https://scrimba.com/p/pByETK/cbp9Pua' +--- + +## Description +
+The grid you created in the last challenge will set the number of rows automatically. To adjust the rows manually, use the grid-template-rows property in the same way you used grid-template-columns in previous challenge. +
+ +## Instructions +
+Add two rows to the grid that are 50px tall each. +
+ +## Tests +
+ +```yml +- text: container class should have a grid-template-rows property with two units of 50px. + testString: 'assert(code.match(/.container\s*?{[\s\S]*grid-template-rows\s*?:\s*?50px\s*?50px\s*?;[\s\S]*}/gi), "container class should have a grid-template-rows property with two units of 50px.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + + +
+
1
+
2
+
3
+
4
+
5
+
+``` + +
+ + + +
+ +## Solution +
+ + +```js +var code = ".container {grid-template-rows: 50px 50px;}" +``` + +
diff --git a/curriculum/challenges/01-responsive-web-design/css-grid/Align All Items Horizontally using justify-items.md b/curriculum/challenges/01-responsive-web-design/css-grid/Align All Items Horizontally using justify-items.md new file mode 100644 index 0000000000..c6192979ab --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/css-grid/Align All Items Horizontally using justify-items.md @@ -0,0 +1,81 @@ +--- +id: 5a90376038fddaf9a66b5d3c +title: Align All Items Horizontally using justify-items +challengeType: 0 +videoUrl: 'https://scrimba.com/p/pByETK/cJbpECn' +--- + +## Description +
+Sometimes you want all the items in your CSS Grid to share the same alignment. You can use the previously learned properties and align them individually, or you can align them all at once horizontally by using justify-items on your grid container. This property can accept all the same values you learned about in the previous two challenges, the difference being that it will move all the items in our grid to the desired alignment. +
+ +## Instructions +
+Use this property to center all our items horizontally. +
+ +## Tests +
+ +```yml +- text: container class should have a justify-items property that has the value of center. + testString: 'assert(code.match(/.container\s*?{[\s\S]*justify-items\s*?:\s*?center\s*?;[\s\S]*}/gi), "container class should have a justify-items property that has the value of center.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + + +
+
1
+
2
+
3
+
4
+
5
+
+``` + +
+ + + +
+ +## Solution +
+ + +```js +var code = ".container {justify-items: center;}" +``` + +
diff --git a/curriculum/challenges/01-responsive-web-design/css-grid/Align All Items Vertically using align-items.md b/curriculum/challenges/01-responsive-web-design/css-grid/Align All Items Vertically using align-items.md new file mode 100644 index 0000000000..dd3e5781e6 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/css-grid/Align All Items Vertically using align-items.md @@ -0,0 +1,81 @@ +--- +id: 5a94fdf869fb03452672e45b +title: Align All Items Vertically using align-items +challengeType: 0 +videoUrl: 'https://scrimba.com/p/pByETK/ckzPeUv' +--- + +## Description +
+Using the align-items property on a grid container will set the vertical alignment for all the items in our grid. +
+ +## Instructions +
+Use it now to move all the items to the end of each cell. +
+ +## Tests +
+ +```yml +- text: container class should have a align-items property that has the value of end. + testString: 'assert(code.match(/.container\s*?{[\s\S]*align-items\s*?:\s*?end\s*?;[\s\S]*}/gi), "container class should have a align-items property that has the value of end.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + + +
+
1
+
2
+
3
+
4
+
5
+
+``` + +
+ + + +
+ +## Solution +
+ + +```js +var code = ".container {align-items: end;}" +``` + +
diff --git a/curriculum/challenges/01-responsive-web-design/css-grid/Align an Item Horizontally using justify-self.md b/curriculum/challenges/01-responsive-web-design/css-grid/Align an Item Horizontally using justify-self.md new file mode 100644 index 0000000000..ca5c11b573 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/css-grid/Align an Item Horizontally using justify-self.md @@ -0,0 +1,88 @@ +--- +id: 5a90374338fddaf9a66b5d3a +title: Align an Item Horizontally using justify-self +challengeType: 0 +videoUrl: 'https://scrimba.com/p/pByETK/cJbpKHq' +--- + +## Description +
+In CSS Grid, the content of each item is located in a box which is referred to as a cell. You can align the content's position within its cell horizontally using the justify-self property on a grid item. By default, this property has a value of stretch, which will make the content fill the whole width of the cell. This CSS Grid property accepts other values as well: +start: aligns the content at the left of the cell, +center: aligns the content in the center of the cell, +end: aligns the content at the right of the cell. +
+ +## Instructions +
+Use the justify-self property to center the item with the class item2. +
+ +## Tests +
+ +```yml +- text: item2 class should have a justify-self property that has the value of center. + testString: 'assert(code.match(/.item2\s*?{[\s\S]*justify-self\s*?:\s*?center\s*?;[\s\S]*}/gi), "item2 class should have a justify-self property that has the value of center.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + + +
+
1
+
2
+
3
+
4
+
5
+
+``` + +
+ + + +
+ +## Solution +
+ + +```js +var code = ".item2 {justify-self: center;}" +``` + +
diff --git a/curriculum/challenges/01-responsive-web-design/css-grid/Align an Item Vertically using align-self.md b/curriculum/challenges/01-responsive-web-design/css-grid/Align an Item Vertically using align-self.md new file mode 100644 index 0000000000..a8245d3e43 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/css-grid/Align an Item Vertically using align-self.md @@ -0,0 +1,85 @@ +--- +id: 5a90375238fddaf9a66b5d3b +title: Align an Item Vertically using align-self +challengeType: 0 +videoUrl: 'https://scrimba.com/p/pByETK/cmzd4fz' +--- + +## Description +
+Just as you can align an item horizontally, there's a way to align an item vertically as well. To do this, you use the align-self property on an item. This property accepts all of the same values as justify-self from the last challenge. +
+ +## Instructions +
+Align the item with the class item3 vertically at the end. +
+ +## Tests +
+ +```yml +- text: item3 class should have a align-self property that has the value of end. + testString: 'assert(code.match(/.item3\s*?{[\s\S]*align-self\s*?:\s*?end\s*?;[\s\S]*}/gi), "item3 class should have a align-self property that has the value of end.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + + +
+
1
+
2
+
3
+
4
+
5
+
+``` + +
+ + + +
+ +## Solution +
+ + +```js +var code = ".item3 {align-self: end;}" +``` + +
diff --git a/curriculum/challenges/01-responsive-web-design/css-grid/Create Flexible Layouts Using auto-fill.md b/curriculum/challenges/01-responsive-web-design/css-grid/Create Flexible Layouts Using auto-fill.md new file mode 100644 index 0000000000..90ee0784c1 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/css-grid/Create Flexible Layouts Using auto-fill.md @@ -0,0 +1,102 @@ +--- +id: 5a94fe5469fb03452672e461 +title: Create Flexible Layouts Using auto-fill +challengeType: 0 +videoUrl: 'https://scrimba.com/p/pByETK/cmzdycW' +--- + +## Description +
+The repeat function comes with an option called auto-fill. This allows you to automatically insert as many rows or columns of your desired size as possible depending on the size of the container. You can create flexible layouts when combining auto-fill with minmax. +In the preview, grid-template-columns is set to +
repeat(auto-fill, minmax(60px, 1fr));
+When the container changes size, this setup keeps inserting 60px columns and stretching them until it can insert another one. +Note
If your container can't fit all your items on one row, it will move them down to a new one. +
+ +## Instructions +
+In the first grid, use auto-fill with repeat to fill the grid with columns that have a minimum width of 60px and maximum of 1fr. Then resize the preview to see auto-fill in action. +
+ +## Tests +
+ +```yml +- text: container class should have a grid-template-columns property with repeat and auto-fill that will fill the grid with columns that have a minimum width of 60px and maximum of 1fr. + testString: 'assert(code.match(/.container\s*?{[\s\S]*grid-template-columns\s*?:\s*?repeat\s*?\(\s*?auto-fill\s*?,\s*?minmax\s*?\(\s*?60px\s*?,\s*?1fr\s*?\)\s*?\)\s*?;[\s\S]*}/gi), "container class should have a grid-template-columns property with repeat and auto-fill that will fill the grid with columns that have a minimum width of 60px and maximum of 1fr.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + +
+
1
+
2
+
3
+
4
+
5
+
+
+
1
+
2
+
3
+
4
+
5
+
+``` + +
+ + + +
+ +## Solution +
+ + +```js +var code = ".container {grid-template-columns: repeat(auto-fill, minmax(60px, 1fr));}" +``` + +
diff --git a/curriculum/challenges/01-responsive-web-design/css-grid/Create Flexible Layouts Using auto-fit.md b/curriculum/challenges/01-responsive-web-design/css-grid/Create Flexible Layouts Using auto-fit.md new file mode 100644 index 0000000000..25d4b7b809 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/css-grid/Create Flexible Layouts Using auto-fit.md @@ -0,0 +1,100 @@ +--- +id: 5a94fe6269fb03452672e462 +title: Create Flexible Layouts Using auto-fit +challengeType: 0 +videoUrl: 'https://scrimba.com/p/pByETK/c3dPph8' +--- + +## Description +
+auto-fit works almost identically to auto-fill. The only difference is that when the container's size exceeds the size of all the items combined, auto-fill keeps inserting empty rows or columns and pushes your items to the side, while auto-fit collapses those empty rows or columns and stretches your items to fit the size of the container. +Note
If your container can't fit all your items on one row, it will move them down to a new one. +
+ +## Instructions +
+In the second grid, use auto-fit with repeat to fill the grid with columns that have a minimum width of 60px and maximum of 1fr. Then resize the preview to see the difference. +
+ +## Tests +
+ +```yml +- text: container2 class should have a grid-template-columns property with repeat and auto-fit that will fill the grid with columns that have a minimum width of 60px and maximum of 1fr. + testString: 'assert(code.match(/.container\s*?{[\s\S]*grid-template-columns\s*?:\s*?repeat\s*?\(\s*?auto-fit\s*?,\s*?minmax\s*?\(\s*?60px\s*?,\s*?1fr\s*?\)\s*?\)\s*?;[\s\S]*}/gi), "container2 class should have a grid-template-columns property with repeat and auto-fit that will fill the grid with columns that have a minimum width of 60px and maximum of 1fr.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + + +
+
1
+
2
+
3
+
4
+
5
+
+
+
1
+
2
+
3
+
4
+
5
+
+``` + +
+ + + +
+ +## Solution +
+ + +```js +var code = ".container {grid-template-columns: repeat( auto-fill, minmax(60px, 1fr));} .container2 {grid-template-columns: repeat(auto-fit, minmax(60px, 1fr));}" +``` + +
diff --git a/curriculum/challenges/01-responsive-web-design/css-grid/Create Grids within Grids.md b/curriculum/challenges/01-responsive-web-design/css-grid/Create Grids within Grids.md new file mode 100644 index 0000000000..223e69e925 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/css-grid/Create Grids within Grids.md @@ -0,0 +1,112 @@ +--- +id: 5a94fe8569fb03452672e464 +title: Create Grids within Grids +challengeType: 0 +videoUrl: 'https://scrimba.com/p/pByETK/c6N78Ap' +--- + +## Description +
+Turning an element into a grid only affects the behavior of its direct descendants. So by turning a direct descendant into a grid, you have a grid within a grid. +For example, by setting the display and grid-template-columns properties of the element with the item3 class, you create a grid within your grid. +
+ +## Instructions +
+Turn the element with the item3 class into a grid with two columns with a width of auto and 1fr using display and grid-template-columns. +
+ +## Tests +
+ +```yml +- text: item3 class should have a grid-template-columns property with auto and 1fr as values. + testString: 'assert(code.match(/.item3\s*?{[\s\S]*grid-template-columns\s*?:\s*?auto\s*?1fr\s*?;[\s\S]*}/gi), "item3 class should have a grid-template-columns property with auto and 1fr as values.");' +- text: item3 class should have a display property with the value of grid. + testString: 'assert(code.match(/.item3\s*?{[\s\S]*display\s*?:\s*?grid\s*?;[\s\S]*}/gi), "item3 class should have a display property with the value of grid.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + + +
+
header
+
advert
+
+
paragraph1
+
paragraph2
+
+
footer
+
+``` + +
+ + + +
+ +## Solution +
+ + +```js +var code = ".item3 {grid-template-columns: auto 1fr; display: grid;}" +``` + +
diff --git a/curriculum/challenges/01-responsive-web-design/css-grid/Create Your First CSS Grid.md b/curriculum/challenges/01-responsive-web-design/css-grid/Create Your First CSS Grid.md new file mode 100644 index 0000000000..6c6a1df285 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/css-grid/Create Your First CSS Grid.md @@ -0,0 +1,77 @@ +--- +id: 5a858944d96184f06fd60d61 +title: Create Your First CSS Grid +challengeType: 0 +videoUrl: 'https://scrimba.com/p/pByETK/cqwREC4' +--- + +## Description +
+Turn any HTML element into a grid container by setting its display property to grid. This gives you the ability to use all the other properties associated with CSS Grid. +Note
In CSS Grid, the parent element is referred to as the container and its children are called items. +
+ +## Instructions +
+Change the display of the div with the container class to grid. +
+ +## Tests +
+ +```yml +- text: container class should have a display property with a value of grid. + testString: 'assert(code.match(/.container\s*?{[\s\S]*display\s*?:\s*?grid\s*?;[\s\S]*}/gi), "container class should have a display property with a value of grid.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + + +
+
1
+
2
+
3
+
4
+
5
+
+``` + +
+ + + +
+ +## Solution +
+ + +```js +var code = ".container {display: grid;}" +``` + +
diff --git a/curriculum/challenges/01-responsive-web-design/css-grid/Create a Column Gap Using grid-column-gap.md b/curriculum/challenges/01-responsive-web-design/css-grid/Create a Column Gap Using grid-column-gap.md new file mode 100644 index 0000000000..2abe5b4e42 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/css-grid/Create a Column Gap Using grid-column-gap.md @@ -0,0 +1,82 @@ +--- +id: 5a9036ee38fddaf9a66b5d35 +title: Create a Column Gap Using grid-column-gap +challengeType: 0 +videoUrl: 'https://scrimba.com/p/pByETK/cVZ8vfD' +--- + +## Description +
+So far in the grids you have created, the columns have all been tight up against each other. Sometimes you want a gap in between the columns. To add a gap between the columns, use the grid-column-gap property like this: +
grid-column-gap: 10px;
+This creates 10px of empty space between all of our columns. +
+ +## Instructions +
+Give the columns in the grid a 20px gap. +
+ +## Tests +
+ +```yml +- text: container class should have a grid-column-gap property that has the value of 20px. + testString: 'assert(code.match(/.container\s*?{[\s\S]*grid-column-gap\s*?:\s*?20px\s*?;[\s\S]*}/gi), "container class should have a grid-column-gap property that has the value of 20px.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + + +
+
1
+
2
+
3
+
4
+
5
+
+``` + +
+ + + +
+ +## Solution +
+ + +```js +var code = ".container {grid-column-gap: 20px;}" +``` + +
diff --git a/curriculum/challenges/01-responsive-web-design/css-grid/Create a Row Gap using grid-row-gap.md b/curriculum/challenges/01-responsive-web-design/css-grid/Create a Row Gap using grid-row-gap.md new file mode 100644 index 0000000000..c45cbb0b2d --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/css-grid/Create a Row Gap using grid-row-gap.md @@ -0,0 +1,80 @@ +--- +id: 5a9036ee38fddaf9a66b5d36 +title: Create a Row Gap using grid-row-gap +challengeType: 0 +videoUrl: 'https://scrimba.com/p/pByETK/cPbJ2Cv' +--- + +## Description +
+You can add a gap in between the rows of a grid using grid-row-gap in the same way that you added a gap in between columns in the previous challenge. +
+ +## Instructions +
+Create a gap for the rows that is 5px tall. +
+ +## Tests +
+ +```yml +- text: container class should have a grid-row-gap property that has the value of 5px. + testString: 'assert(code.match(/.container\s*?{[\s\S]*grid-row-gap\s*?:\s*?5px\s*?;[\s\S]*}/gi), "container class should have a grid-row-gap property that has the value of 5px.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + + +
+
1
+
2
+
3
+
4
+
5
+
+``` + +
+ + + +
+ +## Solution +
+ + +```js +var code = ".container {grid-row-gap: 5px;}" +``` + +
diff --git a/curriculum/challenges/01-responsive-web-design/css-grid/Divide the Grid Into an Area Template.md b/curriculum/challenges/01-responsive-web-design/css-grid/Divide the Grid Into an Area Template.md new file mode 100644 index 0000000000..8f525fb636 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/css-grid/Divide the Grid Into an Area Template.md @@ -0,0 +1,88 @@ +--- +id: 5a94fe0569fb03452672e45c +title: Divide the Grid Into an Area Template +challengeType: 0 +videoUrl: 'https://scrimba.com/p/pByETK/cLLpGAy' +--- + +## Description +
+You can group cells of your grid together into an area and give the area a custom name. Do this by using grid-template-areas on the container like this: +
grid-template-areas:
  "header header header"
  "advert content content"
  "footer footer footer";
+The code above merges the top three cells together into an area named header, the bottom three cells into a footer area, and it makes two areas in the middle row; advert and content. +Note
Every word in the code represents a cell and every pair of quotation marks represent a row. +In addition to custom labels, you can use a period (.) to designate an empty cell in the grid. +
+ +## Instructions +
+Place the area template so that the cell labeled advert becomes an empty cell. +
+ +## Tests +
+ +```yml +- text: container class should have a grid-template-areas property similar to the preview but has . instead of the advert area. + testString: 'assert(code.match(/.container\s*?{[\s\S]*grid-template-areas\s*?:\s*?"\s*?header\s*?header\s*?header\s*?"\s*?"\s*?.\s*?content\s*?content\s*?"\s*?"\s*?footer\s*?footer\s*?footer\s*?"\s*?;[\s\S]*}/gi), "container class should have a grid-template-areas propertiy similar to the preview but has . instead of the advert area.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + + +
+
1
+
2
+
3
+
4
+
5
+
+``` + +
+ + + +
+ +## Solution +
+ + +```js +var code = ".container {grid-template-areas: \"header header header\" \". content content\" \"footer footer footer\";}" +``` + +
diff --git a/curriculum/challenges/01-responsive-web-design/css-grid/Limit Item Size Using the minmax Function.md b/curriculum/challenges/01-responsive-web-design/css-grid/Limit Item Size Using the minmax Function.md new file mode 100644 index 0000000000..d2e18e5260 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/css-grid/Limit Item Size Using the minmax Function.md @@ -0,0 +1,83 @@ +--- +id: 5a94fe4469fb03452672e460 +title: Limit Item Size Using the minmax Function +challengeType: 0 +videoUrl: 'https://scrimba.com/p/pByETK/cD97RTv' +--- + +## Description +
+There's another built-in function to use with grid-template-columns and grid-template-rows called minmax. It's used to limit the size of items when the grid container changes size. To do this you need to specify the acceptable size range for your item. Here is an example: +
grid-template-columns: 100px minmax(50px, 200px);
+In the code above, grid-template-columns is set to create two columns; the first is 100px wide, and the second has the minimum width of 50px and the maximum width of 200px. +
+ +## Instructions +
+Using the minmax function, replace the 1fr in the repeat function with a column size that has the minimum width of 90px and the maximum width of 1fr, and resize the preview panel to see the effect. +
+ +## Tests +
+ +```yml +- text: container class should have a grid-template-columns property that is set to repeat 3 columns with the minimum width of 90px and maximum width of 1fr. + testString: 'assert(code.match(/.container\s*?{[\s\S]*grid-template-columns\s*?:\s*?repeat\s*?\(\s*?3\s*?,\s*?minmax\s*?\(\s*?90px\s*?,\s*?1fr\s*?\)\s*?\)\s*?;[\s\S]*}/gi), "container class should have a grid-template-columns property that is set to repeat 3 columns with the minimum width of 90px and maximum width of 1fr.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + + +
+
1
+
2
+
3
+
4
+
5
+
+``` + +
+ + + +
+ +## Solution +
+ + +```js +var code = ".container {grid-template-columns: repeat(3, minmax(90px, 1fr));}" +``` + +
diff --git a/curriculum/challenges/01-responsive-web-design/css-grid/Place Items in Grid Areas Using the grid-area Property.md b/curriculum/challenges/01-responsive-web-design/css-grid/Place Items in Grid Areas Using the grid-area Property.md new file mode 100644 index 0000000000..14092fd7c9 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/css-grid/Place Items in Grid Areas Using the grid-area Property.md @@ -0,0 +1,90 @@ +--- +id: 5a94fe1369fb03452672e45d +title: Place Items in Grid Areas Using the grid-area Property +challengeType: 0 +videoUrl: 'https://scrimba.com/p/pByETK/cRrqmtV' +--- + +## Description +
+After creating an areas template for your grid container, as shown in the previous challenge, you can place an item in your custom area by referencing the name you gave it. To do this, you use the grid-area property on an item like this: +
.item1 { grid-area: header; }
+This lets the grid know that you want the item1 class to go in the area named header. In this case, the item will use the entire top row because that whole row is named as the header area. +
+ +## Instructions +
+Place an element with the item5 class in the footer area using the grid-area property. +
+ +## Tests +
+ +```yml +- text: item5 class should have a grid-area property that has the value of footer. + testString: 'assert(code.match(/.item5\s*?{[\s\S]*grid-area\s*?:\s*?footer\s*?;[\s\S]*}/gi), "item5 class should have a grid-area property that has the value of footer.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + + +
+
1
+
2
+
3
+
4
+
5
+
+``` + +
+ + + +
+ +## Solution +
+ + +```js +var code = ".item5 {grid-area: footer;}" +``` + +
diff --git a/curriculum/challenges/01-responsive-web-design/css-grid/Reduce Repetition Using the repeat Function.md b/curriculum/challenges/01-responsive-web-design/css-grid/Reduce Repetition Using the repeat Function.md new file mode 100644 index 0000000000..abf7e46621 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/css-grid/Reduce Repetition Using the repeat Function.md @@ -0,0 +1,89 @@ +--- +id: 5a94fe3669fb03452672e45f +title: Reduce Repetition Using the repeat Function +challengeType: 0 +videoUrl: 'https://scrimba.com/p/pByETK/cQvqyHR' +--- + +## Description +
+When you used grid-template-columns and grid-template-rows to define the structure of a grid, you entered a value for each row or column you created. +Lets say you want a grid with 100 rows of the same height. It isn't very practical to insert 100 values individually. Fortunately, there's a better way - by using the repeat function to specify the number of times you want your column or row to be repeated, followed by a comma and the value you want to repeat. +Here's an example that would create the 100 row grid, each row at 50px tall. +
grid-template-rows: repeat(100, 50px);
+You can also repeat multiple values with the repeat function, and insert the function amongst other values when defining a grid structure. Here's what I mean: +
grid-template-columns: repeat(2, 1fr 50px) 20px;
+This translates to: +
grid-template-columns: 1fr 50px 1fr 50px 20px;
+Note
1fr 50px is repeated twice followed by 20px. +
+ +## Instructions +
+Use repeat to remove repetition from the grid-template-columns property. +
+ +## Tests +
+ +```yml +- text: container class should have a grid-template-columns property that is set to repeat 3 columns with the width of 1fr. + testString: 'assert(code.match(/.container\s*?{[\s\S]*grid-template-columns\s*?:\s*?repeat\s*?\(\s*?3\s*?,\s*?1fr\s*?\)\s*?;[\s\S]*}/gi), "container class should have a grid-template-columns property that is set to repeat 3 columns with the width of 1fr.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + + +
+
1
+
2
+
3
+
4
+
5
+
+``` + +
+ + + +
+ +## Solution +
+ + +```js +var code = ".container {grid-template-columns: repeat(3, 1fr);}" +``` + +
diff --git a/curriculum/challenges/01-responsive-web-design/css-grid/Use CSS Grid units to Change the Size of Columns and Rows.md b/curriculum/challenges/01-responsive-web-design/css-grid/Use CSS Grid units to Change the Size of Columns and Rows.md new file mode 100644 index 0000000000..f0a3a6040a --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/css-grid/Use CSS Grid units to Change the Size of Columns and Rows.md @@ -0,0 +1,85 @@ +--- +id: 5a9036ee38fddaf9a66b5d34 +title: Use CSS Grid units to Change the Size of Columns and Rows +challengeType: 0 +videoUrl: 'https://scrimba.com/p/pByETK/cvE8phd' +--- + +## Description +
+You can use absolute and relative units like px and em in CSS Grid to define the size of rows and columns. You can use these as well: +fr: sets the column or row to a fraction of the available space, +auto: sets the column or row to the width or height of its content automatically, +%: adjusts the column or row to the percent width of its container. +Here's the code that generates the output in the preview: +
grid-template-columns: auto 50px 10% 2fr 1fr;
+This snippet creates five columns. The first column is as wide as its content, the second column is 50px, the third column is 10% of its container, and for the last two columns; the remaining space is divided into three sections, two are allocated for the fourth column, and one for the fifth. +
+ +## Instructions +
+Make a grid with three columns whose widths are as follows: 1fr, 100px, and 2fr. +
+ +## Tests +
+ +```yml +- text: 'container class should have a grid-template-columns property that has three columns with the following widths: 1fr, 100px, and 2fr.' + testString: 'assert(code.match(/.container\s*?{[\s\S]*grid-template-columns\s*?:\s*?1fr\s*?100px\s*?2fr\s*?;[\s\S]*}/gi), "container class should have a grid-template-columns property that has three columns with the following widths: 1fr, 100px, and 2fr.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + + +
+
1
+
2
+
3
+
4
+
5
+
+``` + +
+ + + +
+ +## Solution +
+ + +```js +var code = ".container {grid-template-columns: 1fr 100px 2fr;}" +``` + +
diff --git a/curriculum/challenges/01-responsive-web-design/css-grid/Use Media Queries to Create Responsive Layouts.md b/curriculum/challenges/01-responsive-web-design/css-grid/Use Media Queries to Create Responsive Layouts.md new file mode 100644 index 0000000000..ef76a40c54 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/css-grid/Use Media Queries to Create Responsive Layouts.md @@ -0,0 +1,120 @@ +--- +id: 5a94fe7769fb03452672e463 +title: Use Media Queries to Create Responsive Layouts +challengeType: 0 +videoUrl: 'https://scrimba.com/p/pByETK/cMbqeHk' +--- + +## Description +
+CSS Grid can be an easy way to make your site more responsive by using media queries to rearrange grid areas, change dimensions of a grid, and rearrange the placement of items. +In the preview, when the viewport width is 300px or more, the number of columns changes from 1 to 2. The advertisement area then occupies the left column completely. +
+ +## Instructions +
+When the viewport width is 400px or more, make the header area occupy the top row completely and the footer area occupy the bottom row completely. +
+ +## Tests +
+ +```yml +- text: 'When the viewport is 400px or more, container class should have a grid-template-areas property in which the footer and header areas occupy the top and bottom rows respectively and advert and content occupy the left and right columns of the middle row.' + testString: 'assert(code.match(/@media\s*?\(\s*?min-width\s*?:\s*?400px\s*?\)[\s\S]*.container\s*?{[\s\S]*grid-template-areas\s*?:\s*?"\s*?header\s*?header\s*?"\s*?"\s*?advert\s*?content\s*?"\s*?"\s*?footer\s*?footer\s*?"\s*?;[\s\S]*}/gi), "When the viewport is 400px or more, container class should have a grid-template-areas property in which the footer and header areas occupy the top and bottom rows respectively and advert and content occupy the left and right columns of the middle row.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + + +
+
header
+
advert
+
content
+
footer
+
+``` + +
+ + + +
+ +## Solution +
+ + +```js +var code = "@media (min-width: 400px){.container{ grid-template-areas: \"header header\" \"advert content\" \"footer footer\";}}" +``` + +
diff --git a/curriculum/challenges/01-responsive-web-design/css-grid/Use grid-area Without Creating an Areas Template.md b/curriculum/challenges/01-responsive-web-design/css-grid/Use grid-area Without Creating an Areas Template.md new file mode 100644 index 0000000000..c49d3b035d --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/css-grid/Use grid-area Without Creating an Areas Template.md @@ -0,0 +1,88 @@ +--- +id: 5a94fe2669fb03452672e45e +title: Use grid-area Without Creating an Areas Template +challengeType: 0 +videoUrl: 'https://scrimba.com/p/pByETK/c6N7VhK' +--- + +## Description +
+The grid-area property you learned in the last challenge can be used in another way. If your grid doesn't have an areas template to reference, you can create an area on the fly for an item to be placed like this: +
item1 { grid-area: 1/1/2/4; }
+This is using the line numbers you learned about earlier to define where the area for this item will be. The numbers in the example above represent these values: +
grid-area: horizontal line to start at / vertical line to start at / horizontal line to end at / vertical line to end at;
+So the item in the example will consume the rows between lines 1 and 2, and the columns between lines 1 and 4. +
+ +## Instructions +
+Using the grid-area property, place the element with item5 class between the third and fourth horizontal lines and between the first and fourth vertical lines. +
+ +## Tests +
+ +```yml +- text: item5 class should have a grid-area property that has the value of 3/1/4/4. + testString: 'assert(code.match(/.item5\s*?{[\s\S]*grid-area\s*?:\s*?3\s*?\/\s*?1\s*?\/\s*?4\s*?\/\s*?4\s*?;[\s\S]*}/gi), "item5 class should have a grid-area property that has the value of 3/1/4/4.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + + +
+
1
+
2
+
3
+
4
+
5
+
+``` + +
+ + + +
+ +## Solution +
+ + +```js +var code = ".item5 {grid-area: 3/1/4/4;}" +``` + +
diff --git a/curriculum/challenges/01-responsive-web-design/css-grid/Use grid-column to Control Spacing.md b/curriculum/challenges/01-responsive-web-design/css-grid/Use grid-column to Control Spacing.md new file mode 100644 index 0000000000..44264fbb5a --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/css-grid/Use grid-column to Control Spacing.md @@ -0,0 +1,91 @@ +--- +id: 5a90372638fddaf9a66b5d38 +title: Use grid-column to Control Spacing +challengeType: 0 +videoUrl: 'https://scrimba.com/p/pByETK/cnzkDSr' +--- + +## Description +
+Up to this point, all the properties that have been discussed are for grid containers. The grid-column property is the first one for use on the grid items themselves. +The hypothetical horizontal and vertical lines that create the grid are referred to as lines. These lines are numbered starting with 1 at the top left corner of the grid and move right for columns and down for rows, counting upward. +This is what the lines look like for a 3x3 grid: +

column lines

1

2

3

4

row lines

1

2

3

4

+To control the amount of columns an item will consume, you can use the grid-column property in conjunction with the line numbers you want the item to start and stop at. +Here's an example: +
grid-column: 1 / 3;
+This will make the item start at the first vertical line of the grid on the left and span to the 3rd line of the grid, consuming two columns. +
+ +## Instructions +
+Make the item with the class item5 consume the last two columns of the grid. +
+ +## Tests +
+ +```yml +- text: item5 class should have a grid-column property that has the value of 2 / 4. + testString: 'assert(code.match(/.item5\s*?{[\s\S]*grid-column\s*?:\s*?2\s*?\/\s*?4\s*?;[\s\S]*}/gi), "item5 class should have a grid-column property that has the value of 2 / 4.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + + +
+
1
+
2
+
3
+
4
+
5
+
+``` + +
+ + + +
+ +## Solution +
+ + +```js +var code = ".item5 {grid-column: 2 / 4;}" +``` + +
diff --git a/curriculum/challenges/01-responsive-web-design/css-grid/Use grid-row to Control Spacing.md b/curriculum/challenges/01-responsive-web-design/css-grid/Use grid-row to Control Spacing.md new file mode 100644 index 0000000000..0f1c953d11 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/css-grid/Use grid-row to Control Spacing.md @@ -0,0 +1,85 @@ +--- +id: 5a90373638fddaf9a66b5d39 +title: Use grid-row to Control Spacing +challengeType: 0 +videoUrl: 'https://scrimba.com/p/pByETK/c9WBLU4' +--- + +## Description +
+Of course, you can make items consume multiple rows just like you can with columns. You define the horizontal lines you want an item to start and stop at using the grid-row property on a grid item. +
+ +## Instructions +
+Make the element with the item5 class consume the last two rows. +
+ +## Tests +
+ +```yml +- text: item5 class should have a grid-row property that has the value of 2 / 4. + testString: 'assert(code.match(/.item5\s*?{[\s\S]*grid-row\s*?:\s*?2\s*?\/\s*?4\s*?;[\s\S]*}/gi), "item5 class should have a grid-row property that has the value of 2 / 4.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + + +
+
1
+
2
+
3
+
4
+
5
+
+``` + +
+ + + +
+ +## Solution +
+ + +```js +var code = ".item5 {grid-row: 2 / 4;}" +``` + +
diff --git a/curriculum/challenges/01-responsive-web-design/css-grid/meta.json b/curriculum/challenges/01-responsive-web-design/css-grid/meta.json new file mode 100644 index 0000000000..02d5481ec7 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/css-grid/meta.json @@ -0,0 +1,8 @@ +{ + "name": "CSS Grid", + "dashedName": "css-grid", + "order": 6, + "time": "5 hours", + "superBlock": "responsive-web-design", + "superOrder": 1 +} \ No newline at end of file diff --git a/curriculum/challenges/01-responsive-web-design/responsive-web-design-principles/Create a Media Query.md b/curriculum/challenges/01-responsive-web-design/responsive-web-design-principles/Create a Media Query.md new file mode 100644 index 0000000000..8a373ddaea --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/responsive-web-design-principles/Create a Media Query.md @@ -0,0 +1,67 @@ +--- +id: 587d78b0367417b2b2512b08 +title: Create a Media Query +challengeType: 0 +videoUrl: 'https://scrimba.com/p/pzrPu4/cqwKrtm' +--- + +## Description +
+Media Queries are a new technique introduced in CSS3 that change the presentation of content based on different viewport sizes. The viewport is a user's visible area of a web page, and is different depending on the device used to access the site. +Media Queries consist of a media type, and if that media type matches the type of device the document is displayed on, the styles are applied. You can have as many selectors and styles inside your media query as you want. +Here's an example of a media query that returns the content when the device's width is less than or equal to 100px: +@media (max-width: 100px) { /* CSS Rules */ } +and the following media query returns the content when the device's height is more than or equal to 350px: +@media (min-height: 350px) { /* CSS Rules */ } +Remember, the CSS inside the media query is applied only if the media type matches that of the device being used. +
+ +## Instructions +
+Add a media query, so that the p tag has a font-size of 10px when the device's height is less than or equal to 800px. +
+ +## Tests +
+ +```yml +- text: Your p element should have the font-size of 10px when the device height is less than or equal to 800px. + testString: 'assert($("p").css("font-size") == "10px", "Your p element should have the font-size of 10px when the device height is less than or equal to 800px.");' +- text: Declare a @media query for devices with a height less than or equal to 800px. + testString: 'assert(code.match(/@media\s*?\(\s*?max-height\s*?:\s*?800px\s*?\)/g), "Declare a @media query for devices with a height less than or equal to 800px.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + + +

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus quis tempus massa. Aenean erat nisl, gravida vel vestibulum cursus, interdum sit amet lectus. Sed sit amet quam nibh. Suspendisse quis tincidunt nulla. In hac habitasse platea dictumst. Ut sit amet pretium nisl. Vivamus vel mi sem. Aenean sit amet consectetur sem. Suspendisse pretium, purus et gravida consequat, nunc ligula ultricies diam, at aliquet velit libero a dui.

+``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/responsive-web-design-principles/Make Typography Responsive.md b/curriculum/challenges/01-responsive-web-design/responsive-web-design-principles/Make Typography Responsive.md new file mode 100644 index 0000000000..19f5980e68 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/responsive-web-design-principles/Make Typography Responsive.md @@ -0,0 +1,61 @@ +--- +id: 587d78b1367417b2b2512b0c +title: Make Typography Responsive +challengeType: 0 +videoUrl: 'https://scrimba.com/p/pzrPu4/crzN7T8' +--- + +## Description +
+Instead of using em or px to size text, you can use viewport units for responsive typography. Viewport units, like percentages, are relative units, but they are based off different items. Viewport units are relative to the viewport dimensions (width or height) of a device, and percentages are relative to the size of the parent container element. +The four different viewport units are: + +
+ +## Instructions +
+Set the width of the h2 tag to 80% of the viewport's width and the width of the paragraph as 75% of the viewport's smaller dimension. +
+ +## Tests +
+ +```yml +- text: Your h2 tag should have a width of 80vw. + testString: 'assert(code.match(/h2\s*?{\s*?width:\s*?80vw;\s*?}/g), "Your h2 tag should have a width of 80vw.");' +- text: Your p tag should have a width of 75vmin. + testString: 'assert(code.match(/p\s*?{\s*?width:\s*?75vmin;\s*?}/g), "Your p tag should have a width of 75vmin.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + + +

Importantus Ipsum

+

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus quis tempus massa. Aenean erat nisl, gravida vel vestibulum cursus, interdum sit amet lectus. Sed sit amet quam nibh. Suspendisse quis tincidunt nulla. In hac habitasse platea dictumst. Ut sit amet pretium nisl. Vivamus vel mi sem. Aenean sit amet consectetur sem. Suspendisse pretium, purus et gravida consequat, nunc ligula ultricies diam, at aliquet velit libero a dui.

+``` + +
+ + + +
+ +## Solution +
+ + +```js +var code = "h2 {width: 80vw;} p {width: 75vmin;}" +``` + +
diff --git a/curriculum/challenges/01-responsive-web-design/responsive-web-design-principles/Make an Image Responsive.md b/curriculum/challenges/01-responsive-web-design/responsive-web-design-principles/Make an Image Responsive.md new file mode 100644 index 0000000000..841c5d290d --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/responsive-web-design-principles/Make an Image Responsive.md @@ -0,0 +1,62 @@ +--- +id: 587d78b1367417b2b2512b09 +title: Make an Image Responsive +challengeType: 0 +videoUrl: 'https://scrimba.com/p/pzrPu4/cz763UD' +--- + +## Description +
+Making images responsive with CSS is actually very simple. Instead of applying an absolute width to an element: +img { width: 720px; } +You can use: +
img {
  max-width: 100%;
  display: block;
  height: auto;
}
+The max-width property of 100% scales the image to fit the width of its container, but the image won't stretch wider than its original width. Setting the display property to block changes the image from an inline element (its default), to a block element on its own line. The height property of auto keeps the original aspect ratio of the image. +
+ +## Instructions +
+Add style rules for the img tag to make it responsive to the size of its container. It should display as a block-level element, it should fit the full width of its container without stretching, and it should keep its original aspect ratio. +
+ +## Tests +
+ +```yml +- text: Your img tag should have a max-width set to 100%. + testString: 'assert(code.match(/max-width:\s*?100%;/g), "Your img tag should have a max-width set to 100%.");' +- text: Your img tag should have a display set to block. + testString: 'assert($("img").css("display") == "block", "Your img tag should have a display set to block.");' +- text: Your img tag should have a height set to auto. + testString: 'assert(code.match(/height:\s*?auto;/g), "Your img tag should have a height set to auto.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + + +freeCodeCamp stickers set +``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/responsive-web-design-principles/Use a Retina Image for Higher Resolution Displays.md b/curriculum/challenges/01-responsive-web-design/responsive-web-design-principles/Use a Retina Image for Higher Resolution Displays.md new file mode 100644 index 0000000000..a203cdd18e --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/responsive-web-design-principles/Use a Retina Image for Higher Resolution Displays.md @@ -0,0 +1,58 @@ +--- +id: 587d78b1367417b2b2512b0a +title: Use a Retina Image for Higher Resolution Displays +challengeType: 0 +videoUrl: 'https://scrimba.com/p/pzrPu4/cVZ4Rfp' +--- + +## Description +
+The simplest way to make your images appear "retina" (and optimize them for retina displays) is to define their width and height values as only half of what the original file is. +Here is an example of an image that is only using half of the original height and width: +
<style>
  img { height: 250px; width: 250px; }
</style>
<img src="coolPic500x500" alt="A most excellent picture">
+
+ +## Instructions +
+Set the width and height of the img tag to half of their original values. In this case, both the original height and the original width are 200px. +
+ +## Tests +
+ +```yml +- text: Your img tag should have a width of 100 pixels. + testString: 'assert($("img").css("width") == "100px", "Your img tag should have a width of 100 pixels.");' +- text: Your img tag should have a height of 100 pixels. + testString: 'assert($("img").css("height") == "100px", "Your img tag should have a height of 100 pixels.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```html + + +freeCodeCamp sticker that says 'Because CamperBot Cares' +``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/responsive-web-design-principles/meta.json b/curriculum/challenges/01-responsive-web-design/responsive-web-design-principles/meta.json new file mode 100644 index 0000000000..700ba88014 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/responsive-web-design-principles/meta.json @@ -0,0 +1,8 @@ +{ + "name": "Responsive Web Design Principles", + "dashedName": "responsive-web-design-principles", + "order": 4, + "time": "1 hour", + "superBlock": "responsive-web-design", + "superOrder": 1 +} \ No newline at end of file diff --git a/curriculum/challenges/01-responsive-web-design/responsive-web-design-projects/Build a Personal Portfolio Webpage.md b/curriculum/challenges/01-responsive-web-design/responsive-web-design-projects/Build a Personal Portfolio Webpage.md new file mode 100644 index 0000000000..0a627b0e5d --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/responsive-web-design-projects/Build a Personal Portfolio Webpage.md @@ -0,0 +1,55 @@ +--- +id: bd7158d8c242eddfaeb5bd13 +title: Build a Personal Portfolio Webpage +isRequired: true +challengeType: 3 +--- + +## Description +
+Objective: Build a CodePen.io app that is functionally similar to this: https://codepen.io/freeCodeCamp/full/zNBOYG. +Fulfill the below user stories and get all of the tests to pass. Give it your own personal style. +You can use HTML, JavaScript, and CSS to complete this project. Plain CSS is recommended because that is what the lessons have covered so far and you should get some practice with plain CSS. You can use Bootstrap or SASS if you choose. Additional technologies (just for example jQuery, React, Angular, or Vue) are not recommended for this project, and using them is at your own risk. Other projects will give you a chance to work with different technology stacks like React. We will accept and try to fix all issue reports that use the suggested technology stack for this project. Happy coding! +User Story #1: My portfolio should have a welcome section with an id of welcome-section. +User Story #2: The welcome section should have an h1 element that contains text. +User Story #3: My portfolio should have a projects section with an id of projects. +User Story #4: The projects section should contain at least one element with a class of project-tile to hold a project. +User Story #5: The projects section should contain at least one link to a project. +User Story #6: My portfolio should have a navbar with an id of navbar. +User Story #7: The navbar should contain at least one link that I can click on to navigate to different sections of the page. +User Story #8: My portfolio should have a link with an id of profile-link, which opens my GitHub or FCC profile in a new tab. +User Story #9: My portfolio should have at least one media query. +User Story #10: The height of the welcome section should be equal to the height of the viewport. +User Story #11: The navbar should always be at the top of the viewport. +You can build your project by forking this CodePen pen. Or you can use this CDN link to run the tests in any environment you like: https://cdn.freecodecamp.org/testable-projects-fcc/v1/bundle.js +Once you're done, submit the URL to your working project with all its tests passing. +Remember to use the Read-Search-Ask method if you get stuck. +
+ +## Instructions +
+ +
+ +## Tests +
+ +```yml +[] + +``` + +
+ +## Challenge Seed +
+ +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/responsive-web-design-projects/Build a Product Landing Page.md b/curriculum/challenges/01-responsive-web-design/responsive-web-design-projects/Build a Product Landing Page.md new file mode 100644 index 0000000000..d470019f0c --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/responsive-web-design-projects/Build a Product Landing Page.md @@ -0,0 +1,59 @@ +--- +id: 587d78af367417b2b2512b04 +title: Build a Product Landing Page +isRequired: true +challengeType: 3 +--- + +## Description +
+Objective: Build a CodePen.io app that is functionally similar to this: https://codepen.io/freeCodeCamp/full/RKRbwL. +Fulfill the below user stories and get all of the tests to pass. Give it your own personal style. +You can use HTML, JavaScript, and CSS to complete this project. Plain CSS is recommended because that is what the lessons have covered so far and you should get some practice with plain CSS. You can use Bootstrap or SASS if you choose. Additional technologies (just for example jQuery, React, Angular, or Vue) are not recommended for this project, and using them is at your own risk. Other projects will give you a chance to work with different technology stacks like React. We will accept and try to fix all issue reports that use the suggested technology stack for this project. Happy coding! +User Story #1: My product landing page should have a header element with a corresponding id="header". +User Story #2: I can see an image within the header element with a corresponding id="header-img". A company logo would make a good image here. +User Story #3: Within the #header element I can see a nav element with a corresponding id="nav-bar". +User Story #4: I can see at least three clickable elements inside the nav element, each with the class nav-link. +User Story #5: When I click a .nav-link button in the nav element, I am taken to the corresponding section of the landing page. +User Story #6: I can watch an embedded product video with id="video". +User Story #7: My landing page has a form element with a corresponding id="form". +User Story #8: Within the form, there is an input field with id="email" where I can enter an email address. +User Story #9: The #email input field should have placeholder text to let the user know what the field is for. +User Story #10: The #email input field uses HTML5 validation to confirm that the entered text is an email address. +User Story #11: Within the form, there is a submit input with a corresponding id="submit". +User Story #12: When I click the #submit element, the email is submitted to a static page (use this mock URL: https://www.freecodecamp.com/email-submit) that confirms the email address was entered and that it posted successfully. +User Story #13: The navbar should always be at the top of the viewport. +User Story #14: My product landing page should have at least one media query. +User Story #15: My product landing page should utilize CSS flexbox at least once. +You can build your project by forking this CodePen pen. Or you can use this CDN link to run the tests in any environment you like: https://cdn.freecodecamp.org/testable-projects-fcc/v1/bundle.js +Once you're done, submit the URL to your working project with all its tests passing. +Remember to use the Read-Search-Ask method if you get stuck. +
+ +## Instructions +
+ +
+ +## Tests +
+ +```yml +[] + +``` + +
+ +## Challenge Seed +
+ +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/responsive-web-design-projects/Build a Survey Form.md b/curriculum/challenges/01-responsive-web-design/responsive-web-design-projects/Build a Survey Form.md new file mode 100644 index 0000000000..50370d1f40 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/responsive-web-design-projects/Build a Survey Form.md @@ -0,0 +1,60 @@ +--- +id: 587d78af367417b2b2512b03 +title: Build a Survey Form +isRequired: true +challengeType: 3 +--- + +## Description +
+Objective: Build a CodePen.io app that is functionally similar to this: https://codepen.io/freeCodeCamp/full/VPaoNP. +Fulfill the below user stories and get all of the tests to pass. Give it your own personal style. +You can use HTML, JavaScript, and CSS to complete this project. Plain CSS is recommended because that is what the lessons have covered so far and you should get some practice with plain CSS. You can use Bootstrap or SASS if you choose. Additional technologies (just for example jQuery, React, Angular, or Vue) are not recommended for this project, and using them is at your own risk. Other projects will give you a chance to work with different technology stacks like React. We will accept and try to fix all issue reports that use the suggested technology stack for this project. Happy coding! +User Story #1: I can see a title with id="title" in H1 sized text. +User Story #2: I can see a short explanation with id="description" in P sized text. +User Story #3: I can see a form with id="survey-form". +User Story #4: Inside the form element, I am required to enter my name in a field with id="name". +User Story #5: Inside the form element, I am required to enter an email in a field with id="email". +User Story #6: If I enter an email that is not formatted correctly, I will see an HTML5 validation error. +User Story #7: Inside the form, I can enter a number in a field with id="number". +User Story #8: If I enter non-numbers in the number input, I will see an HTML5 validation error. +User Story #9: If I enter numbers outside the range of the number input, which are defined by the min and max attributes, I will see an HTML5 validation error. +User Story #10: For the name, email, and number input fields inside the form I can see corresponding labels that describe the purpose of each field with the following ids: id="name-label", id="email-label", and id="number-label". +User Story #11: For the name, email, and number input fields, I can see placeholder text that gives me a description or instructions for each field. +User Story #12: Inside the form element, I can select an option from a dropdown that has a corresponding id="dropdown". +User Story #13: Inside the form element, I can select a field from one or more groups of radio buttons. Each group should be grouped using the name attribute. +User Story #14: Inside the form element, I can select several fields from a series of checkboxes, each of which must have a value attribute. +User Story #15: Inside the form element, I am presented with a textarea at the end for additional comments. +User Story #16: Inside the form element, I am presented with a button with id="submit" to submit all my inputs. +You can build your project by forking this CodePen pen. Or you can use this CDN link to run the tests in any environment you like: https://cdn.freecodecamp.org/testable-projects-fcc/v1/bundle.js +Once you're done, submit the URL to your working project with all its tests passing. +Remember to use the Read-Search-Ask method if you get stuck. +
+ +## Instructions +
+ +
+ +## Tests +
+ +```yml +[] + +``` + +
+ +## Challenge Seed +
+ +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/responsive-web-design-projects/Build a Technical Documentation Page.md b/curriculum/challenges/01-responsive-web-design/responsive-web-design-projects/Build a Technical Documentation Page.md new file mode 100644 index 0000000000..ec3ef71022 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/responsive-web-design-projects/Build a Technical Documentation Page.md @@ -0,0 +1,59 @@ +--- +id: 587d78b0367417b2b2512b05 +title: Build a Technical Documentation Page +isRequired: true +challengeType: 3 +--- + +## Description +
+Objective: Build a CodePen.io app that is functionally similar to this: https://codepen.io/freeCodeCamp/full/NdrKKL. +Fulfill the below user stories and get all of the tests to pass. Give it your own personal style. +You can use HTML, JavaScript, and CSS to complete this project. Plain CSS is recommended because that is what the lessons have covered so far and you should get some practice with plain CSS. You can use Bootstrap or SASS if you choose. Additional technologies (just for example jQuery, React, Angular, or Vue) are not recommended for this project, and using them is at your own risk. Other projects will give you a chance to work with different technology stacks like React. We will accept and try to fix all issue reports that use the suggested technology stack for this project. Happy coding! +User Story #1: I can see a main element with a corresponding id="main-doc", which contains the page's main content (technical documentation). +User Story #2: Within the #main-doc element, I can see several section elements, each with a class of main-section. There should be a minimum of 5. +User Story #3: The first element within each .main-section should be a header element which contains text that describes the topic of that section. +User Story #4: Each section element with the class of main-section should also have an id that corresponds with the text of each header contained within it. Any spaces should be replaced with underscores (e.g. The section that contains the header "Javascript and Java" should have a corresponding id="Javascript_and_Java"). +User Story #5: The .main-section elements should contain at least 10 p elements total (not each). +User Story #6: The .main-section elements should contain at least 5 code elements total (not each). +User Story #7: The .main-section elements should contain at least 5 li items total (not each). +User Story #8: I can see a nav element with a corresponding id="navbar". +User Story #9: The navbar element should contain one header element which contains text that describes the topic of the technical documentation. +User Story #10: Additionally, the navbar should contain link (a) elements with the class of nav-link. There should be one for every element with the class main-section. +User Story #11: The header element in the navbar must come before any link (a) elements in the navbar. +User Story #12: Each element with the class of nav-link should contain text that corresponds to the header text within each section (e.g. if you have a "Hello world" section/header, your navbar should have an element which contains the text "Hello world"). +User Story #13: When I click on a navbar element, the page should navigate to the corresponding section of the main-doc element (e.g. If I click on a nav-link element that contains the text "Hello world", the page navigates to a section element that has that id and contains the corresponding header. +User Story #14: On regular sized devices (laptops, desktops), the element with id="navbar" should be shown on the left side of the screen and should always be visible to the user. +User Story #15: My Technical Documentation page should use at least one media query. +You can build your project by forking this CodePen pen. Or you can use this CDN link to run the tests in any environment you like: https://cdn.freecodecamp.org/testable-projects-fcc/v1/bundle.js +Once you're done, submit the URL to your working project with all its tests passing. +Remember to use the Read-Search-Ask method if you get stuck. +
+ +## Instructions +
+ +
+ +## Tests +
+ +```yml +[] + +``` + +
+ +## Challenge Seed +
+ +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/responsive-web-design-projects/Build a Tribute Page.md b/curriculum/challenges/01-responsive-web-design/responsive-web-design-projects/Build a Tribute Page.md new file mode 100644 index 0000000000..a85e1ec8c5 --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/responsive-web-design-projects/Build a Tribute Page.md @@ -0,0 +1,53 @@ +--- +id: bd7158d8c442eddfaeb5bd18 +title: Build a Tribute Page +isRequired: true +challengeType: 3 +--- + +## Description +
+Objective: Build a CodePen.io app that is functionally similar to this: https://codepen.io/freeCodeCamp/full/zNqgVx. +Fulfill the below user stories and get all of the tests to pass. Give it your own personal style. +You can use HTML, JavaScript, and CSS to complete this project. Plain CSS is recommended because that is what the lessons have covered so far and you should get some practice with plain CSS. You can use Bootstrap or SASS if you choose. Additional technologies (just for example jQuery, React, Angular, or Vue) are not recommended for this project, and using them is at your own risk. Other projects will give you a chance to work with different technology stacks like React. We will accept and try to fix all issue reports that use the suggested technology stack for this project. Happy coding! +User Story #1: My tribute page should have an element with a corresponding id="main", which contains all other elements. +User Story #2: I should see an element with a corresponding id="title", which contains a string (i.e. text) that describes the subject of the tribute page (e.g. "Dr. Norman Borlaug"). +User Story #3: I should see a div element with a corresponding id="img-div". +User Story #4: Within the img-div element, I should see an img element with a corresponding id="image". +User Story #5: Within the img-div element, I should see an element with a corresponding id="img-caption" that contains textual content describing the image shown in img-div. +User Story #6: I should see an element with a corresponding id="tribute-info", which contains textual content describing the subject of the tribute page. +User Story #7: I should see an a element with a corresponding id="tribute-link", which links to an outside site that contains additional information about the subject of the tribute page. HINT: You must give your element an attribute of target and set it to _blank in order for your link to open in a new tab (i.e. target="_blank"). +User Story #8: The img element should responsively resize, relative to the width of its parent element, without exceeding its original size. +User Story #9: The img element should be centered within its parent element. +You can build your project by forking this CodePen pen. Or you can use this CDN link to run the tests in any environment you like: https://cdn.freecodecamp.org/testable-projects-fcc/v1/bundle.js. +Once you're done, submit the URL to your working project with all its tests passing. +Remember to use the Read-Search-Ask method if you get stuck. +
+ +## Instructions +
+ +
+ +## Tests +
+ +```yml +[] + +``` + +
+ +## Challenge Seed +
+ +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/01-responsive-web-design/responsive-web-design-projects/meta.json b/curriculum/challenges/01-responsive-web-design/responsive-web-design-projects/meta.json new file mode 100644 index 0000000000..a13f375bed --- /dev/null +++ b/curriculum/challenges/01-responsive-web-design/responsive-web-design-projects/meta.json @@ -0,0 +1,8 @@ +{ + "name": "Responsive Web Design Projects", + "dashedName": "responsive-web-design-projects", + "order": 7, + "time": "150 hours", + "superBlock": "responsive-web-design", + "superOrder": 1 +} \ No newline at end of file diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-algorithm-scripting/Boo who.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-algorithm-scripting/Boo who.md new file mode 100644 index 0000000000..1f17256331 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-algorithm-scripting/Boo who.md @@ -0,0 +1,81 @@ +--- +id: a77dbc43c33f39daa4429b4f +title: Boo who +isRequired: true +challengeType: 5 +--- + +## Description +
+Check if a value is classified as a boolean primitive. Return true or false. +Boolean primitives are true and false. +Remember to use Read-Search-Ask if you get stuck. Try to pair program. Write your own code. +
+ +## Instructions +
+ +
+ +## Tests +
+ +```yml +- text: booWho(true) should return true. + testString: 'assert.strictEqual(booWho(true), true, "booWho(true) should return true.");' +- text: booWho(false) should return true. + testString: 'assert.strictEqual(booWho(false), true, "booWho(false) should return true.");' +- text: 'booWho([1, 2, 3]) should return false.' + testString: 'assert.strictEqual(booWho([1, 2, 3]), false, "booWho([1, 2, 3]) should return false.");' +- text: 'booWho([].slice) should return false.' + testString: 'assert.strictEqual(booWho([].slice), false, "booWho([].slice) should return false.");' +- text: 'booWho({ "a": 1 }) should return false.' + testString: 'assert.strictEqual(booWho({ "a": 1 }), false, "booWho({ "a": 1 }) should return false.");' +- text: booWho(1) should return false. + testString: 'assert.strictEqual(booWho(1), false, "booWho(1) should return false.");' +- text: booWho(NaN) should return false. + testString: 'assert.strictEqual(booWho(NaN), false, "booWho(NaN) should return false.");' +- text: booWho("a") should return false. + testString: 'assert.strictEqual(booWho("a"), false, "booWho("a") should return false.");' +- text: booWho("true") should return false. + testString: 'assert.strictEqual(booWho("true"), false, "booWho("true") should return false.");' +- text: booWho("false") should return false. + testString: 'assert.strictEqual(booWho("false"), false, "booWho("false") should return false.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +function booWho(bool) { + // What is the new fad diet for ghost developers? The Boolean. + return bool; +} + +booWho(null); +``` + +
+ + + +
+ +## Solution +
+ + +```js +function booWho(bool) { + return typeof bool === "boolean"; +} + +booWho(null); +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-algorithm-scripting/Chunky Monkey.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-algorithm-scripting/Chunky Monkey.md new file mode 100644 index 0000000000..798ed97af3 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-algorithm-scripting/Chunky Monkey.md @@ -0,0 +1,81 @@ +--- +id: a9bd25c716030ec90084d8a1 +title: Chunky Monkey +isRequired: true +challengeType: 5 +--- + +## Description +
+Write a function that splits an array (first argument) into groups the length of size (second argument) and returns them as a two-dimensional array. +Remember to use Read-Search-Ask if you get stuck. Write your own code. +
+ +## Instructions +
+ +
+ +## Tests +
+ +```yml +- text: 'chunkArrayInGroups(["a", "b", "c", "d"], 2) should return [["a", "b"], ["c", "d"]].' + testString: 'assert.deepEqual(chunkArrayInGroups(["a", "b", "c", "d"], 2), [["a", "b"], ["c", "d"]], "chunkArrayInGroups(["a", "b", "c", "d"], 2) should return [["a", "b"], ["c", "d"]].");' +- text: 'chunkArrayInGroups([0, 1, 2, 3, 4, 5], 3) should return [[0, 1, 2], [3, 4, 5]].' + testString: 'assert.deepEqual(chunkArrayInGroups([0, 1, 2, 3, 4, 5], 3), [[0, 1, 2], [3, 4, 5]], "chunkArrayInGroups([0, 1, 2, 3, 4, 5], 3) should return [[0, 1, 2], [3, 4, 5]].");' +- text: 'chunkArrayInGroups([0, 1, 2, 3, 4, 5], 2) should return [[0, 1], [2, 3], [4, 5]].' + testString: 'assert.deepEqual(chunkArrayInGroups([0, 1, 2, 3, 4, 5], 2), [[0, 1], [2, 3], [4, 5]], "chunkArrayInGroups([0, 1, 2, 3, 4, 5], 2) should return [[0, 1], [2, 3], [4, 5]].");' +- text: 'chunkArrayInGroups([0, 1, 2, 3, 4, 5], 4) should return [[0, 1, 2, 3], [4, 5]].' + testString: 'assert.deepEqual(chunkArrayInGroups([0, 1, 2, 3, 4, 5], 4), [[0, 1, 2, 3], [4, 5]], "chunkArrayInGroups([0, 1, 2, 3, 4, 5], 4) should return [[0, 1, 2, 3], [4, 5]].");' +- text: 'chunkArrayInGroups([0, 1, 2, 3, 4, 5, 6], 3) should return [[0, 1, 2], [3, 4, 5], [6]].' + testString: 'assert.deepEqual(chunkArrayInGroups([0, 1, 2, 3, 4, 5, 6], 3), [[0, 1, 2], [3, 4, 5], [6]], "chunkArrayInGroups([0, 1, 2, 3, 4, 5, 6], 3) should return [[0, 1, 2], [3, 4, 5], [6]].");' +- text: 'chunkArrayInGroups([0, 1, 2, 3, 4, 5, 6, 7, 8], 4) should return [[0, 1, 2, 3], [4, 5, 6, 7], [8]].' + testString: 'assert.deepEqual(chunkArrayInGroups([0, 1, 2, 3, 4, 5, 6, 7, 8], 4), [[0, 1, 2, 3], [4, 5, 6, 7], [8]], "chunkArrayInGroups([0, 1, 2, 3, 4, 5, 6, 7, 8], 4) should return [[0, 1, 2, 3], [4, 5, 6, 7], [8]].");' +- text: 'chunkArrayInGroups([0, 1, 2, 3, 4, 5, 6, 7, 8], 2) should return [[0, 1], [2, 3], [4, 5], [6, 7], [8]].' + testString: 'assert.deepEqual(chunkArrayInGroups([0, 1, 2, 3, 4, 5, 6, 7, 8], 2), [[0, 1], [2, 3], [4, 5], [6, 7], [8]], "chunkArrayInGroups([0, 1, 2, 3, 4, 5, 6, 7, 8], 2) should return [[0, 1], [2, 3], [4, 5], [6, 7], [8]].");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +function chunkArrayInGroups(arr, size) { + // Break it up. + return arr; +} + +chunkArrayInGroups(["a", "b", "c", "d"], 2); +``` + +
+ + + +
+ +## Solution +
+ + +```js +function chunkArrayInGroups(arr, size) { + let out = []; + + for (let i = 0; i < arr.length; i += size) { + out.push(arr.slice(i, i + size)); + } + + return out; +} + +chunkArrayInGroups(["a", "b", "c", "d"], 2); + +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-algorithm-scripting/Confirm the Ending.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-algorithm-scripting/Confirm the Ending.md new file mode 100644 index 0000000000..e4359dc132 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-algorithm-scripting/Confirm the Ending.md @@ -0,0 +1,85 @@ +--- +id: acda2fb1324d9b0fa741e6b5 +title: Confirm the Ending +isRequired: true +challengeType: 5 +--- + +## Description +
+Check if a string (first argument, str) ends with the given target string (second argument, target). +This challenge can be solved with the .endsWith() method, which was introduced in ES2015. But for the purpose of this challenge, we would like you to use one of the JavaScript substring methods instead. +Remember to use Read-Search-Ask if you get stuck. Write your own code. +
+ +## Instructions +
+ +
+ +## Tests +
+ +```yml +- text: 'confirmEnding("Bastian", "n") should return true.' + testString: 'assert(confirmEnding("Bastian", "n") === true, "confirmEnding("Bastian", "n") should return true.");' +- text: 'confirmEnding("Congratulation", "on") should return true.' + testString: 'assert(confirmEnding("Congratulation", "on") === true, "confirmEnding("Congratulation", "on") should return true.");' +- text: 'confirmEnding("Connor", "n") should return false.' + testString: 'assert(confirmEnding("Connor", "n") === false, "confirmEnding("Connor", "n") should return false.");' +- text: 'confirmEnding("Walking on water and developing software from a specification are easy if both are frozen", "specification") should return false.' + testString: 'assert(confirmEnding("Walking on water and developing software from a specification are easy if both are frozen", "specification") === false, "confirmEnding("Walking on water and developing software from a specification are easy if both are frozen", "specification") should return false.");' +- text: 'confirmEnding("He has to give me a new name", "name") should return true.' + testString: 'assert(confirmEnding("He has to give me a new name", "name") === true, "confirmEnding("He has to give me a new name", "name") should return true.");' +- text: 'confirmEnding("Open sesame", "same") should return true.' + testString: 'assert(confirmEnding("Open sesame", "same") === true, "confirmEnding("Open sesame", "same") should return true.");' +- text: 'confirmEnding("Open sesame", "pen") should return false.' + testString: 'assert(confirmEnding("Open sesame", "pen") === false, "confirmEnding("Open sesame", "pen") should return false.");' +- text: 'confirmEnding("Open sesame", "game") should return false.' + testString: 'assert(confirmEnding("Open sesame", "game") === false, "confirmEnding("Open sesame", "game") should return false.");' +- text: 'confirmEnding("If you want to save our world, you must hurry. We dont know how much longer we can withstand the nothing", "mountain") should return false.' + testString: 'assert(confirmEnding("If you want to save our world, you must hurry. We dont know how much longer we can withstand the nothing", "mountain") === false, "confirmEnding("If you want to save our world, you must hurry. We dont know how much longer we can withstand the nothing", "mountain") should return false.");' +- text: 'confirmEnding("Abstraction", "action") should return true.' + testString: 'assert(confirmEnding("Abstraction", "action") === true, "confirmEnding("Abstraction", "action") should return true.");' +- text: Do not use the built-in method .endsWith() to solve the challenge. + testString: 'assert(!(/\.endsWith\(.*?\)\s*?;?/.test(code)) && !(/\["endsWith"\]/.test(code)), "Do not use the built-in method .endsWith() to solve the challenge.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +function confirmEnding(str, target) { + // "Never give up and good luck will find you." + // -- Falcor + return str; +} + +confirmEnding("Bastian", "n"); +``` + +
+ + + +
+ +## Solution +
+ + +```js +function confirmEnding(str, target) { + return str.substring(str.length - target.length) === target; +} + +confirmEnding("Bastian", "n"); + +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-algorithm-scripting/Convert Celsius to Fahrenheit.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-algorithm-scripting/Convert Celsius to Fahrenheit.md new file mode 100644 index 0000000000..2a02a0e8d1 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-algorithm-scripting/Convert Celsius to Fahrenheit.md @@ -0,0 +1,76 @@ +--- +id: 56533eb9ac21ba0edf2244b3 +title: Convert Celsius to Fahrenheit +challengeType: 1 +isRequired: true +--- + +## Description +
+The algorithm to convert from Celsius to Fahrenheit is the temperature in Celsius times 9/5, plus 32. +You are given a variable celsius representing a temperature in Celsius. Use the variable fahrenheit already defined and assign it the Fahrenheit temperature equivalent to the given Celsius temperature. Use the algorithm mentioned above to help convert the Celsius temperature to Fahrenheit. +Don't worry too much about the function and return statements as they will be covered in future challenges. For now, only use operators that you have already learned. +
+ +## Instructions +
+ +
+ +## Tests +
+ +```yml +- text: convertToF(0) should return a number + testString: 'assert(typeof convertToF(0) === "number", "convertToF(0) should return a number");' +- text: convertToF(-30) should return a value of -22 + testString: 'assert(convertToF(-30) === -22, "convertToF(-30) should return a value of -22");' +- text: convertToF(-10) should return a value of 14 + testString: 'assert(convertToF(-10) === 14, "convertToF(-10) should return a value of 14");' +- text: convertToF(0) should return a value of 32 + testString: 'assert(convertToF(0) === 32, "convertToF(0) should return a value of 32");' +- text: convertToF(20) should return a value of 68 + testString: 'assert(convertToF(20) === 68, "convertToF(20) should return a value of 68");' +- text: convertToF(30) should return a value of 86 + testString: 'assert(convertToF(30) === 86, "convertToF(30) should return a value of 86");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +function convertToF(celsius) { + let fahrenheit; + return fahrenheit; +} + +convertToF(30); +``` + +
+ + + +
+ +## Solution +
+ + +```js +function convertToF(celsius) { + let fahrenheit = celsius * 9/5 + 32; + + return fahrenheit; +} + +convertToF(30); + +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-algorithm-scripting/Factorialize a Number.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-algorithm-scripting/Factorialize a Number.md new file mode 100644 index 0000000000..50cd426392 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-algorithm-scripting/Factorialize a Number.md @@ -0,0 +1,74 @@ +--- +id: a302f7aae1aa3152a5b413bc +title: Factorialize a Number +isRequired: true +challengeType: 5 +--- + +## Description +
+Return the factorial of the provided integer. +If the integer is represented with the letter n, a factorial is the product of all positive integers less than or equal to n. +Factorials are often represented with the shorthand notation n! +For example: 5! = 1 * 2 * 3 * 4 * 5 = 120 +Only integers greater than or equal to zero will be supplied to the function. +Remember to use Read-Search-Ask if you get stuck. Write your own code. +
+ +## Instructions +
+ +
+ +## Tests +
+ +```yml +- text: factorialize(5) should return a number. + testString: 'assert(typeof factorialize(5) === "number", "factorialize(5) should return a number.");' +- text: factorialize(5) should return 120. + testString: 'assert(factorialize(5) === 120, "factorialize(5) should return 120.");' +- text: factorialize(10) should return 3628800. + testString: 'assert(factorialize(10) === 3628800, "factorialize(10) should return 3628800.");' +- text: factorialize(20) should return 2432902008176640000. + testString: 'assert(factorialize(20) === 2432902008176640000, "factorialize(20) should return 2432902008176640000.");' +- text: factorialize(0) should return 1. + testString: 'assert(factorialize(0) === 1, "factorialize(0) should return 1.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +function factorialize(num) { + return num; +} + +factorialize(5); +``` + +
+ + + +
+ +## Solution +
+ + +```js +function factorialize(num) { + return num < 1 ? 1 : num * factorialize(num - 1); +} + +factorialize(5); + +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-algorithm-scripting/Falsy Bouncer.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-algorithm-scripting/Falsy Bouncer.md new file mode 100644 index 0000000000..57ce71ac4b --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-algorithm-scripting/Falsy Bouncer.md @@ -0,0 +1,71 @@ +--- +id: adf08ec01beb4f99fc7a68f2 +title: Falsy Bouncer +isRequired: true +challengeType: 5 +--- + +## Description +
+Remove all falsy values from an array. +Falsy values in JavaScript are false, null, 0, "", undefined, and NaN. +Hint: Try converting each value to a Boolean. +Remember to use Read-Search-Ask if you get stuck. Write your own code. +
+ +## Instructions +
+ +
+ +## Tests +
+ +```yml +- text: 'bouncer([7, "ate", "", false, 9]) should return [7, "ate", 9].' + testString: 'assert.deepEqual(bouncer([7, "ate", "", false, 9]), [7, "ate", 9], "bouncer([7, "ate", "", false, 9]) should return [7, "ate", 9].");' +- text: 'bouncer(["a", "b", "c"]) should return ["a", "b", "c"].' + testString: 'assert.deepEqual(bouncer(["a", "b", "c"]), ["a", "b", "c"], "bouncer(["a", "b", "c"]) should return ["a", "b", "c"].");' +- text: 'bouncer([false, null, 0, NaN, undefined, ""]) should return [].' + testString: 'assert.deepEqual(bouncer([false, null, 0, NaN, undefined, ""]), [], "bouncer([false, null, 0, NaN, undefined, ""]) should return [].");' +- text: 'bouncer([1, null, NaN, 2, undefined]) should return [1, 2].' + testString: 'assert.deepEqual(bouncer([1, null, NaN, 2, undefined]), [1, 2], "bouncer([1, null, NaN, 2, undefined]) should return [1, 2].");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +function bouncer(arr) { + // Don't show a false ID to this bouncer. + return arr; +} + +bouncer([7, "ate", "", false, 9]); +``` + +
+ + + +
+ +## Solution +
+ + +```js +function bouncer(arr) { + return arr.filter(e => e); +} + +bouncer([7, "ate", "", false, 9]); + +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-algorithm-scripting/Find the Longest Word in a String.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-algorithm-scripting/Find the Longest Word in a String.md new file mode 100644 index 0000000000..d80cf8763f --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-algorithm-scripting/Find the Longest Word in a String.md @@ -0,0 +1,73 @@ +--- +id: a26cbbe9ad8655a977e1ceb5 +title: Find the Longest Word in a String +isRequired: true +challengeType: 5 +--- + +## Description +
+Return the length of the longest word in the provided sentence. +Your response should be a number. +Remember to use Read-Search-Ask if you get stuck. Write your own code. +
+ +## Instructions +
+ +
+ +## Tests +
+ +```yml +- text: findLongestWordLength("The quick brown fox jumped over the lazy dog") should return a number. + testString: 'assert(typeof findLongestWordLength("The quick brown fox jumped over the lazy dog") === "number", "findLongestWordLength("The quick brown fox jumped over the lazy dog") should return a number.");' +- text: findLongestWordLength("The quick brown fox jumped over the lazy dog") should return 6. + testString: 'assert(findLongestWordLength("The quick brown fox jumped over the lazy dog") === 6, "findLongestWordLength("The quick brown fox jumped over the lazy dog") should return 6.");' +- text: findLongestWordLength("May the force be with you") should return 5. + testString: 'assert(findLongestWordLength("May the force be with you") === 5, "findLongestWordLength("May the force be with you") should return 5.");' +- text: findLongestWordLength("Google do a barrel roll") should return 6. + testString: 'assert(findLongestWordLength("Google do a barrel roll") === 6, "findLongestWordLength("Google do a barrel roll") should return 6.");' +- text: findLongestWordLength("What is the average airspeed velocity of an unladen swallow") should return 8. + testString: 'assert(findLongestWordLength("What is the average airspeed velocity of an unladen swallow") === 8, "findLongestWordLength("What is the average airspeed velocity of an unladen swallow") should return 8.");' +- text: findLongestWordLength("What if we try a super-long word such as otorhinolaryngology") should return 19. + testString: 'assert(findLongestWordLength("What if we try a super-long word such as otorhinolaryngology") === 19, "findLongestWordLength("What if we try a super-long word such as otorhinolaryngology") should return 19.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +function findLongestWordLength(str) { + return str.length; +} + +findLongestWordLength("The quick brown fox jumped over the lazy dog"); +``` + +
+ + + +
+ +## Solution +
+ + +```js +function findLongestWordLength(str) { + return str.split(' ').sort((a, b) => b.length - a.length)[0].length; +} + +findLongestWordLength("The quick brown fox jumped over the lazy dog"); + +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-algorithm-scripting/Finders Keepers.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-algorithm-scripting/Finders Keepers.md new file mode 100644 index 0000000000..77e8d349d4 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-algorithm-scripting/Finders Keepers.md @@ -0,0 +1,74 @@ +--- +id: a6e40f1041b06c996f7b2406 +title: Finders Keepers +isRequired: true +challengeType: 5 +--- + +## Description +
+Create a function that looks through an array (first argument) and returns the first element in the array that passes a truth test (second argument). If no element passes the test, return undefined. +Remember to use Read-Search-Ask if you get stuck. Try to pair program. Write your own code. +
+ +## Instructions +
+ +
+ +## Tests +
+ +```yml +- text: 'findElement([1, 3, 5, 8, 9, 10], function(num) { return num % 2 === 0; }) should return 8.' + testString: 'assert.strictEqual(findElement([1, 3, 5, 8, 9, 10], function(num) { return num % 2 === 0; }), 8, "findElement([1, 3, 5, 8, 9, 10], function(num) { return num % 2 === 0; }) should return 8.");' +- text: 'findElement([1, 3, 5, 9], function(num) { return num % 2 === 0; }) should return undefined.' + testString: 'assert.strictEqual(findElement([1, 3, 5, 9], function(num) { return num % 2 === 0; }), undefined, "findElement([1, 3, 5, 9], function(num) { return num % 2 === 0; }) should return undefined.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +function findElement(arr, func) { + let num = 0; + return num; +} + +findElement([1, 2, 3, 4], num => num % 2 === 0); +``` + +
+ + + +
+ +## Solution +
+ + +```js +function findElement(arr, func) { + let num; + + arr.some(e => { + if (func(e)) { + num = e; + return true; + } + }); + + return num; +} + +findElement([1, 2, 3, 4], num => num % 2 === 0); + +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-algorithm-scripting/Mutations.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-algorithm-scripting/Mutations.md new file mode 100644 index 0000000000..eac62afc2a --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-algorithm-scripting/Mutations.md @@ -0,0 +1,85 @@ +--- +id: af2170cad53daa0770fabdea +title: Mutations +isRequired: true +challengeType: 5 +--- + +## Description +
+Return true if the string in the first element of the array contains all of the letters of the string in the second element of the array. +For example, ["hello", "Hello"], should return true because all of the letters in the second string are present in the first, ignoring case. +The arguments ["hello", "hey"] should return false because the string "hello" does not contain a "y". +Lastly, ["Alien", "line"], should return true because all of the letters in "line" are present in "Alien". +Remember to use Read-Search-Ask if you get stuck. Write your own code. +
+ +## Instructions +
+ +
+ +## Tests +
+ +```yml +- text: 'mutation(["hello", "hey"]) should return false.' + testString: 'assert(mutation(["hello", "hey"]) === false, "mutation(["hello", "hey"]) should return false.");' +- text: 'mutation(["hello", "Hello"]) should return true.' + testString: 'assert(mutation(["hello", "Hello"]) === true, "mutation(["hello", "Hello"]) should return true.");' +- text: 'mutation(["zyxwvutsrqponmlkjihgfedcba", "qrstu"]) should return true.' + testString: 'assert(mutation(["zyxwvutsrqponmlkjihgfedcba", "qrstu"]) === true, "mutation(["zyxwvutsrqponmlkjihgfedcba", "qrstu"]) should return true.");' +- text: 'mutation(["Mary", "Army"]) should return true.' + testString: 'assert(mutation(["Mary", "Army"]) === true, "mutation(["Mary", "Army"]) should return true.");' +- text: 'mutation(["Mary", "Aarmy"]) should return true.' + testString: 'assert(mutation(["Mary", "Aarmy"]) === true, "mutation(["Mary", "Aarmy"]) should return true.");' +- text: 'mutation(["Alien", "line"]) should return true.' + testString: 'assert(mutation(["Alien", "line"]) === true, "mutation(["Alien", "line"]) should return true.");' +- text: 'mutation(["floor", "for"]) should return true.' + testString: 'assert(mutation(["floor", "for"]) === true, "mutation(["floor", "for"]) should return true.");' +- text: 'mutation(["hello", "neo"]) should return false.' + testString: 'assert(mutation(["hello", "neo"]) === false, "mutation(["hello", "neo"]) should return false.");' +- text: 'mutation(["voodoo", "no"]) should return false.' + testString: 'assert(mutation(["voodoo", "no"]) === false, "mutation(["voodoo", "no"]) should return false.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +function mutation(arr) { + return arr; +} + +mutation(["hello", "hey"]); +``` + +
+ + + +
+ +## Solution +
+ + +```js +function mutation(arr) { + let hash = Object.create(null); + + arr[0].toLowerCase().split(").forEach(c => hash[c] = true); + + return !arr[1].toLowerCase().split(").filter(c => !hash[c]).length; +} + +mutation(["hello", "hey"]); + +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-algorithm-scripting/Repeat a String Repeat a String.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-algorithm-scripting/Repeat a String Repeat a String.md new file mode 100644 index 0000000000..99e204eb04 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-algorithm-scripting/Repeat a String Repeat a String.md @@ -0,0 +1,76 @@ +--- +id: afcc8d540bea9ea2669306b6 +title: Repeat a String Repeat a String +isRequired: true +challengeType: 5 +--- + +## Description +
+Repeat a given string str (first argument) for num times (second argument). Return an empty string if num is not a positive number. +Remember to use Read-Search-Ask if you get stuck. Write your own code. +
+ +## Instructions +
+ +
+ +## Tests +
+ +```yml +- text: 'repeatStringNumTimes("*", 3) should return "***".' + testString: 'assert(repeatStringNumTimes("*", 3) === "***", "repeatStringNumTimes("*", 3) should return "***".");' +- text: 'repeatStringNumTimes("abc", 3) should return "abcabcabc".' + testString: 'assert(repeatStringNumTimes("abc", 3) === "abcabcabc", "repeatStringNumTimes("abc", 3) should return "abcabcabc".");' +- text: 'repeatStringNumTimes("abc", 4) should return "abcabcabcabc".' + testString: 'assert(repeatStringNumTimes("abc", 4) === "abcabcabcabc", "repeatStringNumTimes("abc", 4) should return "abcabcabcabc".");' +- text: 'repeatStringNumTimes("abc", 1) should return "abc".' + testString: 'assert(repeatStringNumTimes("abc", 1) === "abc", "repeatStringNumTimes("abc", 1) should return "abc".");' +- text: 'repeatStringNumTimes("*", 8) should return "********".' + testString: 'assert(repeatStringNumTimes("*", 8) === "********", "repeatStringNumTimes("*", 8) should return "********".");' +- text: 'repeatStringNumTimes("abc", -2) should return "".' + testString: 'assert(repeatStringNumTimes("abc", -2) === "", "repeatStringNumTimes("abc", -2) should return "".");' +- text: The built-in repeat()-method should not be used + testString: 'assert(!/\.repeat/g.test(code), "The built-in repeat()-method should not be used");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +function repeatStringNumTimes(str, num) { + // repeat after me + return str; +} + +repeatStringNumTimes("abc", 3); +``` + +
+ + + +
+ +## Solution +
+ + +```js +function repeatStringNumTimes(str, num) { + if (num < 0) return "; + return num === 1 ? str : str + repeatStringNumTimes(str, num-1); +} + +repeatStringNumTimes("abc", 3); + +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-algorithm-scripting/Return Largest Numbers in Arrays.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-algorithm-scripting/Return Largest Numbers in Arrays.md new file mode 100644 index 0000000000..2dff6f74cc --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-algorithm-scripting/Return Largest Numbers in Arrays.md @@ -0,0 +1,70 @@ +--- +id: a789b3483989747d63b0e427 +title: Return Largest Numbers in Arrays +isRequired: true +challengeType: 5 +--- + +## Description +
+Return an array consisting of the largest number from each provided sub-array. For simplicity, the provided array will contain exactly 4 sub-arrays. +Remember, you can iterate through an array with a simple for loop, and access each member with array syntax arr[i]. +Remember to use Read-Search-Ask if you get stuck. Write your own code. +
+ +## Instructions +
+ +
+ +## Tests +
+ +```yml +- text: 'largestOfFour([[4, 5, 1, 3], [13, 27, 18, 26], [32, 35, 37, 39], [1000, 1001, 857, 1]]) should return an array.' + testString: 'assert(largestOfFour([[4, 5, 1, 3], [13, 27, 18, 26], [32, 35, 37, 39], [1000, 1001, 857, 1]]).constructor === Array, "largestOfFour([[4, 5, 1, 3], [13, 27, 18, 26], [32, 35, 37, 39], [1000, 1001, 857, 1]]) should return an array.");' +- text: 'largestOfFour([[13, 27, 18, 26], [4, 5, 1, 3], [32, 35, 37, 39], [1000, 1001, 857, 1]]) should return [27, 5, 39, 1001].' + testString: 'assert.deepEqual(largestOfFour([[13, 27, 18, 26], [4, 5, 1, 3], [32, 35, 37, 39], [1000, 1001, 857, 1]]), [27, 5, 39, 1001], "largestOfFour([[13, 27, 18, 26], [4, 5, 1, 3], [32, 35, 37, 39], [1000, 1001, 857, 1]]) should return [27, 5, 39, 1001].");' +- text: 'largestOfFour([[4, 9, 1, 3], [13, 35, 18, 26], [32, 35, 97, 39], [1000000, 1001, 857, 1]]) should return [9, 35, 97, 1000000].' + testString: 'assert.deepEqual(largestOfFour([[4, 9, 1, 3], [13, 35, 18, 26], [32, 35, 97, 39], [1000000, 1001, 857, 1]]), [9, 35, 97, 1000000], "largestOfFour([[4, 9, 1, 3], [13, 35, 18, 26], [32, 35, 97, 39], [1000000, 1001, 857, 1]]) should return [9, 35, 97, 1000000].");' +- text: 'largestOfFour([[17, 23, 25, 12], [25, 7, 34, 48], [4, -10, 18, 21], [-72, -3, -17, -10]]) should return [25, 48, 21, -3].' + testString: 'assert.deepEqual(largestOfFour([[17, 23, 25, 12], [25, 7, 34, 48], [4, -10, 18, 21], [-72, -3, -17, -10]]), [25, 48, 21, -3], "largestOfFour([[17, 23, 25, 12], [25, 7, 34, 48], [4, -10, 18, 21], [-72, -3, -17, -10]]) should return [25, 48, 21, -3].");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +function largestOfFour(arr) { + // You can do this! + return arr; +} + +largestOfFour([[4, 5, 1, 3], [13, 27, 18, 26], [32, 35, 37, 39], [1000, 1001, 857, 1]]); +``` + +
+ + + +
+ +## Solution +
+ + +```js +function largestOfFour(arr) { + return arr.map(subArr => Math.max.apply(null, subArr)); +} + +largestOfFour([[4, 5, 1, 3], [13, 27, 18, 26], [32, 35, 37, 39], [1000, 1001, 857, 1]]); + +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-algorithm-scripting/Reverse a String.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-algorithm-scripting/Reverse a String.md new file mode 100644 index 0000000000..e95b40c477 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-algorithm-scripting/Reverse a String.md @@ -0,0 +1,70 @@ +--- +id: a202eed8fc186c8434cb6d61 +title: Reverse a String +isRequired: true +challengeType: 5 +--- + +## Description +
+Reverse the provided string. +You may need to turn the string into an array before you can reverse it. +Your result must be a string. +Remember to use Read-Search-Ask if you get stuck. Write your own code. +
+ +## Instructions +
+ +
+ +## Tests +
+ +```yml +- text: reverseString("hello") should return a string. + testString: 'assert(typeof reverseString("hello") === "string", "reverseString("hello") should return a string.");' +- text: reverseString("hello") should become "olleh". + testString: 'assert(reverseString("hello") === "olleh", "reverseString("hello") should become "olleh".");' +- text: reverseString("Howdy") should become "ydwoH". + testString: 'assert(reverseString("Howdy") === "ydwoH", "reverseString("Howdy") should become "ydwoH".");' +- text: reverseString("Greetings from Earth") should return "htraE morf sgniteerG". + testString: 'assert(reverseString("Greetings from Earth") === "htraE morf sgniteerG", "reverseString("Greetings from Earth") should return "htraE morf sgniteerG".");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +function reverseString(str) { + return str; +} + +reverseString("hello"); +``` + +
+ + + +
+ +## Solution +
+ + +```js +function reverseString(str) { + return str.split(").reverse().join("); +} + +reverseString("hello"); + +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-algorithm-scripting/Slice and Splice.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-algorithm-scripting/Slice and Splice.md new file mode 100644 index 0000000000..6a4c34eba9 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-algorithm-scripting/Slice and Splice.md @@ -0,0 +1,90 @@ +--- +id: 579e2a2c335b9d72dd32e05c +title: Slice and Splice +isRequired: true +isBeta: true +challengeType: 5 +--- + +## Description +
+You are given two arrays and an index. +Use the array methods slice and splice to copy each element of the first array into the second array, in order. +Begin inserting elements at index n of the second array. +Return the resulting array. The input arrays should remain the same after the function runs. +Remember to use Read-Search-Ask if you get stuck. Write your own code. +
+ +## Instructions +
+ +
+ +## Tests +
+ +```yml +- text: 'frankenSplice([1, 2, 3], [4, 5], 1) should return [4, 1, 2, 3, 5].' + testString: 'assert.deepEqual(frankenSplice([1, 2, 3], [4, 5], 1), [4, 1, 2, 3, 5], "frankenSplice([1, 2, 3], [4, 5], 1) should return [4, 1, 2, 3, 5].");' +- text: 'frankenSplice([1, 2], ["a", "b"], 1) should return ["a", 1, 2, "b"].' + testString: 'assert.deepEqual(frankenSplice(testArr1, testArr2, 1), ["a", 1, 2, "b"], "frankenSplice([1, 2], ["a", "b"], 1) should return ["a", 1, 2, "b"].");' +- text: 'frankenSplice(["claw", "tentacle"], ["head", "shoulders", "knees", "toes"], 2) should return ["head", "shoulders", "claw", "tentacle", "knees", "toes"].' + testString: 'assert.deepEqual(frankenSplice(["claw", "tentacle"], ["head", "shoulders", "knees", "toes"], 2), ["head", "shoulders", "claw", "tentacle", "knees", "toes"], "frankenSplice(["claw", "tentacle"], ["head", "shoulders", "knees", "toes"], 2) should return ["head", "shoulders", "claw", "tentacle", "knees", "toes"].");' +- text: All elements from the first array should be added to the second array in their original order. + testString: 'assert.deepEqual(frankenSplice([1, 2, 3, 4], [], 0), [1, 2, 3, 4], "All elements from the first array should be added to the second array in their original order.");' +- text: The first array should remain the same after the function runs. + testString: 'assert(testArr1[0] === 1 && testArr1[1] === 2, "The first array should remain the same after the function runs.");' +- text: The second array should remain the same after the function runs. + testString: 'assert(testArr2[0] === "a" && testArr2[1] === "b", "The second array should remain the same after the function runs.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +function frankenSplice(arr1, arr2, n) { + // It's alive. It's alive! + return arr2; +} + +frankenSplice([1, 2, 3], [4, 5, 6], 1); +``` + +
+ + +### After Test +
+ +```js +console.info('after the test'); +``` + +
+ +
+ +## Solution +
+ + +```js +function frankenSplice(arr1, arr2, n) { + // It's alive. It's alive! + let result = arr2.slice(); + for (let i = 0; i < arr1.length; i++) { + result.splice(n+i, 0, arr1[i]); + } + return result; +} + +frankenSplice([1, 2, 3], [4, 5], 1); + +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-algorithm-scripting/Title Case a Sentence.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-algorithm-scripting/Title Case a Sentence.md new file mode 100644 index 0000000000..4604fade08 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-algorithm-scripting/Title Case a Sentence.md @@ -0,0 +1,69 @@ +--- +id: ab6137d4e35944e21037b769 +title: Title Case a Sentence +isRequired: true +challengeType: 5 +--- + +## Description +
+Return the provided string with the first letter of each word capitalized. Make sure the rest of the word is in lower case. +For the purpose of this exercise, you should also capitalize connecting words like "the" and "of". +Remember to use Read-Search-Ask if you get stuck. Write your own code. +
+ +## Instructions +
+ +
+ +## Tests +
+ +```yml +- text: 'titleCase("I'm a little tea pot") should return a string.' + testString: 'assert(typeof titleCase("I"m a little tea pot") === "string", "titleCase("I'm a little tea pot") should return a string.");' +- text: 'titleCase("I'm a little tea pot") should return I'm A Little Tea Pot.' + testString: 'assert(titleCase("I"m a little tea pot") === "I"m A Little Tea Pot", "titleCase("I'm a little tea pot") should return I'm A Little Tea Pot.");' +- text: titleCase("sHoRt AnD sToUt") should return Short And Stout. + testString: 'assert(titleCase("sHoRt AnD sToUt") === "Short And Stout", "titleCase("sHoRt AnD sToUt") should return Short And Stout.");' +- text: titleCase("HERE IS MY HANDLE HERE IS MY SPOUT") should return Here Is My Handle Here Is My Spout. + testString: 'assert(titleCase("HERE IS MY HANDLE HERE IS MY SPOUT") === "Here Is My Handle Here Is My Spout", "titleCase("HERE IS MY HANDLE HERE IS MY SPOUT") should return Here Is My Handle Here Is My Spout.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +function titleCase(str) { + return str; +} + +titleCase("I'm a little tea pot"); +``` + +
+ + + +
+ +## Solution +
+ + +```js +function titleCase(str) { + return str.split(' ').map(word => word.charAt(0).toUpperCase() + word.substring(1).toLowerCase()).join(' '); +} + +titleCase("I'm a little tea pot"); + +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-algorithm-scripting/Truncate a String.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-algorithm-scripting/Truncate a String.md new file mode 100644 index 0000000000..50f1e7637e --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-algorithm-scripting/Truncate a String.md @@ -0,0 +1,77 @@ +--- +id: ac6993d51946422351508a41 +title: Truncate a String +isRequired: true +challengeType: 5 +--- + +## Description +
+Truncate a string (first argument) if it is longer than the given maximum string length (second argument). Return the truncated string with a ... ending. +Remember to use Read-Search-Ask if you get stuck. Write your own code. +
+ +## Instructions +
+ +
+ +## Tests +
+ +```yml +- text: 'truncateString("A-tisket a-tasket A green and yellow basket", 8) should return "A-tisket...".' + testString: 'assert(truncateString("A-tisket a-tasket A green and yellow basket", 8) === "A-tisket...", "truncateString("A-tisket a-tasket A green and yellow basket", 8) should return "A-tisket...".");' +- text: 'truncateString("Peter Piper picked a peck of pickled peppers", 11) should return "Peter Piper...".' + testString: 'assert(truncateString("Peter Piper picked a peck of pickled peppers", 11) === "Peter Piper...", "truncateString("Peter Piper picked a peck of pickled peppers", 11) should return "Peter Piper...".");' +- text: 'truncateString("A-tisket a-tasket A green and yellow basket", "A-tisket a-tasket A green and yellow basket".length) should return "A-tisket a-tasket A green and yellow basket".' + testString: 'assert(truncateString("A-tisket a-tasket A green and yellow basket", "A-tisket a-tasket A green and yellow basket".length) === "A-tisket a-tasket A green and yellow basket", "truncateString("A-tisket a-tasket A green and yellow basket", "A-tisket a-tasket A green and yellow basket".length) should return "A-tisket a-tasket A green and yellow basket".");' +- text: 'truncateString("A-tisket a-tasket A green and yellow basket", "A-tisket a-tasket A green and yellow basket".length + 2) should return "A-tisket a-tasket A green and yellow basket".' + testString: 'assert(truncateString("A-tisket a-tasket A green and yellow basket", "A-tisket a-tasket A green and yellow basket".length + 2) === "A-tisket a-tasket A green and yellow basket", "truncateString("A-tisket a-tasket A green and yellow basket", "A-tisket a-tasket A green and yellow basket".length + 2) should return "A-tisket a-tasket A green and yellow basket".");' +- text: 'truncateString("A-", 1) should return "A...".' + testString: 'assert(truncateString("A-", 1) === "A...", "truncateString("A-", 1) should return "A...".");' +- text: 'truncateString("Absolutely Longer", 2) should return "Ab...".' + testString: 'assert(truncateString("Absolutely Longer", 2) === "Ab...", "truncateString("Absolutely Longer", 2) should return "Ab...".");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +function truncateString(str, num) { + // Clear out that junk in your trunk + return str; +} + +truncateString("A-tisket a-tasket A green and yellow basket", 8); +``` + +
+ + + +
+ +## Solution +
+ + +```js +function truncateString(str, num) { + if (num >= str.length) { + return str; + } + + return str.slice(0, num) + '...'; +} + +truncateString("A-tisket a-tasket A green and yellow basket", 8); + +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-algorithm-scripting/Where do I Belong.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-algorithm-scripting/Where do I Belong.md new file mode 100644 index 0000000000..9ec8b1e202 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-algorithm-scripting/Where do I Belong.md @@ -0,0 +1,103 @@ +--- +id: a24c1a4622e3c05097f71d67 +title: Where do I Belong +isRequired: true +challengeType: 5 +--- + +## Description +
+Return the lowest index at which a value (second argument) should be inserted into an array (first argument) once it has been sorted. The returned value should be a number. +For example, getIndexToIns([1,2,3,4], 1.5) should return 1 because it is greater than 1 (index 0), but less than 2 (index 1). +Likewise, getIndexToIns([20,3,5], 19) should return 2 because once the array has been sorted it will look like [3,5,20] and 19 is less than 20 (index 2) and greater than 5 (index 1). +Remember to use Read-Search-Ask if you get stuck. Write your own code. +
+ +## Instructions +
+ +
+ +## Tests +
+ +```yml +- text: 'getIndexToIns([10, 20, 30, 40, 50], 35) should return 3.' + testString: 'assert(getIndexToIns([10, 20, 30, 40, 50], 35) === 3, "getIndexToIns([10, 20, 30, 40, 50], 35) should return 3.");' +- text: 'getIndexToIns([10, 20, 30, 40, 50], 35) should return a number.' + testString: 'assert(typeof(getIndexToIns([10, 20, 30, 40, 50], 35)) === "number", "getIndexToIns([10, 20, 30, 40, 50], 35) should return a number.");' +- text: 'getIndexToIns([10, 20, 30, 40, 50], 30) should return 2.' + testString: 'assert(getIndexToIns([10, 20, 30, 40, 50], 30) === 2, "getIndexToIns([10, 20, 30, 40, 50], 30) should return 2.");' +- text: 'getIndexToIns([10, 20, 30, 40, 50], 30) should return a number.' + testString: 'assert(typeof(getIndexToIns([10, 20, 30, 40, 50], 30)) === "number", "getIndexToIns([10, 20, 30, 40, 50], 30) should return a number.");' +- text: 'getIndexToIns([40, 60], 50) should return 1.' + testString: 'assert(getIndexToIns([40, 60], 50) === 1, "getIndexToIns([40, 60], 50) should return 1.");' +- text: 'getIndexToIns([40, 60], 50) should return a number.' + testString: 'assert(typeof(getIndexToIns([40, 60], 50)) === "number", "getIndexToIns([40, 60], 50) should return a number.");' +- text: 'getIndexToIns([3, 10, 5], 3) should return 0.' + testString: 'assert(getIndexToIns([3, 10, 5], 3) === 0, "getIndexToIns([3, 10, 5], 3) should return 0.");' +- text: 'getIndexToIns([3, 10, 5], 3) should return a number.' + testString: 'assert(typeof(getIndexToIns([3, 10, 5], 3)) === "number", "getIndexToIns([3, 10, 5], 3) should return a number.");' +- text: 'getIndexToIns([5, 3, 20, 3], 5) should return 2.' + testString: 'assert(getIndexToIns([5, 3, 20, 3], 5) === 2, "getIndexToIns([5, 3, 20, 3], 5) should return 2.");' +- text: 'getIndexToIns([5, 3, 20, 3], 5) should return a number.' + testString: 'assert(typeof(getIndexToIns([5, 3, 20, 3], 5)) === "number", "getIndexToIns([5, 3, 20, 3], 5) should return a number.");' +- text: 'getIndexToIns([2, 20, 10], 19) should return 2.' + testString: 'assert(getIndexToIns([2, 20, 10], 19) === 2, "getIndexToIns([2, 20, 10], 19) should return 2.");' +- text: 'getIndexToIns([2, 20, 10], 19) should return a number.' + testString: 'assert(typeof(getIndexToIns([2, 20, 10], 19)) === "number", "getIndexToIns([2, 20, 10], 19) should return a number.");' +- text: 'getIndexToIns([2, 5, 10], 15) should return 3.' + testString: 'assert(getIndexToIns([2, 5, 10], 15) === 3, "getIndexToIns([2, 5, 10], 15) should return 3.");' +- text: 'getIndexToIns([2, 5, 10], 15) should return a number.' + testString: 'assert(typeof(getIndexToIns([2, 5, 10], 15)) === "number", "getIndexToIns([2, 5, 10], 15) should return a number.");' +- text: 'getIndexToIns([], 1) should return 0.' + testString: 'assert(getIndexToIns([], 1) === 0, "getIndexToIns([], 1) should return 0.");' +- text: 'getIndexToIns([], 1) should return a number.' + testString: 'assert(typeof(getIndexToIns([], 1)) === "number", "getIndexToIns([], 1) should return a number.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +function getIndexToIns(arr, num) { + // Find my place in this sorted array. + return num; +} + +getIndexToIns([40, 60], 50); +``` + +
+ + + +
+ +## Solution +
+ + +```js +function getIndexToIns(arr, num) { + arr = arr.sort((a, b) => a - b); + + for (let i = 0; i < arr.length; i++) { + if (arr[i] >= num) { + return i; + } + } + + return arr.length; +} + +getIndexToIns([40, 60], 50); + +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-algorithm-scripting/meta.json b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-algorithm-scripting/meta.json new file mode 100644 index 0000000000..63ec8f0e86 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-algorithm-scripting/meta.json @@ -0,0 +1,8 @@ +{ + "name": "Basic Algorithm Scripting", + "dashedName": "basic-algorithm-scripting", + "order": 6, + "time": "50 hours", + "superBlock": "javascript-algorithms-and-data-structures", + "superOrder": 2 +} \ No newline at end of file diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-data-structures/ Iterate Through the Keys of an Object with a for...in Statement.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-data-structures/ Iterate Through the Keys of an Object with a for...in Statement.md new file mode 100644 index 0000000000..f5ce628425 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-data-structures/ Iterate Through the Keys of an Object with a for...in Statement.md @@ -0,0 +1,79 @@ +--- +id: 587d7b7d367417b2b2512b1d +title: ' Iterate Through the Keys of an Object with a for...in Statement' +challengeType: 1 +--- + +## Description +
+Sometimes you may need to iterate through all the keys within an object. This requires a specific syntax in JavaScript called a for...in statement. For our users object, this could look like: +
for (let user in users) {
  console.log(user);
};

// logs:
Alan
Jeff
Sarah
Ryan
+In this statement, we defined a variable user, and as you can see, this variable was reset during each iteration to each of the object's keys as the statement looped through the object, resulting in each user's name being printed to the console. +NOTE:
Objects do not maintain an ordering to stored keys like arrays do; thus a keys position on an object, or the relative order in which it appears, is irrelevant when referencing or accessing that key. +
+ +## Instructions +
+We've defined a function, countOnline; use a for...in statement within this function to loop through the users in the users object and return the number of users whose online property is set to true. +
+ +## Tests +
+ +```yml +- text: The users object contains users Jeff and Ryan with online set to true and users Alan and Sarah with online set to false + testString: 'assert(users.Alan.online === false && users.Jeff.online === true && users.Sarah.online === false && users.Ryan.online === true, "The users object contains users Jeff and Ryan with online set to true and users Alan and Sarah with online set to false");' +- text: The function countOnline returns the number of users with the online property set to true + testString: 'assert((function() { users.Harry = {online: true}; users.Sam = {online: true}; users.Carl = {online: true}; return countOnline(users) })() === 5, "The function countOnline returns the number of users with the online property set to true");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +let users = { + Alan: { + age: 27, + online: false + }, + Jeff: { + age: 32, + online: true + }, + Sarah: { + age: 48, + online: false + }, + Ryan: { + age: 19, + online: true + } +}; + +function countOnline(obj) { + // change code below this line + + // change code above this line +} + +console.log(countOnline(users)); +``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-data-structures/Access Property Names with Bracket Notation.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-data-structures/Access Property Names with Bracket Notation.md new file mode 100644 index 0000000000..176010bb62 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-data-structures/Access Property Names with Bracket Notation.md @@ -0,0 +1,75 @@ +--- +id: 587d7b7c367417b2b2512b1a +title: Access Property Names with Bracket Notation +challengeType: 1 +--- + +## Description +
+In the first object challenge we mentioned the use of bracket notation as a way to access property values using the evaluation of a variable. For instance, imagine that our foods object is being used in a program for a supermarket cash register. We have some function that sets the selectedFood and we want to check our foods object for the presence of that food. This might look like: +
let selectedFood = getCurrentFood(scannedItem);
let inventory = foods[selectedFood];
+This code will evaluate the value stored in the selectedFood variable and return the value of that key in the foods object, or undefined if it is not present. Bracket notation is very useful because sometimes object properties are not known before runtime or we need to access them in a more dynamic way. +
+ +## Instructions +
+We've defined a function, checkInventory, which receives a scanned item as an argument. Return the current value of the scannedItem key in the foods object. You can assume that only valid keys will be provided as an argument to checkInventory. +
+ +## Tests +
+ +```yml +- text: checkInventory is a function + testString: 'assert.strictEqual(typeof checkInventory, "function", "checkInventory is a function");' +- text: 'The foods object should have only the following key-value pairs: apples: 25, oranges: 32, plums: 28, bananas: 13, grapes: 35, strawberries: 27' + testString: 'assert.deepEqual(foods, {apples: 25, oranges: 32, plums: 28, bananas: 13, grapes: 35, strawberries: 27}, "The foods object should have only the following key-value pairs: apples: 25, oranges: 32, plums: 28, bananas: 13, grapes: 35, strawberries: 27");' +- text: checkInventory("apples") should return 25 + testString: 'assert.strictEqual(checkInventory("apples"), 25, "checkInventory("apples") should return 25");' +- text: checkInventory("bananas") should return 13 + testString: 'assert.strictEqual(checkInventory("bananas"), 13, "checkInventory("bananas") should return 13");' +- text: checkInventory("strawberries") should return 27 + testString: 'assert.strictEqual(checkInventory("strawberries"), 27, "checkInventory("strawberries") should return 27");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +let foods = { + apples: 25, + oranges: 32, + plums: 28, + bananas: 13, + grapes: 35, + strawberries: 27 +}; +// do not change code above this line + +function checkInventory(scannedItem) { + // change code below this line + +} + +// change code below this line to test different cases: +console.log(checkInventory("apples")); +``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-data-structures/Access an Array's Contents Using Bracket Notation.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-data-structures/Access an Array's Contents Using Bracket Notation.md new file mode 100644 index 0000000000..c37c2b2524 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-data-structures/Access an Array's Contents Using Bracket Notation.md @@ -0,0 +1,68 @@ +--- +id: 5a661e0f1068aca922b3ef17 +title: Access an Array's Contents Using Bracket Notation +challengeType: 1 +--- + +## Description +
+The fundamental feature of any data structure is, of course, the ability to not only store data, but to be able to retrieve that data on command. So, now that we've learned how to create an array, let's begin to think about how we can access that array's information. +When we define a simple array as seen below, there are 3 items in it: +
let ourArray = ["a", "b", "c"];
+In an array, each array item has an index. This index doubles as the position of that item in the array, and how you reference it. However, it is important to note, that JavaScript arrays are zero-indexed, meaning that the first element of an array is actually at the zeroth position, not the first. +In order to retrieve an element from an array we can enclose an index in brackets and append it to the end of an array, or more commonly, to a variable which references an array object. This is known as bracket notation. +For example, if we want to retrieve the "a" from ourArray and assign it to a variable, we can do so with the following code: +
let ourVariable = ourArray[0];
// ourVariable equals "a"
+In addition to accessing the value associated with an index, you can also set an index to a value using the same notation: +
ourArray[1] = "not b anymore";
// ourArray now equals ["a", "not b anymore", "c"];
+Using bracket notation, we have now reset the item at index 1 from "b", to "not b anymore". +
+ +## Instructions +
+In order to complete this challenge, set the 2nd position (index 1) of myArray to anything you want, besides "b". +
+ +## Tests +
+ +```yml +- text: 'myArray[0] is equal to "a"' + testString: 'assert.strictEqual(myArray[0], "a", "myArray[0] is equal to "a"");' +- text: 'myArray[1] is no longer set to "b"' + testString: 'assert.notStrictEqual(myArray[1], "b", "myArray[1] is no longer set to "b"");' +- text: 'myArray[2] is equal to "c"' + testString: 'assert.strictEqual(myArray[2], "c", "myArray[2] is equal to "c"");' +- text: 'myArray[3] is equal to "d"' + testString: 'assert.strictEqual(myArray[3], "d", "myArray[3] is equal to "d"");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +let myArray = ["a", "b", "c", "d"]; +// change code below this line + +//change code above this line +console.log(myArray); +``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-data-structures/Add Items Using splice().md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-data-structures/Add Items Using splice().md new file mode 100644 index 0000000000..0f0121ef7a --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-data-structures/Add Items Using splice().md @@ -0,0 +1,65 @@ +--- +id: 587d78b3367417b2b2512b11 +title: Add Items Using splice() +challengeType: 1 +--- + +## Description +
+Remember in the last challenge we mentioned that splice() can take up to three parameters? Well, we can go one step further with splice() — in addition to removing elements, we can use that third parameter, which represents one or more elements, to add them as well. This can be incredibly useful for quickly switching out an element, or a set of elements, for another. For instance, let's say you're storing a color scheme for a set of DOM elements in an array, and want to dynamically change a color based on some action: +
function colorChange(arr, index, newColor) {
  arr.splice(index, 1, newColor);
  return arr;
}

let colorScheme = ['#878787', '#a08794', '#bb7e8c', '#c9b6be', '#d1becf'];

colorScheme = colorChange(colorScheme, 2, '#332327');
// we have removed '#bb7e8c' and added '#332327' in its place
// colorScheme now equals ['#878787', '#a08794', '#332327', '#c9b6be', '#d1becf']
+This function takes an array of hex values, an index at which to remove an element, and the new color to replace the removed element with. The return value is an array containing a newly modified color scheme! While this example is a bit oversimplified, we can see the value that utilizing splice() to its maximum potential can have. +
+ +## Instructions +
+We have defined a function, htmlColorNames, which takes an array of HTML colors as an argument. Modify the function using splice() to remove the first two elements of the array and add 'DarkSalmon' and 'BlanchedAlmond' in their respective places. +
+ +## Tests +
+ +```yml +- text: 'htmlColorNames should return ["DarkSalmon", "BlanchedAlmond", "LavenderBlush", "PaleTurqoise", "FireBrick"]' + testString: 'assert.deepEqual(htmlColorNames(["DarkGoldenRod", "WhiteSmoke", "LavenderBlush", "PaleTurqoise", "FireBrick"]), ["DarkSalmon", "BlanchedAlmond", "LavenderBlush", "PaleTurqoise", "FireBrick"], "htmlColorNames should return ["DarkSalmon", "BlanchedAlmond", "LavenderBlush", "PaleTurqoise", "FireBrick"]");' +- text: The htmlColorNames function should utilize the splice() method + testString: 'assert(/.splice/.test(code), "The htmlColorNames function should utilize the splice() method");' +- text: You should not use shift() or unshift(). + testString: 'assert(!/shift|unshift/.test(code), "You should not use shift() or unshift().");' +- text: You should not use array bracket notation. + testString: 'assert(!/\[\d\]\s*=/.test(code), "You should not use array bracket notation.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +function htmlColorNames(arr) { + // change code below this line + + // change code above this line + return arr; +} + +// do not change code below this line +console.log(htmlColorNames(['DarkGoldenRod', 'WhiteSmoke', 'LavenderBlush', 'PaleTurqoise', 'FireBrick'])); +``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-data-structures/Add Items to an Array with push() and unshift().md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-data-structures/Add Items to an Array with push() and unshift().md new file mode 100644 index 0000000000..5b4afef3b7 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-data-structures/Add Items to an Array with push() and unshift().md @@ -0,0 +1,64 @@ +--- +id: 587d78b2367417b2b2512b0e +title: Add Items to an Array with push() and unshift() +challengeType: 1 +--- + +## Description +
+An array's length, like the data types it can contain, is not fixed. Arrays can be defined with a length of any number of elements, and elements can be added or removed over time; in other words, arrays are mutable. In this challenge, we will look at two methods with which we can programmatically modify an array: Array.push() and Array.unshift(). +Both methods take one or more elements as parameters and add those elements to the array the method is being called on; the push() method adds elements to the end of an array, and unshift() adds elements to the beginning. Consider the following: +
let twentyThree = 'XXIII';
let romanNumerals = ['XXI', 'XXII'];

romanNumerals.unshift('XIX', 'XX');
// now equals ['XIX', 'XX', 'XXI', 'XXII']

romanNumerals.push(twentyThree);
// now equals ['XIX', 'XX', 'XXI', 'XXII', 'XXIII'] +Notice that we can also pass variables, which allows us even greater flexibility in dynamically modifying our array's data. +
+ +## Instructions +
+We have defined a function, mixedNumbers, which we are passing an array as an argument. Modify the function by using push() and unshift() to add 'I', 2, 'three' to the beginning of the array and 7, 'VIII', 9 to the end so that the returned array contains representations of the numbers 1-9 in order. +
+ +## Tests +
+ +```yml +- text: 'mixedNumbers(["IV", 5, "six"]) should now return ["I", 2, "three", "IV", 5, "six", 7, "VIII", 9]' + testString: 'assert.deepEqual(mixedNumbers(["IV", 5, "six"]), ["I", 2, "three", "IV", 5, "six", 7, "VIII", 9], "mixedNumbers(["IV", 5, "six"]) should now return ["I", 2, "three", "IV", 5, "six", 7, "VIII", 9]");' +- text: The mixedNumbers function should utilize the push() method + testString: 'assert.notStrictEqual(mixedNumbers.toString().search(/\.push\(/), -1, "The mixedNumbers function should utilize the push() method");' +- text: The mixedNumbers function should utilize the unshift() method + testString: 'assert.notStrictEqual(mixedNumbers.toString().search(/\.unshift\(/), -1, "The mixedNumbers function should utilize the unshift() method");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +function mixedNumbers(arr) { + // change code below this line + + // change code above this line + return arr; +} + +// do not change code below this line +console.log(mixedNumbers(['IV', 5, 'six'])); +``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-data-structures/Add Key-Value Pairs to JavaScript Objects.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-data-structures/Add Key-Value Pairs to JavaScript Objects.md new file mode 100644 index 0000000000..eed5c0e03b --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-data-structures/Add Key-Value Pairs to JavaScript Objects.md @@ -0,0 +1,73 @@ +--- +id: 587d7b7c367417b2b2512b18 +title: Add Key-Value Pairs to JavaScript Objects +challengeType: 1 +--- + +## Description +
+At their most basic, objects are just collections of key-value pairs, or in other words, pieces of data mapped to unique identifiers that we call properties or keys. Let's take a look at a very simple example: +
let FCC_User = {
  username: 'awesome_coder',
  followers: 572,
  points: 1741,
  completedProjects: 15
};
+The above code defines an object called FCC_User that has four properties, each of which map to a specific value. If we wanted to know the number of followers FCC_User has, we can access that property by writing: +
let userData = FCC_User.followers;
// userData equals 572
+This is called dot notation. Alternatively, we can also access the property with brackets, like so: +
let userData = FCC_User['followers']
// userData equals 572
+Notice that with bracket notation, we enclosed followers in quotes. This is because the brackets actually allow us to pass a variable in to be evaluated as a property name (hint: keep this in mind for later!). Had we passed followers in without the quotes, the JavaScript engine would have attempted to evaluate it as a variable, and a ReferenceError: followers is not defined would have been thrown. +
+ +## Instructions +
+Using the same syntax, we can also add new key-value pairs to objects. We've created a foods object with three entries. Add three more entries: bananas with a value of 13, grapes with a value of 35, and strawberries with a value of 27. +
+ +## Tests +
+ +```yml +- text: foods is an object + testString: 'assert(typeof foods === "object", "foods is an object");' +- text: The foods object has a key "bananas" with a value of 13 + testString: 'assert(foods.bananas === 13, "The foods object has a key "bananas" with a value of 13");' +- text: The foods object has a key "grapes" with a value of 35 + testString: 'assert(foods.grapes === 35, "The foods object has a key "grapes" with a value of 35");' +- text: The foods object has a key "strawberries" with a value of 27 + testString: 'assert(foods.strawberries === 27, "The foods object has a key "strawberries" with a value of 27");' +- text: The key-value pairs should be set using dot or bracket notation + testString: 'assert(code.search(/bananas:/) === -1 && code.search(/grapes:/) === -1 && code.search(/strawberries:/) === -1, "The key-value pairs should be set using dot or bracket notation");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +let foods = { + apples: 25, + oranges: 32, + plums: 28 +}; + +// change code below this line + +// change code above this line + +console.log(foods); +``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-data-structures/Check For The Presence of an Element With indexOf().md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-data-structures/Check For The Presence of an Element With indexOf().md new file mode 100644 index 0000000000..9bf831df06 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-data-structures/Check For The Presence of an Element With indexOf().md @@ -0,0 +1,66 @@ +--- +id: 587d7b7b367417b2b2512b14 +title: Check For The Presence of an Element With indexOf() +challengeType: 1 +--- + +## Description +
+Since arrays can be changed, or mutated, at any time, there's no guarantee about where a particular piece of data will be on a given array, or if that element even still exists. Luckily, JavaScript provides us with another built-in method, indexOf(), that allows us to quickly and easily check for the presence of an element on an array. indexOf() takes an element as a parameter, and when called, it returns the position, or index, of that element, or -1 if the element does not exist on the array. +For example: +
let fruits = ['apples', 'pears', 'oranges', 'peaches', 'pears'];

fruits.indexOf('dates') // returns -1
fruits.indexOf('oranges') // returns 2
fruits.indexOf('pears') // returns 1, the first index at which the element exists
+
+ +## Instructions +
+indexOf() can be incredibly useful for quickly checking for the presence of an element on an array. We have defined a function, quickCheck, that takes an array and an element as arguments. Modify the function using indexOf() so that it returns true if the passed element exists on the array, and false if it does not. +
+ +## Tests +
+ +```yml +- text: 'quickCheck(["squash", "onions", "shallots"], "mushrooms") should return false' + testString: 'assert.strictEqual(quickCheck(["squash", "onions", "shallots"], "mushrooms"), false, "quickCheck(["squash", "onions", "shallots"], "mushrooms") should return false");' +- text: 'quickCheck(["squash", "onions", "shallots"], "onions") should return true' + testString: 'assert.strictEqual(quickCheck(["squash", "onions", "shallots"], "onions"), true, "quickCheck(["squash", "onions", "shallots"], "onions") should return true");' +- text: 'quickCheck([3, 5, 9, 125, 45, 2], 125) should return true' + testString: 'assert.strictEqual(quickCheck([3, 5, 9, 125, 45, 2], 125), true, "quickCheck([3, 5, 9, 125, 45, 2], 125) should return true");' +- text: 'quickCheck([true, false, false], undefined) should return false' + testString: 'assert.strictEqual(quickCheck([true, false, false], undefined), false, "quickCheck([true, false, false], undefined) should return false");' +- text: The quickCheck function should utilize the indexOf() method + testString: 'assert.notStrictEqual(quickCheck.toString().search(/\.indexOf\(/), -1, "The quickCheck function should utilize the indexOf() method");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +function quickCheck(arr, elem) { + // change code below this line + + // change code above this line +} + +// change code here to test different cases: +console.log(quickCheck(['squash', 'onions', 'shallots'], 'mushrooms')); +``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-data-structures/Check if an Object has a Property.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-data-structures/Check if an Object has a Property.md new file mode 100644 index 0000000000..ff22fa9c62 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-data-structures/Check if an Object has a Property.md @@ -0,0 +1,79 @@ +--- +id: 587d7b7d367417b2b2512b1c +title: Check if an Object has a Property +challengeType: 1 +--- + +## Description +
+Now we can add, modify, and remove keys from objects. But what if we just wanted to know if an object has a specific property? JavaScript provides us with two different ways to do this. One uses the hasOwnProperty() method and the other uses the in keyword. If we have an object users with a property of Alan, we could check for its presence in either of the following ways: +
users.hasOwnProperty('Alan');
'Alan' in users;
// both return true
+
+ +## Instructions +
+We've created an object, users, with some users in it and a function isEveryoneHere, which we pass the users object to as an argument. Finish writing this function so that it returns true only if the users object contains all four names, Alan, Jeff, Sarah, and Ryan, as keys, and false otherwise. +
+ +## Tests +
+ +```yml +- text: 'The users object only contains the keys Alan, Jeff, Sarah, and Ryan' + testString: 'assert("Alan" in users && "Jeff" in users && "Sarah" in users && "Ryan" in users && Object.keys(users).length === 4, "The users object only contains the keys Alan, Jeff, Sarah, and Ryan");' +- text: 'The function isEveryoneHere returns true if Alan, Jeff, Sarah, and Ryan are properties on the users object' + testString: 'assert(isEveryoneHere(users) === true, "The function isEveryoneHere returns true if Alan, Jeff, Sarah, and Ryan are properties on the users object");' +- text: 'The function isEveryoneHere returns false if Alan, Jeff, Sarah, and Ryan are not properties on the users object' + testString: 'assert((function() { delete users.Alan; delete users.Jeff; delete users.Sarah; delete users.Ryan; return isEveryoneHere(users) })() === false, "The function isEveryoneHere returns false if Alan, Jeff, Sarah, and Ryan are not properties on the users object");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +let users = { + Alan: { + age: 27, + online: true + }, + Jeff: { + age: 32, + online: true + }, + Sarah: { + age: 48, + online: true + }, + Ryan: { + age: 19, + online: true + } +}; + +function isEveryoneHere(obj) { + // change code below this line + + // change code above this line +} + +console.log(isEveryoneHere(users)); +``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-data-structures/Combine Arrays with the Spread Operator.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-data-structures/Combine Arrays with the Spread Operator.md new file mode 100644 index 0000000000..e505662fc3 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-data-structures/Combine Arrays with the Spread Operator.md @@ -0,0 +1,60 @@ +--- +id: 587d7b7b367417b2b2512b17 +title: Combine Arrays with the Spread Operator +challengeType: 1 +--- + +## Description +
+Another huge advantage of the spread operator, is the ability to combine arrays, or to insert all the elements of one array into another, at any index. With more traditional syntaxes, we can concatenate arrays, but this only allows us to combine arrays at the end of one, and at the start of another. Spread syntax makes the following operation extremely simple: +
let thisArray = ['sage', 'rosemary', 'parsley', 'thyme'];

let thatArray = ['basil', 'cilantro', ...thisArray, 'coriander'];
// thatArray now equals ['basil', 'cilantro', 'sage', 'rosemary', 'parsley', 'thyme', 'coriander']
+Using spread syntax, we have just achieved an operation that would have been more complex and more verbose had we used traditional methods. +
+ +## Instructions +
+We have defined a function spreadOut that returns the variable sentence, modify the function using the spread operator so that it returns the array ['learning', 'to', 'code', 'is', 'fun']. +
+ +## Tests +
+ +```yml +- text: 'spreadOut should return ["learning", "to", "code", "is", "fun"]' + testString: 'assert.deepEqual(spreadOut(), ["learning", "to", "code", "is", "fun"], "spreadOut should return ["learning", "to", "code", "is", "fun"]");' +- text: The spreadOut function should utilize spread syntax + testString: 'assert.notStrictEqual(spreadOut.toString().search(/[...]/), -1, "The spreadOut function should utilize spread syntax");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +function spreadOut() { + let fragment = ['to', 'code']; + let sentence; // change this line + return sentence; +} + +// do not change code below this line +console.log(spreadOut()); +``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-data-structures/Copy Array Items Using slice().md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-data-structures/Copy Array Items Using slice().md new file mode 100644 index 0000000000..c036c68db7 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-data-structures/Copy Array Items Using slice().md @@ -0,0 +1,60 @@ +--- +id: 587d7b7a367417b2b2512b12 +title: Copy Array Items Using slice() +challengeType: 1 +--- + +## Description +
+The next method we will cover is slice(). slice(), rather than modifying an array, copies, or extracts, a given number of elements to a new array, leaving the array it is called upon untouched. slice() takes only 2 parameters — the first is the index at which to begin extraction, and the second is the index at which to stop extraction (extraction will occur up to, but not including the element at this index). Consider this: +
let weatherConditions = ['rain', 'snow', 'sleet', 'hail', 'clear'];

let todaysWeather = weatherConditions.slice(1, 3);
// todaysWeather equals ['snow', 'sleet'];
// weatherConditions still equals ['rain', 'snow', 'sleet', 'hail', 'clear']
+In effect, we have created a new array by extracting elements from an existing array. +
+ +## Instructions +
+We have defined a function, forecast, that takes an array as an argument. Modify the function using slice() to extract information from the argument array and return a new array that contains the elements 'warm' and 'sunny'. +
+ +## Tests +
+ +```yml +- text: 'forecast should return ["warm", "sunny"]' + testString: 'assert.deepEqual(forecast(["cold", "rainy", "warm", "sunny", "cool", "thunderstorms"]), ["warm", "sunny"], "forecast should return ["warm", "sunny"]");' +- text: The forecast function should utilize the slice() method + testString: 'assert(/\.slice\(/.test(code), "The forecast function should utilize the slice() method");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +function forecast(arr) { + // change code below this line + + return arr; +} + +// do not change code below this line +console.log(forecast(['cold', 'rainy', 'warm', 'sunny', 'cool', 'thunderstorms'])); +``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-data-structures/Copy an Array with the Spread Operator.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-data-structures/Copy an Array with the Spread Operator.md new file mode 100644 index 0000000000..1a015d6968 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-data-structures/Copy an Array with the Spread Operator.md @@ -0,0 +1,71 @@ +--- +id: 587d7b7b367417b2b2512b13 +title: Copy an Array with the Spread Operator +challengeType: 1 +--- + +## Description +
+While slice() allows us to be selective about what elements of an array to copy, among several other useful tasks, ES6's new spread operator allows us to easily copy all of an array's elements, in order, with a simple and highly readable syntax. The spread syntax simply looks like this: ... +In practice, we can use the spread operator to copy an array like so: +
let thisArray = [true, true, undefined, false, null];
let thatArray = [...thisArray];
// thatArray equals [true, true, undefined, false, null]
// thisArray remains unchanged, and is identical to thatArray
+
+ +## Instructions +
+We have defined a function, copyMachine which takes arr (an array) and num (a number) as arguments. The function is supposed to return a new array made up of num copies of arr. We have done most of the work for you, but it doesn't work quite right yet. Modify the function using spread syntax so that it works correctly (hint: another method we have already covered might come in handy here!). +
+ +## Tests +
+ +```yml +- text: 'copyMachine([true, false, true], 2) should return [[true, false, true], [true, false, true]]' + testString: 'assert.deepEqual(copyMachine([true, false, true], 2), [[true, false, true], [true, false, true]], "copyMachine([true, false, true], 2) should return [[true, false, true], [true, false, true]]");' +- text: 'copyMachine([1, 2, 3], 5) should return [[1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3]]' + testString: 'assert.deepEqual(copyMachine([1, 2, 3], 5), [[1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3]], "copyMachine([1, 2, 3], 5) should return [[1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3]]");' +- text: 'copyMachine([true, true, null], 1) should return [[true, true, null]]' + testString: 'assert.deepEqual(copyMachine([true, true, null], 1), [[true, true, null]], "copyMachine([true, true, null], 1) should return [[true, true, null]]");' +- text: 'copyMachine(["it works"], 3) should return [["it works"], ["it works"], ["it works"]]' + testString: 'assert.deepEqual(copyMachine(["it works"], 3), [["it works"], ["it works"], ["it works"]], "copyMachine(["it works"], 3) should return [["it works"], ["it works"], ["it works"]]");' +- text: The copyMachine function should utilize the spread operator with array arr + testString: 'assert.notStrictEqual(copyMachine.toString().indexOf(".concat(_toConsumableArray(arr))"), -1, "The copyMachine function should utilize the spread operator with array arr");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +function copyMachine(arr, num) { + let newArr = []; + while (num >= 1) { + // change code below this line + + // change code above this line + num--; + } + return newArr; +} + +// change code here to test different cases: +console.log(copyMachine([true, false, true], 2)); +``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-data-structures/Create complex multi-dimensional arrays.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-data-structures/Create complex multi-dimensional arrays.md new file mode 100644 index 0000000000..45dc3a3751 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-data-structures/Create complex multi-dimensional arrays.md @@ -0,0 +1,72 @@ +--- +id: 587d7b7b367417b2b2512b16 +title: Create complex multi-dimensional arrays +challengeType: 1 +--- + +## Description +
+Awesome! You have just learned a ton about arrays! This has been a fairly high level overview, and there is plenty more to learn about working with arrays, much of which you will see in later sections. But before moving on to looking at Objects, lets take one more look, and see how arrays can become a bit more complex than what we have seen in previous challenges. +One of the most powerful features when thinking of arrays as data structures, is that arrays can contain, or even be completely made up of other arrays. We have seen arrays that contain arrays in previous challenges, but fairly simple ones. However, arrays can contain an infinite depth of arrays that can contain other arrays, each with their own arbitrary levels of depth, and so on. In this way, an array can very quickly become very complex data structure, known as a multi-dimensional, or nested array. Consider the following example: +
let nestedArray = [ // top, or first level - the outer most array
  ['deep'], // an array within an array, 2 levels of depth
  [
    ['deeper'], ['deeper'] // 2 arrays nested 3 levels deep
  ],
  [
    [
      ['deepest'], ['deepest'] // 2 arrays nested 4 levels deep
    ],
    [
      [
        ['deepest-est?'] // an array nested 5 levels deep
      ]
    ]
  ]
];
+While this example may seem convoluted, this level of complexity is not unheard of, or even unusual, when dealing with large amounts of data. +However, we can still very easily access the deepest levels of an array this complex with bracket notation: +
console.log(nestedArray[2][1][0][0][0]);
// logs: deepest-est?
+And now that we know where that piece of data is, we can reset it if we need to: +
nestedArray[2][1][0][0][0] = 'deeper still';

console.log(nestedArray[2][1][0][0][0]);
// now logs: deeper still
+
+ +## Instructions +
+We have defined a variable, myNestedArray, set equal to an array. Modify myNestedArray, using any combination of strings, numbers, and booleans for data elements, so that it has exactly five levels of depth (remember, the outer-most array is level 1). Somewhere on the third level, include the string 'deep', on the fourth level, include the string 'deeper', and on the fifth level, include the string 'deepest'. +
+ +## Tests +
+ +```yml +- text: 'myNestedArray should contain only numbers, booleans, and strings as data elements' + testString: 'assert.strictEqual((function(arr) { let flattened = (function flatten(arr) { const flat = [].concat(...arr); return flat.some (Array.isArray) ? flatten(flat) : flat; })(arr); for (let i = 0; i < flattened.length; i++) { if ( typeof flattened[i] !== "number" && typeof flattened[i] !== "string" && typeof flattened[i] !== "boolean") { return false } } return true })(myNestedArray), true, "myNestedArray should contain only numbers, booleans, and strings as data elements");' +- text: myNestedArray should have exactly 5 levels of depth + testString: 'assert.strictEqual((function(arr) {let depth = 0;function arrayDepth(array, i, d) { if (Array.isArray(array[i])) { arrayDepth(array[i], 0, d + 1);} else { depth = (d > depth) ? d : depth;}if (i < array.length) { arrayDepth(array, i + 1, d);} }arrayDepth(arr, 0, 0);return depth;})(myNestedArray), 4, "myNestedArray should have exactly 5 levels of depth");' +- text: myNestedArray should contain exactly one occurrence of the string "deep" on an array nested 3 levels deep + testString: 'assert((function howDeep(array, target, depth = 0) {return array.reduce((combined, current) => {if (Array.isArray(current)) { return combined.concat(howDeep(current, target, depth + 1));} else if (current === target) { return combined.concat(depth);} else { return combined;}}, []);})(myNestedArray, "deep").length === 1 && (function howDeep(array, target, depth = 0) {return array.reduce((combined, current) => {if (Array.isArray(current)) { return combined.concat(howDeep(current, target, depth + 1));} else if (current === target) { return combined.concat(depth);} else { return combined;}}, []);})(myNestedArray, "deep")[0] === 2, "myNestedArray should contain exactly one occurrence of the string "deep" on an array nested 3 levels deep");' +- text: myNestedArray should contain exactly one occurrence of the string "deeper" on an array nested 4 levels deep + testString: 'assert((function howDeep(array, target, depth = 0) {return array.reduce((combined, current) => {if (Array.isArray(current)) { return combined.concat(howDeep(current, target, depth + 1));} else if (current === target) { return combined.concat(depth);} else { return combined;}}, []);})(myNestedArray, "deeper").length === 1 && (function howDeep(array, target, depth = 0) {return array.reduce((combined, current) => {if (Array.isArray(current)) { return combined.concat(howDeep(current, target, depth + 1));} else if (current === target) { return combined.concat(depth);} else { return combined;}}, []);})(myNestedArray, "deeper")[0] === 3, "myNestedArray should contain exactly one occurrence of the string "deeper" on an array nested 4 levels deep");' +- text: myNestedArray should contain exactly one occurrence of the string "deepest" on an array nested 5 levels deep + testString: 'assert((function howDeep(array, target, depth = 0) {return array.reduce((combined, current) => {if (Array.isArray(current)) { return combined.concat(howDeep(current, target, depth + 1));} else if (current === target) { return combined.concat(depth);} else { return combined;}}, []);})(myNestedArray, "deepest").length === 1 && (function howDeep(array, target, depth = 0) {return array.reduce((combined, current) => {if (Array.isArray(current)) { return combined.concat(howDeep(current, target, depth + 1));} else if (current === target) { return combined.concat(depth);} else { return combined;}}, []);})(myNestedArray, "deepest")[0] === 4, "myNestedArray should contain exactly one occurrence of the string "deepest" on an array nested 5 levels deep");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +let myNestedArray = [ + // change code below this line + ['unshift', false, 1, 2, 3, 'complex', 'nested'], + ['loop', 'shift', 6, 7, 1000, 'method'], + ['concat', false, true, 'spread', 'array'], + ['mutate', 1327.98, 'splice', 'slice', 'push'], + ['iterate', 1.3849, 7, '8.4876', 'arbitrary', 'depth'] + // change code above this line +]; +``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-data-structures/Generate an Array of All Object Keys with Object.keys().md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-data-structures/Generate an Array of All Object Keys with Object.keys().md new file mode 100644 index 0000000000..37f0644210 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-data-structures/Generate an Array of All Object Keys with Object.keys().md @@ -0,0 +1,76 @@ +--- +id: 587d7b7d367417b2b2512b1e +title: Generate an Array of All Object Keys with Object.keys() +challengeType: 1 +--- + +## Description +
+We can also generate an array which contains all the keys stored in an object using the Object.keys() method and passing in an object as the argument. This will return an array with strings representing each property in the object. Again, there will be no specific order to the entries in the array. +
+ +## Instructions +
+Finish writing the getArrayOfUsers function so that it returns an array containing all the properties in the object it receives as an argument. +
+ +## Tests +
+ +```yml +- text: 'The users object only contains the keys Alan, Jeff, Sarah, and Ryan' + testString: 'assert("Alan" in users && "Jeff" in users && "Sarah" in users && "Ryan" in users && Object.keys(users).length === 4, "The users object only contains the keys Alan, Jeff, Sarah, and Ryan");' +- text: The getArrayOfUsers function returns an array which contains all the keys in the users object + testString: 'assert((function() { users.Sam = {}; users.Lewis = {}; let R = getArrayOfUsers(users); return (R.indexOf("Alan") !== -1 && R.indexOf("Jeff") !== -1 && R.indexOf("Sarah") !== -1 && R.indexOf("Ryan") !== -1 && R.indexOf("Sam") !== -1 && R.indexOf("Lewis") !== -1); })() === true, "The getArrayOfUsers function returns an array which contains all the keys in the users object");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +let users = { + Alan: { + age: 27, + online: false + }, + Jeff: { + age: 32, + online: true + }, + Sarah: { + age: 48, + online: false + }, + Ryan: { + age: 19, + online: true + } +}; + +function getArrayOfUsers(obj) { + // change code below this line + + // change code above this line +} + +console.log(getArrayOfUsers(users)); +``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-data-structures/Iterate Through All an Array's Items Using For Loops.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-data-structures/Iterate Through All an Array's Items Using For Loops.md new file mode 100644 index 0000000000..c5378b3615 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-data-structures/Iterate Through All an Array's Items Using For Loops.md @@ -0,0 +1,69 @@ +--- +id: 587d7b7b367417b2b2512b15 +title: Iterate Through All an Array's Items Using For Loops +challengeType: 1 +--- + +## Description +
+Sometimes when working with arrays, it is very handy to be able to iterate through each item to find one or more elements that we might need, or to manipulate an array based on which data items meet a certain set of criteria. JavaScript offers several built in methods that each iterate over arrays in slightly different ways to achieve different results (such as every(), forEach(), map(), etc.), however the technique which is most flexible and offers us the greatest amount of control is a simple for loop. +Consider the following: +
function greaterThanTen(arr) {
  let newArr = [];
  for (let i = 0; i < arr.length; i++) {
    if (arr[i] > 10) {
      newArr.push(arr[i]);
    }
  }
  return newArr;
}

greaterThanTen([2, 12, 8, 14, 80, 0, 1]);
// returns [12, 14, 80]
+Using a for loop, this function iterates through and accesses each element of the array, and subjects it to a simple test that we have created. In this way, we have easily and programmatically determined which data items are greater than 10, and returned a new array containing those items. +
+ +## Instructions +
+We have defined a function, filteredArray, which takes arr, a nested array, and elem as arguments, and returns a new array. elem represents an element that may or may not be present on one or more of the arrays nested within arr. Modify the function, using a for loop, to return a filtered version of the passed array such that any array nested within arr containing elem has been removed. +
+ +## Tests +
+ +```yml +- text: 'filteredArray([[10, 8, 3], [14, 6, 23], [3, 18, 6]], 18) should return [ [10, 8, 3], [14, 6, 23] ]' + testString: 'assert.deepEqual(filteredArray([ [10, 8, 3], [14, 6, 23], [3, 18, 6] ], 18), [[10, 8, 3], [14, 6, 23]], "filteredArray([[10, 8, 3], [14, 6, 23], [3, 18, 6]], 18) should return [ [10, 8, 3], [14, 6, 23] ]");' +- text: 'filteredArray([ ["trumpets", 2], ["flutes", 4], ["saxophones", 2] ], 2) should return [ ["flutes", 4] ]' + testString: 'assert.deepEqual(filteredArray([ ["trumpets", 2], ["flutes", 4], ["saxophones", 2] ], 2), [["flutes", 4]], "filteredArray([ ["trumpets", 2], ["flutes", 4], ["saxophones", 2] ], 2) should return [ ["flutes", 4] ]");' +- text: 'filteredArray([ ["amy", "beth", "sam"], ["dave", "sean", "peter"] ], "peter") should return [ ["amy", "beth", "sam"] ]' + testString: 'assert.deepEqual(filteredArray([["amy", "beth", "sam"], ["dave", "sean", "peter"]], "peter"), [["amy", "beth", "sam"]], "filteredArray([ ["amy", "beth", "sam"], ["dave", "sean", "peter"] ], "peter") should return [ ["amy", "beth", "sam"] ]");' +- text: 'filteredArray([[3, 2, 3], [1, 6, 3], [3, 13, 26], [19, 3, 9]], 3) should return [ ]' + testString: 'assert.deepEqual(filteredArray([[3, 2, 3], [1, 6, 3], [3, 13, 26], [19, 3, 9]], 3), [], "filteredArray([[3, 2, 3], [1, 6, 3], [3, 13, 26], [19, 3, 9]], 3) should return [ ]");' +- text: The filteredArray function should utilize a for loop + testString: 'assert.notStrictEqual(filteredArray.toString().search(/for/), -1, "The filteredArray function should utilize a for loop");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +function filteredArray(arr, elem) { + let newArr = []; + // change code below this line + + // change code above this line + return newArr; +} + +// change code here to test different cases: +console.log(filteredArray([[3, 2, 3], [1, 6, 3], [3, 13, 26], [19, 3, 9]], 3)); +``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-data-structures/Modify an Array Stored in an Object.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-data-structures/Modify an Array Stored in an Object.md new file mode 100644 index 0000000000..0299ef7b58 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-data-structures/Modify an Array Stored in an Object.md @@ -0,0 +1,79 @@ +--- +id: 587d7b7d367417b2b2512b1f +title: Modify an Array Stored in an Object +challengeType: 1 +--- + +## Description +
+Now you've seen all the basic operations for JavaScript objects. You can add, modify, and remove key-value pairs, check if keys exist, and iterate over all the keys in an object. As you continue learning JavaScript you will see even more versatile applications of objects. Additionally, the optional Advanced Data Structures lessons later in the curriculum also cover the ES6 Map and Set objects, both of which are similar to ordinary objects but provide some additional features. Now that you've learned the basics of arrays and objects, you're fully prepared to begin tackling more complex problems using JavaScript! +
+ +## Instructions +
+Take a look at the object we've provided in the code editor. The user object contains three keys. The data key contains five keys, one of which contains an array of friends. From this, you can see how flexible objects are as data structures. We've started writing a function addFriend. Finish writing it so that it takes a user object and adds the name of the friend argument to the array stored in user.data.friends and returns that array. +
+ +## Tests +
+ +```yml +- text: 'The user object has name, age, and data keys' + testString: 'assert("name" in user && "age" in user && "data" in user, "The user object has name, age, and data keys");' +- text: The addFriend function accepts a user object and a friend string as arguments and adds the friend to the array of friends in the user object + testString: 'assert((function() { let L1 = user.data.friends.length; addFriend(user, "Sean"); let L2 = user.data.friends.length; return (L2 === L1 + 1); })(), "The addFriend function accepts a user object and a friend string as arguments and adds the friend to the array of friends in the user object");' +- text: 'addFriend(user, "Pete") should return ["Sam", "Kira", "Tomo", "Pete"]' + testString: 'assert.deepEqual((function() { delete user.data.friends; user.data.friends = ["Sam", "Kira", "Tomo"]; return addFriend(user, "Pete") })(), ["Sam", "Kira", "Tomo", "Pete"], "addFriend(user, "Pete") should return ["Sam", "Kira", "Tomo", "Pete"]");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +let user = { + name: 'Kenneth', + age: 28, + data: { + username: 'kennethCodesAllDay', + joinDate: 'March 26, 2016', + organization: 'freeCodeCamp', + friends: [ + 'Sam', + 'Kira', + 'Tomo' + ], + location: { + city: 'San Francisco', + state: 'CA', + country: 'USA' + } + } +}; + +function addFriend(userObj, friend) { + // change code below this line + + // change code above this line +} + +console.log(addFriend(user, 'Pete')); +``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-data-structures/Modify an Object Nested Within an Object.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-data-structures/Modify an Object Nested Within an Object.md new file mode 100644 index 0000000000..a1c8fb3b83 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-data-structures/Modify an Object Nested Within an Object.md @@ -0,0 +1,70 @@ +--- +id: 587d7b7c367417b2b2512b19 +title: Modify an Object Nested Within an Object +challengeType: 1 +--- + +## Description +
+Now let's take a look at a slightly more complex object. Object properties can be nested to an arbitrary depth, and their values can be any type of data supported by JavaScript, including arrays and even other objects. Consider the following: +
let nestedObject = {
  id: 28802695164,
  date: 'December 31, 2016',
  data: {
    totalUsers: 99,
    online: 80,
    onlineStatus: {
      active: 67,
      away: 13
    }
  }
};
+nestedObject has three unique keys: id, whose value is a number, date whose value is a string, and data, whose value is an object which has yet another object nested within it. While structures can quickly become complex, we can still use the same notations to access the information we need. +
+ +## Instructions +
+Here we've defined an object, userActivity, which includes another object nested within it. You can modify properties on this nested object in the same way you modified properties in the last challenge. Set the value of the online key to 45. +
+ +## Tests +
+ +```yml +- text: 'userActivity has id, date and data properties' + testString: 'assert("id" in userActivity && "date" in userActivity && "data" in userActivity, "userActivity has id, date and data properties");' +- text: userActivity has a data key set to an object with keys totalUsers and online + testString: 'assert("totalUsers" in userActivity.data && "online" in userActivity.data, "userActivity has a data key set to an object with keys totalUsers and online");' +- text: The online property nested in the data key of userActivity should be set to 45 + testString: 'assert(userActivity.data.online === 45, "The online property nested in the data key of userActivity should be set to 45");' +- text: The online property is set using dot or bracket notation + testString: 'assert.strictEqual(code.search(/online: 45/), -1, "The online property is set using dot or bracket notation");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +let userActivity = { + id: 23894201352, + date: 'January 1, 2017', + data: { + totalUsers: 51, + online: 42 + } +}; + +// change code below this line + +// change code above this line + +console.log(userActivity); +``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-data-structures/Remove Items Using splice().md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-data-structures/Remove Items Using splice().md new file mode 100644 index 0000000000..bb66467870 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-data-structures/Remove Items Using splice().md @@ -0,0 +1,63 @@ +--- +id: 587d78b2367417b2b2512b10 +title: Remove Items Using splice() +challengeType: 1 +--- + +## Description +
+Ok, so we've learned how to remove elements from the beginning and end of arrays using shift() and pop(), but what if we want to remove an element from somewhere in the middle? Or remove more than one element at once? Well, that's where splice() comes in. splice() allows us to do just that: remove any number of consecutive elements from anywhere in an array. +splice() can take up to 3 parameters, but for now, we'll focus on just the first 2. The first two parameters of splice() are integers which represent indexes, or positions, of the array that splice() is being called upon. And remember, arrays are zero-indexed, so to indicate the first element of an array, we would use 0. splice()'s first parameter represents the index on the array from which to begin removing elements, while the second parameter indicates the number of elements to delete. For example: +
let array = ['today', 'was', 'not', 'so', 'great'];

array.splice(2, 2);
// remove 2 elements beginning with the 3rd element
// array now equals ['today', 'was', 'great']
+splice() not only modifies the array it's being called on, but it also returns a new array containing the value of the removed elements: +
let array = ['I', 'am', 'feeling', 'really', 'happy'];

let newArray = array.splice(3, 2);
// newArray equals ['really', 'happy']
+
+ +## Instructions +
+We've defined a function, sumOfTen, which takes an array as an argument and returns the sum of that array's elements. Modify the function, using splice(), so that it returns a value of 10. +
+ +## Tests +
+ +```yml +- text: sumOfTen should return 10 + testString: 'assert.strictEqual(sumOfTen([2, 5, 1, 5, 2, 1]), 10, "sumOfTen should return 10");' +- text: The sumOfTen function should utilize the splice() method + testString: 'assert.notStrictEqual(sumOfTen.toString().search(/\.splice\(/), -1, "The sumOfTen function should utilize the splice() method");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +function sumOfTen(arr) { + // change code below this line + + // change code above this line + return arr.reduce((a, b) => a + b); +} + +// do not change code below this line +console.log(sumOfTen([2, 5, 1, 5, 2, 1])); +``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-data-structures/Remove Items from an Array with pop() and shift().md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-data-structures/Remove Items from an Array with pop() and shift().md new file mode 100644 index 0000000000..37df26295c --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-data-structures/Remove Items from an Array with pop() and shift().md @@ -0,0 +1,64 @@ +--- +id: 587d78b2367417b2b2512b0f +title: Remove Items from an Array with pop() and shift() +challengeType: 1 +--- + +## Description +
+Both push() and unshift() have corresponding methods that are nearly functional opposites: pop() and shift(). As you may have guessed by now, instead of adding, pop() removes an element from the end of an array, while shift() removes an element from the beginning. The key difference between pop() and shift() and their cousins push() and unshift(), is that neither method takes parameters, and each only allows an array to be modified by a single element at a time. +Let's take a look: +
let greetings = ['whats up?', 'hello', 'see ya!'];

greetings.pop();
// now equals ['whats up?', 'hello']

greetings.shift();
// now equals ['hello']
+We can also return the value of the removed element with either method like this: +
let popped = greetings.pop();
// returns 'hello'
// greetings now equals []
+
+ +## Instructions +
+We have defined a function, popShift, which takes an array as an argument and returns a new array. Modify the function, using pop() and shift(), to remove the first and last elements of the argument array, and assign the removed elements to their corresponding variables, so that the returned array contains their values. +
+ +## Tests +
+ +```yml +- text: 'popShift(["challenge", "is", "not", "complete"]) should return ["challenge", "complete"]' + testString: 'assert.deepEqual(popShift(["challenge", "is", "not", "complete"]), ["challenge", "complete"], "popShift(["challenge", "is", "not", "complete"]) should return ["challenge", "complete"]");' +- text: The popShift function should utilize the pop() method + testString: 'assert.notStrictEqual(popShift.toString().search(/\.pop\(/), -1, "The popShift function should utilize the pop() method");' +- text: The popShift function should utilize the shift() method + testString: 'assert.notStrictEqual(popShift.toString().search(/\.shift\(/), -1, "The popShift function should utilize the shift() method");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +function popShift(arr) { + let popped; // change this line + let shifted; // change this line + return [shifted, popped]; +} + +// do not change code below this line +console.log(popShift(['challenge', 'is', 'not', 'complete'])); +``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-data-structures/Use an Array to Store a Collection of Data.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-data-structures/Use an Array to Store a Collection of Data.md new file mode 100644 index 0000000000..447da06b63 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-data-structures/Use an Array to Store a Collection of Data.md @@ -0,0 +1,61 @@ +--- +id: 587d7b7e367417b2b2512b20 +title: Use an Array to Store a Collection of Data +challengeType: 1 +--- + +## Description +
+The below is an example of the simplest implementation of an array data structure. This is known as a one-dimensional array, meaning it only has one level, or that it does not have any other arrays nested within it. Notice it contains booleans, strings, and numbers, among other valid JavaScript data types: +
let simpleArray = ['one', 2, 'three’, true, false, undefined, null];
console.log(simpleArray.length);
// logs 7
+All array's have a length property, which as shown above, can be very easily accessed with the syntax Array.length. +A more complex implementation of an array can be seen below. This is known as a multi-dimensional array, or an array that contains other arrays. Notice that this array also contains JavaScript objects, which we will examine very closely in our next section, but for now, all you need to know is that arrays are also capable of storing complex objects. +
let complexArray = [
  [
    {
      one: 1,
      two: 2
    },
    {
      three: 3,
      four: 4
    }
  ],
  [
    {
      a: "a",
      b: "b"
    },
    {
      c: "c",
      d: “d”
    }
  ]
];
+
+ +## Instructions +
+We have defined a variable called yourArray. Complete the statement by assigning an array of at least 5 elements in length to the yourArray variable. Your array should contain at least one string, one number, and one boolean. +
+ +## Tests +
+ +```yml +- text: yourArray is an array + testString: 'assert.strictEqual(Array.isArray(yourArray), true, "yourArray is an array");' +- text: yourArray is at least 5 elements long + testString: 'assert.isAtLeast(yourArray.length, 5, "yourArray is at least 5 elements long");' +- text: yourArray contains at least one boolean + testString: 'assert(yourArray.filter( el => typeof el === "boolean").length >= 1, "yourArray contains at least one boolean");' +- text: yourArray contains at least one number + testString: 'assert(yourArray.filter( el => typeof el === "number").length >= 1, "yourArray contains at least one number");' +- text: yourArray contains at least one string + testString: 'assert(yourArray.filter( el => typeof el === "string").length >= 1, "yourArray contains at least one string");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +let yourArray; // change this line +``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-data-structures/Use the delete Keyword to Remove Object Properties.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-data-structures/Use the delete Keyword to Remove Object Properties.md new file mode 100644 index 0000000000..166015e2ff --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-data-structures/Use the delete Keyword to Remove Object Properties.md @@ -0,0 +1,67 @@ +--- +id: 587d7b7c367417b2b2512b1b +title: Use the delete Keyword to Remove Object Properties +challengeType: 1 +--- + +## Description +
+Now you know what objects are and their basic features and advantages. In short, they are key-value stores which provide a flexible, intuitive way to structure data, and, they provide very fast lookup time. Throughout the rest of these challenges, we will describe several common operations you can perform on objects so you can become comfortable applying these useful data structures in your programs. +In earlier challenges, we have both added to and modified an object's key-value pairs. Here we will see how we can remove a key-value pair from an object. +Let's revisit our foods object example one last time. If we wanted to remove the apples key, we can remove it by using the delete keyword like this: +
delete foods.apples;
+
+ +## Instructions +
+Use the delete keyword to remove the oranges, plums, and strawberries keys from the foods object. +
+ +## Tests +
+ +```yml +- text: 'The foods object only has three keys: apples, grapes, and bananas' + testString: 'assert(!foods.hasOwnProperty("oranges") && !foods.hasOwnProperty("plums") && !foods.hasOwnProperty("strawberries") && Object.keys(foods).length === 3, "The foods object only has three keys: apples, grapes, and bananas");' +- text: 'The oranges, plums, and strawberries keys are removed using delete' + testString: 'assert(code.search(/oranges:/) !== -1 && code.search(/plums:/) !== -1 && code.search(/strawberries:/) !== -1, "The oranges, plums, and strawberries keys are removed using delete");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +let foods = { + apples: 25, + oranges: 32, + plums: 28, + bananas: 13, + grapes: 35, + strawberries: 27 +}; + +// change code below this line + +// change code above this line + +console.log(foods); +``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-data-structures/meta.json b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-data-structures/meta.json new file mode 100644 index 0000000000..6cc41a1891 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-data-structures/meta.json @@ -0,0 +1,8 @@ +{ + "name": "Basic Data Structures", + "dashedName": "basic-data-structures", + "order": 5, + "time": "1 hour", + "superBlock": "javascript-algorithms-and-data-structures", + "superOrder": 2 +} \ No newline at end of file diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Access Array Data with Indexes.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Access Array Data with Indexes.md new file mode 100644 index 0000000000..c948e74de3 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Access Array Data with Indexes.md @@ -0,0 +1,75 @@ +--- +id: 56bbb991ad1ed5201cd392ca +title: Access Array Data with Indexes +challengeType: 1 +guideUrl: 'https://guide.freecodecamp.org/certificates/access-array-data-with-indexes' +--- + +## Description +
+We can access the data inside arrays using indexes. +Array indexes are written in the same bracket notation that strings use, except that instead of specifying a character, they are specifying an entry in the array. Like strings, arrays use zero-based indexing, so the first element in an array is element 0. +Example +
var array = [50,60,70];
array[0]; // equals 50
var data = array[1]; // equals 60
+Note
There shouldn't be any spaces between the array name and the square brackets, like array [0]. Although JavaScript is able to process this correctly, this may confuse other programmers reading your code. +
+ +## Instructions +
+Create a variable called myData and set it to equal the first value of myArray using bracket notation. +
+ +## Tests +
+ +```yml +- text: The variable myData should equal the first value of myArray. + testString: 'assert((function(){if(typeof myArray !== "undefined" && typeof myData !== "undefined" && myArray[0] === myData){return true;}else{return false;}})(), "The variable myData should equal the first value of myArray.");' +- text: The data in variable myArray should be accessed using bracket notation. + testString: 'assert((function(){if(code.match(/\s*=\s*myArray\[0\]/g)){return true;}else{return false;}})(), "The data in variable myArray should be accessed using bracket notation.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +// Example +var ourArray = [50,60,70]; +var ourData = ourArray[0]; // equals 50 + +// Setup +var myArray = [50,60,70]; + +// Only change code below this line. + +``` + +
+ + +### After Test +
+ +```js +console.info('after the test'); +``` + +
+ +
+ +## Solution +
+ + +```js +var myArray = [50,60,70]; +var myData = myArray[0]; +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Access Multi-Dimensional Arrays With Indexes.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Access Multi-Dimensional Arrays With Indexes.md new file mode 100644 index 0000000000..bb4b9396bc --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Access Multi-Dimensional Arrays With Indexes.md @@ -0,0 +1,71 @@ +--- +id: 56592a60ddddeae28f7aa8e1 +title: Access Multi-Dimensional Arrays With Indexes +challengeType: 1 +guideUrl: 'https://guide.freecodecamp.org/certificates/access-array-data-with-indexes' +--- + +## Description +
+One way to think of a multi-dimensional array, is as an array of arrays. When you use brackets to access your array, the first set of brackets refers to the entries in the outer-most (the first level) array, and each additional pair of brackets refers to the next level of entries inside. +Example +
var arr = [
  [1,2,3],
  [4,5,6],
  [7,8,9],
  [[10,11,12], 13, 14]
];
arr[3]; // equals [[10,11,12], 13, 14]
arr[3][0]; // equals [10,11,12]
arr[3][0][1]; // equals 11
+Note
There shouldn't be any spaces between the array name and the square brackets, like array [0][0] and even this array [0] [0] is not allowed. Although JavaScript is able to process this correctly, this may confuse other programmers reading your code. +
+ +## Instructions +
+Using bracket notation select an element from myArray such that myData is equal to 8. +
+ +## Tests +
+ +```yml +- text: myData should be equal to 8. + testString: 'assert(myData === 8, "myData should be equal to 8.");' +- text: You should be using bracket notation to read the correct value from myArray. + testString: 'assert(/myArray\[2\]\[1\]/g.test(code) && !/myData\s*=\s*(?:.*[-+*/%]|\d)/g.test(code), "You should be using bracket notation to read the correct value from myArray.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +// Setup +var myArray = [[1,2,3], [4,5,6], [7,8,9], [[10,11,12], 13, 14]]; + +// Only change code below this line. +var myData = myArray[0][0]; + +``` + +
+ + +### After Test +
+ +```js +console.info('after the test'); +``` + +
+ +
+ +## Solution +
+ + +```js +var myArray = [[1,2,3],[4,5,6], [7,8,9], [[10,11,12], 13, 14]]; +var myData = myArray[2][1]; +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Accessing Nested Arrays.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Accessing Nested Arrays.md new file mode 100644 index 0000000000..3381816dc8 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Accessing Nested Arrays.md @@ -0,0 +1,108 @@ +--- +id: 56533eb9ac21ba0edf2244cd +title: Accessing Nested Arrays +challengeType: 1 +guideUrl: 'https://guide.freecodecamp.org/certificates/access-array-data-with-indexes' +--- + +## Description +
+As we have seen in earlier examples, objects can contain both nested objects and nested arrays. Similar to accessing nested objects, Array bracket notation can be chained to access nested arrays. +Here is an example of how to access a nested array: +
var ourPets = [
  {
    animalType: "cat",
    names: [
      "Meowzer",
      "Fluffy",
      "Kit-Cat"
    ]
  },
  {
    animalType: "dog",
    names: [
      "Spot",
      "Bowser",
      "Frankie"
    ]
  }
];
ourPets[0].names[1]; // "Fluffy"
ourPets[1].names[0]; // "Spot"
+
+ +## Instructions +
+Retrieve the second tree from the variable myPlants using object dot and array bracket notation. +
+ +## Tests +
+ +```yml +- text: secondTree should equal "pine" + testString: 'assert(secondTree === "pine", "secondTree should equal "pine"");' +- text: Use dot and bracket notation to access myPlants + testString: 'assert(/=\s*myPlants\[1\].list\[1\]/.test(code), "Use dot and bracket notation to access myPlants");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +// Setup +var myPlants = [ + { + type: "flowers", + list: [ + "rose", + "tulip", + "dandelion" + ] + }, + { + type: "trees", + list: [ + "fir", + "pine", + "birch" + ] + } +]; + +// Only change code below this line + +var secondTree = ""; // Change this line + +``` + +
+ + +### After Test +
+ +```js +console.info('after the test'); +``` + +
+ +
+ +## Solution +
+ + +```js +var myPlants = [ + { + type: "flowers", + list: [ + "rose", + "tulip", + "dandelion" + ] + }, + { + type: "trees", + list: [ + "fir", + "pine", + "birch" + ] + } +]; + +// Only change code below this line + +var secondTree = myPlants[1].list[1]; +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Accessing Nested Objects.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Accessing Nested Objects.md new file mode 100644 index 0000000000..68c73def8a --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Accessing Nested Objects.md @@ -0,0 +1,89 @@ +--- +id: 56533eb9ac21ba0edf2244cc +title: Accessing Nested Objects +challengeType: 1 +guideUrl: 'https://guide.freecodecamp.org/certificates/accessing-nested-objects-in-json' +--- + +## Description +
+The sub-properties of objects can be accessed by chaining together the dot or bracket notation. +Here is a nested object: +
var ourStorage = {
  "desk": {
    "drawer": "stapler"
  },
  "cabinet": {
    "top drawer": {
      "folder1": "a file",
      "folder2": "secrets"
    },
    "bottom drawer": "soda"
  }
};
ourStorage.cabinet["top drawer"].folder2; // "secrets"
ourStorage.desk.drawer; // "stapler"
+
+ +## Instructions +
+Access the myStorage object and assign the contents of the glove box property to the gloveBoxContents variable. Use bracket notation for properties with a space in their name. +
+ +## Tests +
+ +```yml +- text: gloveBoxContents should equal "maps" + testString: 'assert(gloveBoxContents === "maps", "gloveBoxContents should equal "maps"");' +- text: Use dot and bracket notation to access myStorage + testString: 'assert(/=\s*myStorage\.car\.inside\[\s*("|")glove box\1\s*\]/g.test(code), "Use dot and bracket notation to access myStorage");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +// Setup +var myStorage = { + "car": { + "inside": { + "glove box": "maps", + "passenger seat": "crumbs" + }, + "outside": { + "trunk": "jack" + } + } +}; + +var gloveBoxContents = undefined; // Change this line + +``` + +
+ + +### After Test +
+ +```js +console.info('after the test'); +``` + +
+ +
+ +## Solution +
+ + +```js +var myStorage = { + "car":{ + "inside":{ + "glove box":"maps", + "passenger seat":"crumbs" + }, + "outside":{ + "trunk":"jack" + } + } +}; +var gloveBoxContents = myStorage.car.inside["glove box"]; +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Accessing Object Properties with Bracket Notation.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Accessing Object Properties with Bracket Notation.md new file mode 100644 index 0000000000..7520ede16a --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Accessing Object Properties with Bracket Notation.md @@ -0,0 +1,88 @@ +--- +id: 56533eb9ac21ba0edf2244c8 +title: Accessing Object Properties with Bracket Notation +challengeType: 1 +guideUrl: 'https://guide.freecodecamp.org/certificates/accessing-objects-properties-with-bracket-notation' +--- + +## Description +
+The second way to access the properties of an object is bracket notation ([]). If the property of the object you are trying to access has a space in its name, you will need to use bracket notation. +However, you can still use bracket notation on object properties without spaces. +Here is a sample of using bracket notation to read an object's property: +
var myObj = {
  "Space Name": "Kirk",
  "More Space": "Spock",
  "NoSpace": "USS Enterprise"
};
myObj["Space Name"]; // Kirk
myObj['More Space']; // Spock
myObj["NoSpace"]; // USS Enterprise
+Note that property names with spaces in them must be in quotes (single or double). +
+ +## Instructions +
+Read the values of the properties "an entree" and "the drink" of testObj using bracket notation and assign them to entreeValue and drinkValue respectively. +
+ +## Tests +
+ +```yml +- text: entreeValue should be a string + testString: 'assert(typeof entreeValue === "string" , "entreeValue should be a string");' +- text: The value of entreeValue should be "hamburger" + testString: 'assert(entreeValue === "hamburger" , "The value of entreeValue should be "hamburger"");' +- text: drinkValue should be a string + testString: 'assert(typeof drinkValue === "string" , "drinkValue should be a string");' +- text: The value of drinkValue should be "water" + testString: 'assert(drinkValue === "water" , "The value of drinkValue should be "water"");' +- text: You should use bracket notation twice + testString: 'assert(code.match(/testObj\s*?\[("|")[^""]+\1\]/g).length > 1, "You should use bracket notation twice");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +// Setup +var testObj = { + "an entree": "hamburger", + "my side": "veggies", + "the drink": "water" +}; + +// Only change code below this line + +var entreeValue = testObj; // Change this line +var drinkValue = testObj; // Change this line +``` + +
+ + +### After Test +
+ +```js +console.info('after the test'); +``` + +
+ +
+ +## Solution +
+ + +```js +var testObj = { + "an entree": "hamburger", + "my side": "veggies", + "the drink": "water" +}; +var entreeValue = testObj["an entree"]; +var drinkValue = testObj['the drink']; +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Accessing Object Properties with Dot Notation.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Accessing Object Properties with Dot Notation.md new file mode 100644 index 0000000000..899f1ff57c --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Accessing Object Properties with Dot Notation.md @@ -0,0 +1,87 @@ +--- +id: 56533eb9ac21ba0edf2244c7 +title: Accessing Object Properties with Dot Notation +challengeType: 1 +--- + +## Description +
+There are two ways to access the properties of an object: dot notation (.) and bracket notation ([]), similar to an array. +Dot notation is what you use when you know the name of the property you're trying to access ahead of time. +Here is a sample of using dot notation (.) to read an object's property: +
var myObj = {
  prop1: "val1",
  prop2: "val2"
};
var prop1val = myObj.prop1; // val1
var prop2val = myObj.prop2; // val2
+
+ +## Instructions +
+Read in the property values of testObj using dot notation. Set the variable hatValue equal to the object's property hat and set the variable shirtValue equal to the object's property shirt. +
+ +## Tests +
+ +```yml +- text: hatValue should be a string + testString: 'assert(typeof hatValue === "string" , "hatValue should be a string");' +- text: The value of hatValue should be "ballcap" + testString: 'assert(hatValue === "ballcap" , "The value of hatValue should be "ballcap"");' +- text: shirtValue should be a string + testString: 'assert(typeof shirtValue === "string" , "shirtValue should be a string");' +- text: The value of shirtValue should be "jersey" + testString: 'assert(shirtValue === "jersey" , "The value of shirtValue should be "jersey"");' +- text: You should use dot notation twice + testString: 'assert(code.match(/testObj\.\w+/g).length > 1, "You should use dot notation twice");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +// Setup +var testObj = { + "hat": "ballcap", + "shirt": "jersey", + "shoes": "cleats" +}; + +// Only change code below this line + +var hatValue = testObj; // Change this line +var shirtValue = testObj; // Change this line +``` + +
+ + +### After Test +
+ +```js +console.info('after the test'); +``` + +
+ +
+ +## Solution +
+ + +```js +var testObj = { + "hat": "ballcap", + "shirt": "jersey", + "shoes": "cleats" +}; + +var hatValue = testObj.hat; +var shirtValue = testObj.shirt; +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Accessing Object Properties with Variables.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Accessing Object Properties with Variables.md new file mode 100644 index 0000000000..c5574bdc63 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Accessing Object Properties with Variables.md @@ -0,0 +1,93 @@ +--- +id: 56533eb9ac21ba0edf2244c9 +title: Accessing Object Properties with Variables +challengeType: 1 +guideUrl: 'https://guide.freecodecamp.org/certificates/accessing-objects-properties-with-variables' +--- + +## Description +
+Another use of bracket notation on objects is to access a property which is stored as the value of a variable. This can be very useful for iterating through an object's properties or when accessing a lookup table. +Here is an example of using a variable to access a property: +
var dogs = {
  Fido: "Mutt", + Hunter: "Doberman", + Snoopie: "Beagle"
};
var myDog = "Hunter";
var myBreed = dogs[myDog];
console.log(myBreed); // "Doberman"
+Another way you can use this concept is when the property's name is collected dynamically during the program execution, as follows: +
var someObj = {
  propName: "John"
};
function propPrefix(str) {
  var s = "prop";
  return s + str;
}
var someProp = propPrefix("Name"); // someProp now holds the value 'propName'
console.log(someObj[someProp]); // "John"
+Note that we do not use quotes around the variable name when using it to access the property because we are using the value of the variable, not the name. +
+ +## Instructions +
+Use the playerNumber variable to look up player 16 in testObj using bracket notation. Then assign that name to the player variable. +
+ +## Tests +
+ +```yml +- text: playerNumber should be a number + testString: 'assert(typeof playerNumber === "number", "playerNumber should be a number");' +- text: The variable player should be a string + testString: 'assert(typeof player === "string", "The variable player should be a string");' +- text: The value of player should be "Montana" + testString: 'assert(player === "Montana", "The value of player should be "Montana"");' +- text: You should use bracket notation to access testObj + testString: 'assert(/testObj\s*?\[.*?\]/.test(code),"You should use bracket notation to access testObj");' +- text: You should not assign the value Montana to the variable player directly. + testString: 'assert(!code.match(/player\s*=\s*"|\"\s*Montana\s*"|\"\s*;/gi),"You should not assign the value Montana to the variable player directly.");' +- text: You should be using the variable playerNumber in your bracket notation + testString: 'assert(/testObj\s*?\[\s*playerNumber\s*\]/.test(code),"You should be using the variable playerNumber in your bracket notation");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +// Setup +var testObj = { + 12: "Namath", + 16: "Montana", + 19: "Unitas" +}; + +// Only change code below this line; + +var playerNumber; // Change this Line +var player = testObj; // Change this Line +``` + +
+ + +### After Test +
+ +```js +console.info('after the test'); +``` + +
+ +
+ +## Solution +
+ + +```js +var testObj = { + 12: "Namath", + 16: "Montana", + 19: "Unitas" +}; +var playerNumber = 16; +var player = testObj[playerNumber]; +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Add New Properties to a JavaScript Object.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Add New Properties to a JavaScript Object.md new file mode 100644 index 0000000000..62b4b91cac --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Add New Properties to a JavaScript Object.md @@ -0,0 +1,91 @@ +--- +id: 56bbb991ad1ed5201cd392d2 +title: Add New Properties to a JavaScript Object +challengeType: 1 +--- + +## Description +
+You can add new properties to existing JavaScript objects the same way you would modify them. +Here's how we would add a "bark" property to ourDog: +ourDog.bark = "bow-wow"; +or +ourDog["bark"] = "bow-wow"; +Now when we evaluate ourDog.bark, we'll get his bark, "bow-wow". +
+ +## Instructions +
+Add a "bark" property to myDog and set it to a dog sound, such as "woof". You may use either dot or bracket notation. +
+ +## Tests +
+ +```yml +- text: Add the property "bark" to myDog. + testString: 'assert(myDog.bark !== undefined, "Add the property "bark" to myDog.");' +- text: Do not add "bark" to the setup section + testString: 'assert(!/bark[^\n]:/.test(code), "Do not add "bark" to the setup section");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +// Example +var ourDog = { + "name": "Camper", + "legs": 4, + "tails": 1, + "friends": ["everything!"] +}; + +ourDog.bark = "bow-wow"; + +// Setup +var myDog = { + "name": "Happy Coder", + "legs": 4, + "tails": 1, + "friends": ["freeCodeCamp Campers"] +}; + +// Only change code below this line. + +``` + +
+ + +### After Test +
+ +```js +console.info('after the test'); +``` + +
+ +
+ +## Solution +
+ + +```js +var myDog = { + "name": "Happy Coder", + "legs": 4, + "tails": 1, + "friends": ["freeCodeCamp Campers"] +}; +myDog.bark = "Woof Woof"; +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Add Two Numbers with JavaScript.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Add Two Numbers with JavaScript.md new file mode 100644 index 0000000000..66f9257bf0 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Add Two Numbers with JavaScript.md @@ -0,0 +1,66 @@ +--- +id: cf1111c1c11feddfaeb3bdef +title: Add Two Numbers with JavaScript +challengeType: 1 +--- + +## Description +
+Number is a data type in JavaScript which represents numeric data. +Now let's try to add two numbers using JavaScript. +JavaScript uses the + symbol as addition operation when placed between two numbers. +Example +
myVar = 5 + 10; // assigned 15
+
+ +## Instructions +
+Change the 0 so that sum will equal 20. +
+ +## Tests +
+ +```yml +- text: sum should equal 20 + testString: 'assert(sum === 20, "sum should equal 20");' +- text: Use the + operator + testString: 'assert(/\+/.test(code), "Use the + operator");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +var sum = 10 + 0; + +``` + +
+ + +### After Test +
+ +```js +console.info('after the test'); +``` + +
+ +
+ +## Solution +
+ + +```js +var sum = 10 + 10; +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Adding a Default Option in Switch Statements.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Adding a Default Option in Switch Statements.md new file mode 100644 index 0000000000..5582b7a1a1 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Adding a Default Option in Switch Statements.md @@ -0,0 +1,97 @@ +--- +id: 56533eb9ac21ba0edf2244de +title: Adding a Default Option in Switch Statements +challengeType: 1 +guideUrl: 'https://guide.freecodecamp.org/certificates/adding-a-default-option-in-switch-statements' +--- + +## Description +
+In a switch statement you may not be able to specify all possible values as case statements. Instead, you can add the default statement which will be executed if no matching case statements are found. Think of it like the final else statement in an if/else chain. +A default statement should be the last case. +
switch (num) {
  case value1:
    statement1;
    break;
  case value2:
    statement2;
    break;
...
  default:
    defaultStatement;
    break;
}
+
+ +## Instructions +
+Write a switch statement to set answer for the following conditions:
"a" - "apple"
"b" - "bird"
"c" - "cat"
default - "stuff" +
+ +## Tests +
+ +```yml +- text: switchOfStuff("a") should have a value of "apple" + testString: 'assert(switchOfStuff("a") === "apple", "switchOfStuff("a") should have a value of "apple"");' +- text: switchOfStuff("b") should have a value of "bird" + testString: 'assert(switchOfStuff("b") === "bird", "switchOfStuff("b") should have a value of "bird"");' +- text: switchOfStuff("c") should have a value of "cat" + testString: 'assert(switchOfStuff("c") === "cat", "switchOfStuff("c") should have a value of "cat"");' +- text: switchOfStuff("d") should have a value of "stuff" + testString: 'assert(switchOfStuff("d") === "stuff", "switchOfStuff("d") should have a value of "stuff"");' +- text: switchOfStuff(4) should have a value of "stuff" + testString: 'assert(switchOfStuff(4) === "stuff", "switchOfStuff(4) should have a value of "stuff"");' +- text: You should not use any if or else statements + testString: 'assert(!/else/g.test(code) || !/if/g.test(code), "You should not use any if or else statements");' +- text: You should use a default statement + testString: 'assert(switchOfStuff("string-to-trigger-default-case") === "stuff", "You should use a default statement");' +- text: You should have at least 3 break statements + testString: 'assert(code.match(/break/g).length > 2, "You should have at least 3 break statements");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +function switchOfStuff(val) { + var answer = ""; + // Only change code below this line + + + + // Only change code above this line + return answer; +} + +// Change this value to test +switchOfStuff(1); + +``` + +
+ + + +
+ +## Solution +
+ + +```js +function switchOfStuff(val) { + var answer = ""; + + switch(val) { + case "a": + answer = "apple"; + break; + case "b": + answer = "bird"; + break; + case "c": + answer = "cat"; + break; + default: + answer = "stuff"; + } + return answer; +} +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Appending Variables to Strings.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Appending Variables to Strings.md new file mode 100644 index 0000000000..0d598d0aab --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Appending Variables to Strings.md @@ -0,0 +1,77 @@ +--- +id: 56533eb9ac21ba0edf2244ed +title: Appending Variables to Strings +challengeType: 1 +guideUrl: 'https://guide.freecodecamp.org/certificates/appending-variables-to-strings' +--- + +## Description +
+Just as we can build a string over multiple lines out of string literals, we can also append variables to a string using the plus equals (+=) operator. +
+ +## Instructions +
+Set someAdjective and append it to myStr using the += operator. +
+ +## Tests +
+ +```yml +- text: someAdjective should be set to a string at least 3 characters long + testString: 'assert(typeof someAdjective !== "undefined" && someAdjective.length > 2, "someAdjective should be set to a string at least 3 characters long");' +- text: Append someAdjective to myStr using the += operator + testString: 'assert(code.match(/myStr\s*\+=\s*someAdjective\s*/).length > 0, "Append someAdjective to myStr using the += operator");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +// Example +var anAdjective = "awesome!"; +var ourStr = "freeCodeCamp is "; +ourStr += anAdjective; + +// Only change code below this line + +var someAdjective; +var myStr = "Learning to code is "; + +``` + +
+ + +### After Test +
+ +```js +console.info('after the test'); +``` + +
+ +
+ +## Solution +
+ + +```js +var anAdjective = "awesome!"; +var ourStr = "freeCodeCamp is "; +ourStr += anAdjective; + +var someAdjective = "neat"; +var myStr = "Learning to code is "; +myStr += someAdjective; +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Assignment with a Returned Value.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Assignment with a Returned Value.md new file mode 100644 index 0000000000..c363f7d393 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Assignment with a Returned Value.md @@ -0,0 +1,89 @@ +--- +id: 56533eb9ac21ba0edf2244c3 +title: Assignment with a Returned Value +challengeType: 1 +guideUrl: 'https://guide.freecodecamp.org/certificates/assignment-with-a-returned-value' +--- + +## Description +
+If you'll recall from our discussion of Storing Values with the Assignment Operator, everything to the right of the equal sign is resolved before the value is assigned. This means we can take the return value of a function and assign it to a variable. +Assume we have pre-defined a function sum which adds two numbers together, then: +ourSum = sum(5, 12); +will call sum function, which returns a value of 17 and assigns it to ourSum variable. +
+ +## Instructions +
+Call the processArg function with an argument of 7 and assign its return value to the variable processed. +
+ +## Tests +
+ +```yml +- text: processed should have a value of 2 + testString: 'assert(processed === 2, "processed should have a value of 2");' +- text: You should assign processArg to processed + testString: 'assert(/processed\s*=\s*processArg\(\s*7\s*\)\s*;/.test(code), "You should assign processArg to processed");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +// Example +var changed = 0; + +function change(num) { + return (num + 5) / 3; +} + +changed = change(10); + +// Setup +var processed = 0; + +function processArg(num) { + return (num + 3) / 5; +} + +// Only change code below this line + + +``` + +
+ + +### After Test +
+ +```js +console.info('after the test'); +``` + +
+ +
+ +## Solution +
+ + +```js +var processed = 0; + +function processArg(num) { + return (num + 3) / 5; +} + +processed = processArg(7); +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Build JavaScript Objects.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Build JavaScript Objects.md new file mode 100644 index 0000000000..11174d9769 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Build JavaScript Objects.md @@ -0,0 +1,95 @@ +--- +id: 56bbb991ad1ed5201cd392d0 +title: Build JavaScript Objects +challengeType: 1 +--- + +## Description +
+You may have heard the term object before. +Objects are similar to arrays, except that instead of using indexes to access and modify their data, you access the data in objects through what are called properties. +Objects are useful for storing data in a structured way, and can represent real world objects, like a cat. +Here's a sample cat object: +
var cat = {
  "name": "Whiskers",
  "legs": 4,
  "tails": 1,
  "enemies": ["Water", "Dogs"]
};
+In this example, all the properties are stored as strings, such as - "name", "legs", and "tails". However, you can also use numbers as properties. You can even omit the quotes for single-word string properties, as follows: +
var anotherObject = {
  make: "Ford",
  5: "five",
  "model": "focus"
};
+However, if your object has any non-string properties, JavaScript will automatically typecast them as strings. +
+ +## Instructions +
+Make an object that represents a dog called myDog which contains the properties "name" (a string), "legs", "tails" and "friends". +You can set these object properties to whatever values you want, as long "name" is a string, "legs" and "tails" are numbers, and "friends" is an array. +
+ +## Tests +
+ +```yml +- text: myDog should contain the property name and it should be a string. + testString: 'assert((function(z){if(z.hasOwnProperty("name") && z.name !== undefined && typeof z.name === "string"){return true;}else{return false;}})(myDog), "myDog should contain the property name and it should be a string.");' +- text: myDog should contain the property legs and it should be a number. + testString: 'assert((function(z){if(z.hasOwnProperty("legs") && z.legs !== undefined && typeof z.legs === "number"){return true;}else{return false;}})(myDog), "myDog should contain the property legs and it should be a number.");' +- text: myDog should contain the property tails and it should be a number. + testString: 'assert((function(z){if(z.hasOwnProperty("tails") && z.tails !== undefined && typeof z.tails === "number"){return true;}else{return false;}})(myDog), "myDog should contain the property tails and it should be a number.");' +- text: myDog should contain the property friends and it should be an array. + testString: 'assert((function(z){if(z.hasOwnProperty("friends") && z.friends !== undefined && Array.isArray(z.friends)){return true;}else{return false;}})(myDog), "myDog should contain the property friends and it should be an array.");' +- text: myDog should only contain all the given properties. + testString: 'assert((function(z){return Object.keys(z).length === 4;})(myDog), "myDog should only contain all the given properties.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +// Example +var ourDog = { + "name": "Camper", + "legs": 4, + "tails": 1, + "friends": ["everything!"] +}; + +// Only change code below this line. + +var myDog = { + + + + +}; +``` + +
+ + +### After Test +
+ +```js +console.info('after the test'); +``` + +
+ +
+ +## Solution +
+ + +```js +var myDog = { + "name": "Camper", + "legs": 4, + "tails": 1, + "friends": ["everything!"] +}; +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Chaining If Else Statements.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Chaining If Else Statements.md new file mode 100644 index 0000000000..f796aa9e05 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Chaining If Else Statements.md @@ -0,0 +1,98 @@ +--- +id: 56533eb9ac21ba0edf2244dc +title: Chaining If Else Statements +challengeType: 1 +--- + +## Description +
+if/else statements can be chained together for complex logic. Here is pseudocode of multiple chained if / else if statements: +
if (condition1) {
  statement1
} else if (condition2) {
  statement2
} else if (condition3) {
  statement3
. . .
} else {
  statementN
}
+
+ +## Instructions +
+Write chained if/else if statements to fulfill the following conditions: +num < 5 - return "Tiny"
num < 10 - return "Small"
num < 15 - return "Medium"
num < 20 - return "Large"
num >= 20 - return "Huge" +
+ +## Tests +
+ +```yml +- text: You should have at least four else statements + testString: 'assert(code.match(/else/g).length > 3, "You should have at least four else statements");' +- text: You should have at least four if statements + testString: 'assert(code.match(/if/g).length > 3, "You should have at least four if statements");' +- text: You should have at least one return statement + testString: 'assert(code.match(/return/g).length >= 1, "You should have at least one return statement");' +- text: testSize(0) should return "Tiny" + testString: 'assert(testSize(0) === "Tiny", "testSize(0) should return "Tiny"");' +- text: testSize(4) should return "Tiny" + testString: 'assert(testSize(4) === "Tiny", "testSize(4) should return "Tiny"");' +- text: testSize(5) should return "Small" + testString: 'assert(testSize(5) === "Small", "testSize(5) should return "Small"");' +- text: testSize(8) should return "Small" + testString: 'assert(testSize(8) === "Small", "testSize(8) should return "Small"");' +- text: testSize(10) should return "Medium" + testString: 'assert(testSize(10) === "Medium", "testSize(10) should return "Medium"");' +- text: testSize(14) should return "Medium" + testString: 'assert(testSize(14) === "Medium", "testSize(14) should return "Medium"");' +- text: testSize(15) should return "Large" + testString: 'assert(testSize(15) === "Large", "testSize(15) should return "Large"");' +- text: testSize(17) should return "Large" + testString: 'assert(testSize(17) === "Large", "testSize(17) should return "Large"");' +- text: testSize(20) should return "Huge" + testString: 'assert(testSize(20) === "Huge", "testSize(20) should return "Huge"");' +- text: testSize(25) should return "Huge" + testString: 'assert(testSize(25) === "Huge", "testSize(25) should return "Huge"");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +function testSize(num) { + // Only change code below this line + + + return "Change Me"; + // Only change code above this line +} + +// Change this value to test +testSize(7); +``` + +
+ + + +
+ +## Solution +
+ + +```js +function testSize(num) { + if (num < 5) { + return "Tiny"; + } else if (num < 10) { + return "Small"; + } else if (num < 15) { + return "Medium"; + } else if (num < 20) { + return "Large"; + } else { + return "Huge"; + } +} +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Comment Your JavaScript Code.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Comment Your JavaScript Code.md new file mode 100644 index 0000000000..78060ccaa7 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Comment Your JavaScript Code.md @@ -0,0 +1,60 @@ +--- +id: bd7123c9c441eddfaeb4bdef +title: Comment Your JavaScript Code +challengeType: 1 +--- + +## Description +
+Comments are lines of code that JavaScript will intentionally ignore. Comments are a great way to leave notes to yourself and to other people who will later need to figure out what that code does. +There are two ways to write comments in JavaScript: +Using // will tell JavaScript to ignore the remainder of the text on the current line: +
// This is an in-line comment.
+You can make a multi-line comment beginning with /* and ending with */: +
/* This is a
multi-line comment */
+Best Practice
As you write code, you should regularly add comments to clarify the function of parts of your code. Good commenting can help communicate the intent of your code—both for others and for your future self. +
+ +## Instructions +
+Try creating one of each type of comment. +
+ +## Tests +
+ +```yml +- text: Create a // style comment that contains at least five letters. + testString: 'assert(code.match(/(\/\/)...../g), "Create a // style comment that contains at least five letters.");' +- text: Create a /* */ style comment that contains at least five letters. + testString: 'assert(code.match(/(\/\*)([^\/]{5,})(?=\*\/)/gm), "Create a /* */ style comment that contains at least five letters.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js + +``` + +
+ + + +
+ +## Solution +
+ + +```js +// Fake Comment +/* Another Comment */ +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Comparison with the Equality Operator.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Comparison with the Equality Operator.md new file mode 100644 index 0000000000..366efbefb6 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Comparison with the Equality Operator.md @@ -0,0 +1,76 @@ +--- +id: 56533eb9ac21ba0edf2244d0 +title: Comparison with the Equality Operator +challengeType: 1 +--- + +## Description +
+There are many Comparison Operators in JavaScript. All of these operators return a boolean true or false value. +The most basic operator is the equality operator ==. The equality operator compares two values and returns true if they're equivalent or false if they are not. Note that equality is different from assignment (=), which assigns the value at the right of the operator to a variable in the left. +
function equalityTest(myVal) {
  if (myVal == 10) {
     return "Equal";
  }
  return "Not Equal";
}
+If myVal is equal to 10, the equality operator returns true, so the code in the curly braces will execute, and the function will return "Equal". Otherwise, the function will return "Not Equal". +In order for JavaScript to compare two different data types (for example, numbers and strings), it must convert one type to another. This is known as "Type Coercion". Once it does, however, it can compare terms as follows: +
1 == 1 // true
1 == 2 // false
1 == '1' // true
"3" == 3 // true
+
+ +## Instructions +
+Add the equality operator to the indicated line so that the function will return "Equal" when val is equivalent to 12 +
+ +## Tests +
+ +```yml +- text: testEqual(10) should return "Not Equal" + testString: 'assert(testEqual(10) === "Not Equal", "testEqual(10) should return "Not Equal"");' +- text: testEqual(12) should return "Equal" + testString: 'assert(testEqual(12) === "Equal", "testEqual(12) should return "Equal"");' +- text: testEqual("12") should return "Equal" + testString: 'assert(testEqual("12") === "Equal", "testEqual("12") should return "Equal"");' +- text: You should use the == operator + testString: 'assert(code.match(/==/g) && !code.match(/===/g), "You should use the == operator");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +// Setup +function testEqual(val) { + if (val) { // Change this line + return "Equal"; + } + return "Not Equal"; +} + +// Change this value to test +testEqual(10); +``` + +
+ + + +
+ +## Solution +
+ + +```js +function testEqual(val) { + if (val == 12) { + return "Equal"; + } + return "Not Equal"; +} +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Comparison with the Greater Than Operator.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Comparison with the Greater Than Operator.md new file mode 100644 index 0000000000..b27cc4e860 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Comparison with the Greater Than Operator.md @@ -0,0 +1,89 @@ +--- +id: 56533eb9ac21ba0edf2244d4 +title: Comparison with the Greater Than Operator +challengeType: 1 +--- + +## Description +
+The greater than operator (>) compares the values of two numbers. If the number to the left is greater than the number to the right, it returns true. Otherwise, it returns false. +Like the equality operator, greater than operator will convert data types of values while comparing. +Examples +
5 > 3 // true
7 > '3' // true
2 > 3 // false
'1' > 9 // false
+
+ +## Instructions +
+Add the greater than operator to the indicated lines so that the return statements make sense. +
+ +## Tests +
+ +```yml +- text: testGreaterThan(0) should return "10 or Under" + testString: 'assert(testGreaterThan(0) === "10 or Under", "testGreaterThan(0) should return "10 or Under"");' +- text: testGreaterThan(10) should return "10 or Under" + testString: 'assert(testGreaterThan(10) === "10 or Under", "testGreaterThan(10) should return "10 or Under"");' +- text: testGreaterThan(11) should return "Over 10" + testString: 'assert(testGreaterThan(11) === "Over 10", "testGreaterThan(11) should return "Over 10"");' +- text: testGreaterThan(99) should return "Over 10" + testString: 'assert(testGreaterThan(99) === "Over 10", "testGreaterThan(99) should return "Over 10"");' +- text: testGreaterThan(100) should return "Over 10" + testString: 'assert(testGreaterThan(100) === "Over 10", "testGreaterThan(100) should return "Over 10"");' +- text: testGreaterThan(101) should return "Over 100" + testString: 'assert(testGreaterThan(101) === "Over 100", "testGreaterThan(101) should return "Over 100"");' +- text: testGreaterThan(150) should return "Over 100" + testString: 'assert(testGreaterThan(150) === "Over 100", "testGreaterThan(150) should return "Over 100"");' +- text: You should use the > operator at least twice + testString: 'assert(code.match(/val\s*>\s*("|")*\d+("|")*/g).length > 1, "You should use the > operator at least twice");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +function testGreaterThan(val) { + if (val) { // Change this line + return "Over 100"; + } + + if (val) { // Change this line + return "Over 10"; + } + + return "10 or Under"; +} + +// Change this value to test +testGreaterThan(10); +``` + +
+ + + +
+ +## Solution +
+ + +```js +function testGreaterThan(val) { + if (val > 100) { // Change this line + return "Over 100"; + } + if (val > 10) { // Change this line + return "Over 10"; + } + return "10 or Under"; +} +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Comparison with the Greater Than Or Equal To Operator.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Comparison with the Greater Than Or Equal To Operator.md new file mode 100644 index 0000000000..ffc2803e8d --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Comparison with the Greater Than Or Equal To Operator.md @@ -0,0 +1,91 @@ +--- +id: 56533eb9ac21ba0edf2244d5 +title: Comparison with the Greater Than Or Equal To Operator +challengeType: 1 +--- + +## Description +
+The greater than or equal to operator (>=) compares the values of two numbers. If the number to the left is greater than or equal to the number to the right, it returns true. Otherwise, it returns false. +Like the equality operator, greater than or equal to operator will convert data types while comparing. +Examples +
6 >= 6 // true
7 >= '3' // true
2 >= 3 // false
'7' >= 9 // false
+
+ +## Instructions +
+Add the greater than or equal to operator to the indicated lines so that the return statements make sense. +
+ +## Tests +
+ +```yml +- text: testGreaterOrEqual(0) should return "Less than 10" + testString: 'assert(testGreaterOrEqual(0) === "Less than 10", "testGreaterOrEqual(0) should return "Less than 10"");' +- text: testGreaterOrEqual(9) should return "Less than 10" + testString: 'assert(testGreaterOrEqual(9) === "Less than 10", "testGreaterOrEqual(9) should return "Less than 10"");' +- text: testGreaterOrEqual(10) should return "10 or Over" + testString: 'assert(testGreaterOrEqual(10) === "10 or Over", "testGreaterOrEqual(10) should return "10 or Over"");' +- text: testGreaterOrEqual(11) should return "10 or Over" + testString: 'assert(testGreaterOrEqual(11) === "10 or Over", "testGreaterOrEqual(11) should return "10 or Over"");' +- text: testGreaterOrEqual(19) should return "10 or Over" + testString: 'assert(testGreaterOrEqual(19) === "10 or Over", "testGreaterOrEqual(19) should return "10 or Over"");' +- text: testGreaterOrEqual(100) should return "20 or Over" + testString: 'assert(testGreaterOrEqual(100) === "20 or Over", "testGreaterOrEqual(100) should return "20 or Over"");' +- text: testGreaterOrEqual(21) should return "20 or Over" + testString: 'assert(testGreaterOrEqual(21) === "20 or Over", "testGreaterOrEqual(21) should return "20 or Over"");' +- text: You should use the >= operator at least twice + testString: 'assert(code.match(/val\s*>=\s*("|")*\d+("|")*/g).length > 1, "You should use the >= operator at least twice");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +function testGreaterOrEqual(val) { + if (val) { // Change this line + return "20 or Over"; + } + + if (val) { // Change this line + return "10 or Over"; + } + + return "Less than 10"; +} + +// Change this value to test +testGreaterOrEqual(10); +``` + +
+ + + +
+ +## Solution +
+ + +```js +function testGreaterOrEqual(val) { + if (val >= 20) { // Change this line + return "20 or Over"; + } + + if (val >= 10) { // Change this line + return "10 or Over"; + } + + return "Less than 10"; +} +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Comparison with the Inequality Operator.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Comparison with the Inequality Operator.md new file mode 100644 index 0000000000..33125c0b19 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Comparison with the Inequality Operator.md @@ -0,0 +1,77 @@ +--- +id: 56533eb9ac21ba0edf2244d2 +title: Comparison with the Inequality Operator +challengeType: 1 +--- + +## Description +
+The inequality operator (!=) is the opposite of the equality operator. It means "Not Equal" and returns false where equality would return true and vice versa. Like the equality operator, the inequality operator will convert data types of values while comparing. +Examples +
1 != 2 // true
1 != "1" // false
1 != '1' // false
1 != true // false
0 != false // false
+
+ +## Instructions +
+Add the inequality operator != in the if statement so that the function will return "Not Equal" when val is not equivalent to 99 +
+ +## Tests +
+ +```yml +- text: testNotEqual(99) should return "Equal" + testString: 'assert(testNotEqual(99) === "Equal", "testNotEqual(99) should return "Equal"");' +- text: testNotEqual("99") should return "Equal" + testString: 'assert(testNotEqual("99") === "Equal", "testNotEqual("99") should return "Equal"");' +- text: testNotEqual(12) should return "Not Equal" + testString: 'assert(testNotEqual(12) === "Not Equal", "testNotEqual(12) should return "Not Equal"");' +- text: testNotEqual("12") should return "Not Equal" + testString: 'assert(testNotEqual("12") === "Not Equal", "testNotEqual("12") should return "Not Equal"");' +- text: testNotEqual("bob") should return "Not Equal" + testString: 'assert(testNotEqual("bob") === "Not Equal", "testNotEqual("bob") should return "Not Equal"");' +- text: You should use the != operator + testString: 'assert(code.match(/(?!!==)!=/), "You should use the != operator");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +// Setup +function testNotEqual(val) { + if (val) { // Change this line + return "Not Equal"; + } + return "Equal"; +} + +// Change this value to test +testNotEqual(10); +``` + +
+ + + +
+ +## Solution +
+ + +```js +function testNotEqual(val) { + if (val != 99) { + return "Not Equal"; + } + return "Equal"; +} +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Comparison with the Less Than Operator.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Comparison with the Less Than Operator.md new file mode 100644 index 0000000000..0aa0f05509 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Comparison with the Less Than Operator.md @@ -0,0 +1,88 @@ +--- +id: 56533eb9ac21ba0edf2244d6 +title: Comparison with the Less Than Operator +challengeType: 1 +--- + +## Description +
+The less than operator (<) compares the values of two numbers. If the number to the left is less than the number to the right, it returns true. Otherwise, it returns false. Like the equality operator, less than operator converts data types while comparing. +Examples +
2 < 5 // true
'3' < 7 // true
5 < 5 // false
3 < 2 // false
'8' < 4 // false
+
+ +## Instructions +
+Add the less than operator to the indicated lines so that the return statements make sense. +
+ +## Tests +
+ +```yml +- text: testLessThan(0) should return "Under 25" + testString: 'assert(testLessThan(0) === "Under 25", "testLessThan(0) should return "Under 25"");' +- text: testLessThan(24) should return "Under 25" + testString: 'assert(testLessThan(24) === "Under 25", "testLessThan(24) should return "Under 25"");' +- text: testLessThan(25) should return "Under 55" + testString: 'assert(testLessThan(25) === "Under 55", "testLessThan(25) should return "Under 55"");' +- text: testLessThan(54) should return "Under 55" + testString: 'assert(testLessThan(54) === "Under 55", "testLessThan(54) should return "Under 55"");' +- text: testLessThan(55) should return "55 or Over" + testString: 'assert(testLessThan(55) === "55 or Over", "testLessThan(55) should return "55 or Over"");' +- text: testLessThan(99) should return "55 or Over" + testString: 'assert(testLessThan(99) === "55 or Over", "testLessThan(99) should return "55 or Over"");' +- text: You should use the < operator at least twice + testString: 'assert(code.match(/val\s*<\s*("|")*\d+("|")*/g).length > 1, "You should use the < operator at least twice");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +function testLessThan(val) { + if (val) { // Change this line + return "Under 25"; + } + + if (val) { // Change this line + return "Under 55"; + } + + return "55 or Over"; +} + +// Change this value to test +testLessThan(10); +``` + +
+ + + +
+ +## Solution +
+ + +```js +function testLessThan(val) { + if (val < 25) { // Change this line + return "Under 25"; + } + + if (val < 55) { // Change this line + return "Under 55"; + } + + return "55 or Over"; +} +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Comparison with the Less Than Or Equal To Operator.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Comparison with the Less Than Or Equal To Operator.md new file mode 100644 index 0000000000..39f3b88c55 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Comparison with the Less Than Or Equal To Operator.md @@ -0,0 +1,91 @@ +--- +id: 56533eb9ac21ba0edf2244d7 +title: Comparison with the Less Than Or Equal To Operator +challengeType: 1 +--- + +## Description +
+The less than or equal to operator (<=) compares the values of two numbers. If the number to the left is less than or equal to the number to the right, it returns true. If the number on the left is greater than the number on the right, it returns false. Like the equality operator, less than or equal to converts data types. +Examples +
4 <= 5 // true
'7' <= 7 // true
5 <= 5 // true
3 <= 2 // false
'8' <= 4 // false
+
+ +## Instructions +
+Add the less than or equal to operator to the indicated lines so that the return statements make sense. +
+ +## Tests +
+ +```yml +- text: testLessOrEqual(0) should return "Smaller Than or Equal to 12" + testString: 'assert(testLessOrEqual(0) === "Smaller Than or Equal to 12", "testLessOrEqual(0) should return "Smaller Than or Equal to 12"");' +- text: testLessOrEqual(11) should return "Smaller Than or Equal to 12" + testString: 'assert(testLessOrEqual(11) === "Smaller Than or Equal to 12", "testLessOrEqual(11) should return "Smaller Than or Equal to 12"");' +- text: testLessOrEqual(12) should return "Smaller Than or Equal to 12" + testString: 'assert(testLessOrEqual(12) === "Smaller Than or Equal to 12", "testLessOrEqual(12) should return "Smaller Than or Equal to 12"");' +- text: testLessOrEqual(23) should return "Smaller Than or Equal to 24" + testString: 'assert(testLessOrEqual(23) === "Smaller Than or Equal to 24", "testLessOrEqual(23) should return "Smaller Than or Equal to 24"");' +- text: testLessOrEqual(24) should return "Smaller Than or Equal to 24" + testString: 'assert(testLessOrEqual(24) === "Smaller Than or Equal to 24", "testLessOrEqual(24) should return "Smaller Than or Equal to 24"");' +- text: testLessOrEqual(25) should return "More Than 24" + testString: 'assert(testLessOrEqual(25) === "More Than 24", "testLessOrEqual(25) should return "More Than 24"");' +- text: testLessOrEqual(55) should return "More Than 24" + testString: 'assert(testLessOrEqual(55) === "More Than 24", "testLessOrEqual(55) should return "More Than 24"");' +- text: You should use the <= operator at least twice + testString: 'assert(code.match(/val\s*<=\s*("|")*\d+("|")*/g).length > 1, "You should use the <= operator at least twice");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +function testLessOrEqual(val) { + if (val) { // Change this line + return "Smaller Than or Equal to 12"; + } + + if (val) { // Change this line + return "Smaller Than or Equal to 24"; + } + + return "More Than 24"; +} + +// Change this value to test +testLessOrEqual(10); + +``` + +
+ + + +
+ +## Solution +
+ + +```js +function testLessOrEqual(val) { + if (val <= 12) { // Change this line + return "Smaller Than or Equal to 12"; + } + + if (val <= 24) { // Change this line + return "Smaller Than or Equal to 24"; + } + + return "More Than 24"; +} +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Comparison with the Strict Equality Operator.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Comparison with the Strict Equality Operator.md new file mode 100644 index 0000000000..7bec442ed6 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Comparison with the Strict Equality Operator.md @@ -0,0 +1,75 @@ +--- +id: 56533eb9ac21ba0edf2244d1 +title: Comparison with the Strict Equality Operator +challengeType: 1 +--- + +## Description +
+Strict equality (===) is the counterpart to the equality operator (==). However, unlike the equality operator, which attempts to convert both values being compared to a common type, the strict equality operator does not perform a type conversion. +If the values being compared have different types, they are considered unequal, and the strict equality operator will return false. +Examples +
3 === 3 // true
3 === '3' // false
+In the second example, 3 is a Number type and '3' is a String type. +
+ +## Instructions +
+Use the strict equality operator in the if statement so the function will return "Equal" when val is strictly equal to 7 +
+ +## Tests +
+ +```yml +- text: testStrict(10) should return "Not Equal" + testString: 'assert(testStrict(10) === "Not Equal", "testStrict(10) should return "Not Equal"");' +- text: testStrict(7) should return "Equal" + testString: 'assert(testStrict(7) === "Equal", "testStrict(7) should return "Equal"");' +- text: testStrict("7") should return "Not Equal" + testString: 'assert(testStrict("7") === "Not Equal", "testStrict("7") should return "Not Equal"");' +- text: You should use the === operator + testString: 'assert(code.match(/(val\s*===\s*\d+)|(\d+\s*===\s*val)/g).length > 0, "You should use the === operator");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +// Setup +function testStrict(val) { + if (val) { // Change this line + return "Equal"; + } + return "Not Equal"; +} + +// Change this value to test +testStrict(10); +``` + +
+ + + +
+ +## Solution +
+ + +```js +function testStrict(val) { + if (val === 7) { + return "Equal"; + } + return "Not Equal"; +} +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Comparison with the Strict Inequality Operator.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Comparison with the Strict Inequality Operator.md new file mode 100644 index 0000000000..6f0bb9610f --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Comparison with the Strict Inequality Operator.md @@ -0,0 +1,80 @@ +--- +id: 56533eb9ac21ba0edf2244d3 +title: Comparison with the Strict Inequality Operator +challengeType: 1 +--- + +## Description +
+The strict inequality operator (!==) is the logical opposite of the strict equality operator. It means "Strictly Not Equal" and returns false where strict equality would return true and vice versa. Strict inequality will not convert data types. +Examples +
3 !== 3 // false
3 !== '3' // true
4 !== 3 // true
+
+ +## Instructions +
+Add the strict inequality operator to the if statement so the function will return "Not Equal" when val is not strictly equal to 17 +
+ +## Tests +
+ +```yml +- text: testStrictNotEqual(17) should return "Equal" + testString: 'assert(testStrictNotEqual(17) === "Equal", "testStrictNotEqual(17) should return "Equal"");' +- text: testStrictNotEqual("17") should return "Not Equal" + testString: 'assert(testStrictNotEqual("17") === "Not Equal", "testStrictNotEqual("17") should return "Not Equal"");' +- text: testStrictNotEqual(12) should return "Not Equal" + testString: 'assert(testStrictNotEqual(12) === "Not Equal", "testStrictNotEqual(12) should return "Not Equal"");' +- text: testStrictNotEqual("bob") should return "Not Equal" + testString: 'assert(testStrictNotEqual("bob") === "Not Equal", "testStrictNotEqual("bob") should return "Not Equal"");' +- text: You should use the !== operator + testString: 'assert(code.match(/(val\s*!==\s*\d+)|(\d+\s*!==\s*val)/g).length > 0, "You should use the !== operator");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +// Setup +function testStrictNotEqual(val) { + // Only Change Code Below this Line + + if (val) { + + // Only Change Code Above this Line + + return "Not Equal"; + } + return "Equal"; +} + +// Change this value to test +testStrictNotEqual(10); +``` + +
+ + + +
+ +## Solution +
+ + +```js +function testStrictNotEqual(val) { + if (val !== 17) { + return "Not Equal"; + } + return "Equal"; +} +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Comparisons with the Logical And Operator.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Comparisons with the Logical And Operator.md new file mode 100644 index 0000000000..48237ebc0a --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Comparisons with the Logical And Operator.md @@ -0,0 +1,92 @@ +--- +id: 56533eb9ac21ba0edf2244d8 +title: Comparisons with the Logical And Operator +challengeType: 1 +--- + +## Description +
+Sometimes you will need to test more than one thing at a time. The logical and operator (&&) returns true if and only if the operands to the left and right of it are true. +The same effect could be achieved by nesting an if statement inside another if: +
if (num > 5) {
  if (num < 10) {
    return "Yes";
  }
}
return "No";
+will only return "Yes" if num is greater than 5 and less than 10. The same logic can be written as: +
if (num > 5 && num < 10) {
  return "Yes";
}
return "No";
+
+ +## Instructions +
+Combine the two if statements into one statement which will return "Yes" if val is less than or equal to 50 and greater than or equal to 25. Otherwise, will return "No". +
+ +## Tests +
+ +```yml +- text: You should use the && operator once + testString: 'assert(code.match(/&&/g).length === 1, "You should use the && operator once");' +- text: You should only have one if statement + testString: 'assert(code.match(/if/g).length === 1, "You should only have one if statement");' +- text: testLogicalAnd(0) should return "No" + testString: 'assert(testLogicalAnd(0) === "No", "testLogicalAnd(0) should return "No"");' +- text: testLogicalAnd(24) should return "No" + testString: 'assert(testLogicalAnd(24) === "No", "testLogicalAnd(24) should return "No"");' +- text: testLogicalAnd(25) should return "Yes" + testString: 'assert(testLogicalAnd(25) === "Yes", "testLogicalAnd(25) should return "Yes"");' +- text: testLogicalAnd(30) should return "Yes" + testString: 'assert(testLogicalAnd(30) === "Yes", "testLogicalAnd(30) should return "Yes"");' +- text: testLogicalAnd(50) should return "Yes" + testString: 'assert(testLogicalAnd(50) === "Yes", "testLogicalAnd(50) should return "Yes"");' +- text: testLogicalAnd(51) should return "No" + testString: 'assert(testLogicalAnd(51) === "No", "testLogicalAnd(51) should return "No"");' +- text: testLogicalAnd(75) should return "No" + testString: 'assert(testLogicalAnd(75) === "No", "testLogicalAnd(75) should return "No"");' +- text: testLogicalAnd(80) should return "No" + testString: 'assert(testLogicalAnd(80) === "No", "testLogicalAnd(80) should return "No"");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +function testLogicalAnd(val) { + // Only change code below this line + + if (val) { + if (val) { + return "Yes"; + } + } + + // Only change code above this line + return "No"; +} + +// Change this value to test +testLogicalAnd(10); +``` + +
+ + + +
+ +## Solution +
+ + +```js +function testLogicalAnd(val) { + if (val >= 25 && val <= 50) { + return "Yes"; + } + return "No"; +} +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Comparisons with the Logical Or Operator.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Comparisons with the Logical Or Operator.md new file mode 100644 index 0000000000..bfb243997b --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Comparisons with the Logical Or Operator.md @@ -0,0 +1,95 @@ +--- +id: 56533eb9ac21ba0edf2244d9 +title: Comparisons with the Logical Or Operator +challengeType: 1 +--- + +## Description +
+The logical or operator (||) returns true if either of the operands is true. Otherwise, it returns false. +The logical or operator is composed of two pipe symbols (|). This can typically be found between your Backspace and Enter keys. +The pattern below should look familiar from prior waypoints: +
if (num > 10) {
  return "No";
}
if (num < 5) {
  return "No";
}
return "Yes";
+will return "Yes" only if num is between 5 and 10 (5 and 10 included). The same logic can be written as: +
if (num > 10 || num < 5) {
  return "No";
}
return "Yes";
+
+ +## Instructions +
+Combine the two if statements into one statement which returns "Outside" if val is not between 10 and 20, inclusive. Otherwise, return "Inside". +
+ +## Tests +
+ +```yml +- text: You should use the || operator once + testString: 'assert(code.match(/\|\|/g).length === 1, "You should use the || operator once");' +- text: You should only have one if statement + testString: 'assert(code.match(/if/g).length === 1, "You should only have one if statement");' +- text: testLogicalOr(0) should return "Outside" + testString: 'assert(testLogicalOr(0) === "Outside", "testLogicalOr(0) should return "Outside"");' +- text: testLogicalOr(9) should return "Outside" + testString: 'assert(testLogicalOr(9) === "Outside", "testLogicalOr(9) should return "Outside"");' +- text: testLogicalOr(10) should return "Inside" + testString: 'assert(testLogicalOr(10) === "Inside", "testLogicalOr(10) should return "Inside"");' +- text: testLogicalOr(15) should return "Inside" + testString: 'assert(testLogicalOr(15) === "Inside", "testLogicalOr(15) should return "Inside"");' +- text: testLogicalOr(19) should return "Inside" + testString: 'assert(testLogicalOr(19) === "Inside", "testLogicalOr(19) should return "Inside"");' +- text: testLogicalOr(20) should return "Inside" + testString: 'assert(testLogicalOr(20) === "Inside", "testLogicalOr(20) should return "Inside"");' +- text: testLogicalOr(21) should return "Outside" + testString: 'assert(testLogicalOr(21) === "Outside", "testLogicalOr(21) should return "Outside"");' +- text: testLogicalOr(25) should return "Outside" + testString: 'assert(testLogicalOr(25) === "Outside", "testLogicalOr(25) should return "Outside"");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +function testLogicalOr(val) { + // Only change code below this line + + if (val) { + return "Outside"; + } + + if (val) { + return "Outside"; + } + + // Only change code above this line + return "Inside"; +} + +// Change this value to test +testLogicalOr(15); +``` + +
+ + + +
+ +## Solution +
+ + +```js +function testLogicalOr(val) { + if (val < 10 || val > 20) { + return "Outside"; + } + return "Inside"; +} +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Compound Assignment With Augmented Addition.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Compound Assignment With Augmented Addition.md new file mode 100644 index 0000000000..f7877eabad --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Compound Assignment With Augmented Addition.md @@ -0,0 +1,86 @@ +--- +id: 56533eb9ac21ba0edf2244af +title: Compound Assignment With Augmented Addition +challengeType: 1 +--- + +## Description +
+In programming, it is common to use assignments to modify the contents of a variable. Remember that everything to the right of the equals sign is evaluated first, so we can say: +myVar = myVar + 5; +to add 5 to myVar. Since this is such a common pattern, there are operators which do both a mathematical operation and assignment in one step. +One such operator is the += operator. +
var myVar = 1;
myVar += 5;
console.log(myVar); // Returns 6
+
+ +## Instructions +
+Convert the assignments for a, b, and c to use the += operator. +
+ +## Tests +
+ +```yml +- text: a should equal 15 + testString: 'assert(a === 15, "a should equal 15");' +- text: b should equal 26 + testString: 'assert(b === 26, "b should equal 26");' +- text: c should equal 19 + testString: 'assert(c === 19, "c should equal 19");' +- text: You should use the += operator for each variable + testString: 'assert(code.match(/\+=/g).length === 3, "You should use the += operator for each variable");' +- text: Do not modify the code above the line + testString: 'assert(/var a = 3;/.test(code) && /var b = 17;/.test(code) && /var c = 12;/.test(code), "Do not modify the code above the line");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +var a = 3; +var b = 17; +var c = 12; + +// Only modify code below this line + +a = a + 12; +b = 9 + b; +c = c + 7; + +``` + +
+ + +### After Test +
+ +```js +console.info('after the test'); +``` + +
+ +
+ +## Solution +
+ + +```js +var a = 3; +var b = 17; +var c = 12; + +a += 12; +b += 9; +c += 7; +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Compound Assignment With Augmented Division.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Compound Assignment With Augmented Division.md new file mode 100644 index 0000000000..7509bc7bbe --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Compound Assignment With Augmented Division.md @@ -0,0 +1,85 @@ +--- +id: 56533eb9ac21ba0edf2244b2 +title: Compound Assignment With Augmented Division +challengeType: 1 +--- + +## Description +
+The /= operator divides a variable by another number. +myVar = myVar / 5; +Will divide myVar by 5. This can be rewritten as: +myVar /= 5; +
+ +## Instructions +
+Convert the assignments for a, b, and c to use the /= operator. +
+ +## Tests +
+ +```yml +- text: a should equal 4 + testString: 'assert(a === 4, "a should equal 4");' +- text: b should equal 27 + testString: 'assert(b === 27, "b should equal 27");' +- text: c should equal 3 + testString: 'assert(c === 3, "c should equal 3");' +- text: You should use the /= operator for each variable + testString: 'assert(code.match(/\/=/g).length === 3, "You should use the /= operator for each variable");' +- text: Do not modify the code above the line + testString: 'assert(/var a = 48;/.test(code) && /var b = 108;/.test(code) && /var c = 33;/.test(code), "Do not modify the code above the line");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +var a = 48; +var b = 108; +var c = 33; + +// Only modify code below this line + +a = a / 12; +b = b / 4; +c = c / 11; + +``` + +
+ + +### After Test +
+ +```js +console.info('after the test'); +``` + +
+ +
+ +## Solution +
+ + +```js +var a = 48; +var b = 108; +var c = 33; + +a /= 12; +b /= 4; +c /= 11; +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Compound Assignment With Augmented Multiplication.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Compound Assignment With Augmented Multiplication.md new file mode 100644 index 0000000000..667eb4704b --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Compound Assignment With Augmented Multiplication.md @@ -0,0 +1,86 @@ +--- +id: 56533eb9ac21ba0edf2244b1 +title: Compound Assignment With Augmented Multiplication +challengeType: 1 +--- + +## Description +
+The *= operator multiplies a variable by a number. +myVar = myVar * 5; +will multiply myVar by 5. This can be rewritten as: +myVar *= 5; +
+ +## Instructions +
+Convert the assignments for a, b, and c to use the *= operator. +
+ +## Tests +
+ +```yml +- text: a should equal 25 + testString: 'assert(a === 25, "a should equal 25");' +- text: b should equal 36 + testString: 'assert(b === 36, "b should equal 36");' +- text: c should equal 46 + testString: 'assert(c === 46, "c should equal 46");' +- text: You should use the *= operator for each variable + testString: 'assert(code.match(/\*=/g).length === 3, "You should use the *= operator for each variable");' +- text: Do not modify the code above the line + testString: 'assert(/var a = 5;/.test(code) && /var b = 12;/.test(code) && /var c = 4\.6;/.test(code), "Do not modify the code above the line");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +var a = 5; +var b = 12; +var c = 4.6; + +// Only modify code below this line + +a = a * 5; +b = 3 * b; +c = c * 10; + + +``` + +
+ + +### After Test +
+ +```js +console.info('after the test'); +``` + +
+ +
+ +## Solution +
+ + +```js +var a = 5; +var b = 12; +var c = 4.6; + +a *= 5; +b *= 3; +c *= 10; +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Compound Assignment With Augmented Subtraction.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Compound Assignment With Augmented Subtraction.md new file mode 100644 index 0000000000..92e3aa91d1 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Compound Assignment With Augmented Subtraction.md @@ -0,0 +1,88 @@ +--- +id: 56533eb9ac21ba0edf2244b0 +title: Compound Assignment With Augmented Subtraction +challengeType: 1 +--- + +## Description +
+Like the += operator, -= subtracts a number from a variable. +myVar = myVar - 5; +will subtract 5 from myVar. This can be rewritten as: +myVar -= 5; +
+ +## Instructions +
+Convert the assignments for a, b, and c to use the -= operator. +
+ +## Tests +
+ +```yml +- text: a should equal 5 + testString: 'assert(a === 5, "a should equal 5");' +- text: b should equal -6 + testString: 'assert(b === -6, "b should equal -6");' +- text: c should equal 2 + testString: 'assert(c === 2, "c should equal 2");' +- text: You should use the -= operator for each variable + testString: 'assert(code.match(/-=/g).length === 3, "You should use the -= operator for each variable");' +- text: Do not modify the code above the line + testString: 'assert(/var a = 11;/.test(code) && /var b = 9;/.test(code) && /var c = 3;/.test(code), "Do not modify the code above the line");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +var a = 11; +var b = 9; +var c = 3; + +// Only modify code below this line + +a = a - 6; +b = b - 15; +c = c - 1; + + +``` + +
+ + +### After Test +
+ +```js +console.info('after the test'); +``` + +
+ +
+ +## Solution +
+ + +```js +var a = 11; +var b = 9; +var c = 3; + +a -= 6; +b -= 15; +c -= 1; + + +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Concatenating Strings with Plus Operator.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Concatenating Strings with Plus Operator.md new file mode 100644 index 0000000000..06918fd184 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Concatenating Strings with Plus Operator.md @@ -0,0 +1,76 @@ +--- +id: 56533eb9ac21ba0edf2244b7 +title: Concatenating Strings with Plus Operator +challengeType: 1 +--- + +## Description +
+In JavaScript, when the + operator is used with a String value, it is called the concatenation operator. You can build a new string out of other strings by concatenating them together. +Example +
'My name is Alan,' + ' I concatenate.'
+Note
Watch out for spaces. Concatenation does not add spaces between concatenated strings, so you'll need to add them yourself. +
+ +## Instructions +
+Build myStr from the strings "This is the start. " and "This is the end." using the + operator. +
+ +## Tests +
+ +```yml +- text: myStr should have a value of This is the start. This is the end. + testString: 'assert(myStr === "This is the start. This is the end.", "myStr should have a value of This is the start. This is the end.");' +- text: Use the + operator to build myStr + testString: 'assert(code.match(/([""]).*([""])\s*\+\s*([""]).*([""])/g).length > 1, "Use the + operator to build myStr");' +- text: myStr should be created using the var keyword. + testString: 'assert(/var\s+myStr/.test(code), "myStr should be created using the var keyword.");' +- text: Make sure to assign the result to the myStr variable. + testString: 'assert(/myStr\s*=/.test(code), "Make sure to assign the result to the myStr variable.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +// Example +var ourStr = "I come first. " + "I come second."; + +// Only change code below this line + +var myStr; + + +``` + +
+ + +### After Test +
+ +```js +console.info('after the test'); +``` + +
+ +
+ +## Solution +
+ + +```js +var ourStr = "I come first. " + "I come second."; +var myStr = "This is the start. " + "This is the end."; +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Concatenating Strings with the Plus Equals Operator.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Concatenating Strings with the Plus Equals Operator.md new file mode 100644 index 0000000000..ecb268e62b --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Concatenating Strings with the Plus Equals Operator.md @@ -0,0 +1,74 @@ +--- +id: 56533eb9ac21ba0edf2244b8 +title: Concatenating Strings with the Plus Equals Operator +challengeType: 1 +--- + +## Description +
+We can also use the += operator to concatenate a string onto the end of an existing string variable. This can be very helpful to break a long string over several lines. +Note
Watch out for spaces. Concatenation does not add spaces between concatenated strings, so you'll need to add them yourself. +
+ +## Instructions +
+Build myStr over several lines by concatenating these two strings: "This is the first sentence. " and "This is the second sentence." using the += operator. Use the += operator similar to how it is shown in the editor. Start by assigning the first string to myStr, then add on the second string. +
+ +## Tests +
+ +```yml +- text: myStr should have a value of This is the first sentence. This is the second sentence. + testString: 'assert(myStr === "This is the first sentence. This is the second sentence.", "myStr should have a value of This is the first sentence. This is the second sentence.");' +- text: Use the += operator to build myStr + testString: 'assert(code.match(/\w\s*\+=\s*[""]/g).length > 1 && code.match(/\w\s*\=\s*[""]/g).length > 1, "Use the += operator to build myStr");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +// Example +var ourStr = "I come first. "; +ourStr += "I come second."; + +// Only change code below this line + +var myStr; + + +``` + +
+ + +### After Test +
+ +```js +console.info('after the test'); +``` + +
+ +
+ +## Solution +
+ + +```js +var ourStr = "I come first. "; +ourStr += "I come second."; + +var myStr = "This is the first sentence. "; +myStr += "This is the second sentence."; +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Constructing Strings with Variables.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Constructing Strings with Variables.md new file mode 100644 index 0000000000..6525074f81 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Constructing Strings with Variables.md @@ -0,0 +1,70 @@ +--- +id: 56533eb9ac21ba0edf2244b9 +title: Constructing Strings with Variables +challengeType: 1 +--- + +## Description +
+Sometimes you will need to build a string, Mad Libs style. By using the concatenation operator (+), you can insert one or more variables into a string you're building. +
+ +## Instructions +
+Set myName to a string equal to your name and build myStr with myName between the strings "My name is " and " and I am well!" +
+ +## Tests +
+ +```yml +- text: myName should be set to a string at least 3 characters long + testString: 'assert(typeof myName !== "undefined" && myName.length > 2, "myName should be set to a string at least 3 characters long");' +- text: Use two + operators to build myStr with myName inside it + testString: 'assert(code.match(/[""]\s*\+\s*myName\s*\+\s*[""]/g).length > 0, "Use two + operators to build myStr with myName inside it");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +// Example +var ourName = "freeCodeCamp"; +var ourStr = "Hello, our name is " + ourName + ", how are you?"; + +// Only change code below this line +var myName; +var myStr; + + +``` + +
+ + +### After Test +
+ +```js +console.info('after the test'); +``` + +
+ +
+ +## Solution +
+ + +```js +var myName = "Bob"; +var myStr = "My name is " + myName + " and I am well!"; +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Count Backwards With a For Loop.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Count Backwards With a For Loop.md new file mode 100644 index 0000000000..673925ebf2 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Count Backwards With a For Loop.md @@ -0,0 +1,87 @@ +--- +id: 56105e7b514f539506016a5e +title: Count Backwards With a For Loop +challengeType: 1 +--- + +## Description +
+A for loop can also count backwards, so long as we can define the right conditions. +In order to count backwards by twos, we'll need to change our initialization, condition, and final-expression. +We'll start at i = 10 and loop while i > 0. We'll decrement i by 2 each loop with i -= 2. +
var ourArray = [];
for (var i=10; i > 0; i-=2) {
  ourArray.push(i);
}
+ourArray will now contain [10,8,6,4,2]. +Let's change our initialization and final-expression so we can count backward by twos by odd numbers. +
+ +## Instructions +
+Push the odd numbers from 9 through 1 to myArray using a for loop. +
+ +## Tests +
+ +```yml +- text: You should be using a for loop for this. + testString: 'assert(code.match(/for\s*\(/g).length > 1, "You should be using a for loop for this.");' +- text: You should be using the array method push. + testString: 'assert(code.match(/myArray.push/), "You should be using the array method push.");' +- text: 'myArray should equal [9,7,5,3,1].' + testString: 'assert.deepEqual(myArray, [9,7,5,3,1], "myArray should equal [9,7,5,3,1].");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +// Example +var ourArray = []; + +for (var i = 10; i > 0; i -= 2) { + ourArray.push(i); +} + +// Setup +var myArray = []; + +// Only change code below this line. + + +``` + +
+ + +### After Test +
+ +```js +console.info('after the test'); +``` + +
+ +
+ +## Solution +
+ + +```js +var ourArray = []; +for (var i = 10; i > 0; i -= 2) { + ourArray.push(i); +} +var myArray = []; +for (var i = 9; i > 0; i -= 2) { + myArray.push(i); +} +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Counting Cards.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Counting Cards.md new file mode 100644 index 0000000000..23b9566b32 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Counting Cards.md @@ -0,0 +1,102 @@ +--- +id: 565bbe00e9cc8ac0725390f4 +title: Counting Cards +challengeType: 1 +--- + +## Description +
+In the casino game Blackjack, a player can gain an advantage over the house by keeping track of the relative number of high and low cards remaining in the deck. This is called Card Counting. +Having more high cards remaining in the deck favors the player. Each card is assigned a value according to the table below. When the count is positive, the player should bet high. When the count is zero or negative, the player should bet low. +
Count ChangeCards
+12, 3, 4, 5, 6
07, 8, 9
-110, 'J', 'Q', 'K', 'A'
+You will write a card counting function. It will receive a card parameter, which can be a number or a string, and increment or decrement the global count variable according to the card's value (see table). The function will then return a string with the current count and the string Bet if the count is positive, or Hold if the count is zero or negative. The current count and the player's decision (Bet or Hold) should be separated by a single space. +Example Output
-3 Hold
5 Bet +Hint
Do NOT reset count to 0 when value is 7, 8, or 9.
Do NOT return an array.
Do NOT include quotes (single or double) in the output. +
+ +## Instructions +
+ +
+ +## Tests +
+ +```yml +- text: 'Cards Sequence 2, 3, 4, 5, 6 should return 5 Bet' + testString: 'assert((function(){ count = 0; cc(2);cc(3);cc(4);cc(5);var out = cc(6); if(out === "5 Bet") {return true;} return false; })(), "Cards Sequence 2, 3, 4, 5, 6 should return 5 Bet");' +- text: 'Cards Sequence 7, 8, 9 should return 0 Hold' + testString: 'assert((function(){ count = 0; cc(7);cc(8);var out = cc(9); if(out === "0 Hold") {return true;} return false; })(), "Cards Sequence 7, 8, 9 should return 0 Hold");' +- text: 'Cards Sequence 10, J, Q, K, A should return -5 Hold' + testString: 'assert((function(){ count = 0; cc(10);cc("J");cc("Q");cc("K");var out = cc("A"); if(out === "-5 Hold") {return true;} return false; })(), "Cards Sequence 10, J, Q, K, A should return -5 Hold");' +- text: 'Cards Sequence 3, 7, Q, 8, A should return -1 Hold' + testString: 'assert((function(){ count = 0; cc(3);cc(7);cc("Q");cc(8);var out = cc("A"); if(out === "-1 Hold") {return true;} return false; })(), "Cards Sequence 3, 7, Q, 8, A should return -1 Hold");' +- text: 'Cards Sequence 2, J, 9, 2, 7 should return 1 Bet' + testString: 'assert((function(){ count = 0; cc(2);cc("J");cc(9);cc(2);var out = cc(7); if(out === "1 Bet") {return true;} return false; })(), "Cards Sequence 2, J, 9, 2, 7 should return 1 Bet");' +- text: 'Cards Sequence 2, 2, 10 should return 1 Bet' + testString: 'assert((function(){ count = 0; cc(2);cc(2);var out = cc(10); if(out === "1 Bet") {return true;} return false; })(), "Cards Sequence 2, 2, 10 should return 1 Bet");' +- text: 'Cards Sequence 3, 2, A, 10, K should return -1 Hold' + testString: 'assert((function(){ count = 0; cc(3);cc(2);cc("A");cc(10);var out = cc("K"); if(out === "-1 Hold") {return true;} return false; })(), "Cards Sequence 3, 2, A, 10, K should return -1 Hold");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +var count = 0; + +function cc(card) { + // Only change code below this line + + + return "Change Me"; + // Only change code above this line +} + +// Add/remove calls to test your function. +// Note: Only the last will display +cc(2); cc(3); cc(7); cc('K'); cc('A'); +``` + +
+ + + +
+ +## Solution +
+ + +```js +var count = 0; +function cc(card) { + switch(card) { + case 2: + case 3: + case 4: + case 5: + case 6: + count++; + break; + case 10: + case 'J': + case 'Q': + case 'K': + case 'A': + count--; + } + if(count > 0) { + return count + " Bet"; + } else { + return count + " Hold"; + } +} +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Create Decimal Numbers with JavaScript.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Create Decimal Numbers with JavaScript.md new file mode 100644 index 0000000000..d37b04088b --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Create Decimal Numbers with JavaScript.md @@ -0,0 +1,66 @@ +--- +id: cf1391c1c11feddfaeb4bdef +title: Create Decimal Numbers with JavaScript +challengeType: 1 +--- + +## Description +
+We can store decimal numbers in variables too. Decimal numbers are sometimes referred to as floating point numbers or floats. +Note
Not all real numbers can accurately be represented in floating point. This can lead to rounding errors. Details Here. +
+ +## Instructions +
+Create a variable myDecimal and give it a decimal value with a fractional part (e.g. 5.7). +
+ +## Tests +
+ +```yml +- text: myDecimal should be a number. + testString: 'assert(typeof myDecimal === "number", "myDecimal should be a number.");' +- text: myDecimal should have a decimal point + testString: 'assert(myDecimal % 1 != 0, "myDecimal should have a decimal point"); ' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +var ourDecimal = 5.7; + +// Only change code below this line + + +``` + +
+ + +### After Test +
+ +```js +console.info('after the test'); +``` + +
+ +
+ +## Solution +
+ + +```js +var myDecimal = 9.9; +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Declare JavaScript Variables.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Declare JavaScript Variables.md new file mode 100644 index 0000000000..c5ff51bb2c --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Declare JavaScript Variables.md @@ -0,0 +1,71 @@ +--- +id: bd7123c9c443eddfaeb5bdef +title: Declare JavaScript Variables +challengeType: 1 +--- + +## Description +
+In computer science, data is anything that is meaningful to the computer. JavaScript provides seven different data types which are undefined, null, boolean, string, symbol, number, and object. +For example, computers distinguish between numbers, such as the number 12, and strings, such as "12", "dog", or "123 cats", which are collections of characters. Computers can perform mathematical operations on a number, but not on a string. +Variables allow computers to store and manipulate data in a dynamic fashion. They do this by using a "label" to point to the data rather than using the data itself. Any of the seven data types may be stored in a variable. +Variables are similar to the x and y variables you use in mathematics, which means they're a simple name to represent the data we want to refer to. Computer variables differ from mathematical variables in that they can store different values at different times. +We tell JavaScript to create or declare a variable by putting the keyword var in front of it, like so: +
var ourName;
+creates a variable called ourName. In JavaScript we end statements with semicolons. +Variable names can be made up of numbers, letters, and $ or _, but may not contain spaces or start with a number. +
+ +## Instructions +
+Use the var keyword to create a variable called myName. +Hint
Look at the ourName example if you get stuck. +
+ +## Tests +
+ +```yml +- text: 'You should declare myName with the var keyword, ending with a semicolon' + testString: 'assert(/var\s+myName\s*;/.test(code), "You should declare myName with the var keyword, ending with a semicolon");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +// Example +var ourName; + +// Declare myName below this line + +``` + +
+ + +### After Test +
+ +```js +console.info('after the test'); +``` + +
+ +
+ +## Solution +
+ + +```js +var myName; +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Declare String Variables.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Declare String Variables.md new file mode 100644 index 0000000000..90d5dda5d7 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Declare String Variables.md @@ -0,0 +1,70 @@ +--- +id: bd7123c9c444eddfaeb5bdef +title: Declare String Variables +challengeType: 1 +--- + +## Description +
+Previously we have used the code +var myName = "your name"; +"your name" is called a string literal. It is a string because it is a series of zero or more characters enclosed in single or double quotes. +
+ +## Instructions +
+Create two new string variables: myFirstName and myLastName and assign them the values of your first and last name, respectively. +
+ +## Tests +
+ +```yml +- text: myFirstName should be a string with at least one character in it. + testString: 'assert((function(){if(typeof myFirstName !== "undefined" && typeof myFirstName === "string" && myFirstName.length > 0){return true;}else{return false;}})(), "myFirstName should be a string with at least one character in it.");' +- text: myLastName should be a string with at least one character in it. + testString: 'assert((function(){if(typeof myLastName !== "undefined" && typeof myLastName === "string" && myLastName.length > 0){return true;}else{return false;}})(), "myLastName should be a string with at least one character in it.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +// Example +var firstName = "Alan"; +var lastName = "Turing"; + +// Only change code below this line + + +``` + +
+ + +### After Test +
+ +```js +console.info('after the test'); +``` + +
+ +
+ +## Solution +
+ + +```js +var myFirstName = "Alan"; +var myLastName = "Turing"; +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Decrement a Number with JavaScript.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Decrement a Number with JavaScript.md new file mode 100644 index 0000000000..87273d2ad1 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Decrement a Number with JavaScript.md @@ -0,0 +1,74 @@ +--- +id: 56533eb9ac21ba0edf2244ad +title: Decrement a Number with JavaScript +challengeType: 1 +--- + +## Description +
+You can easily decrement or decrease a variable by one with the -- operator. +i--; +is the equivalent of +i = i - 1; +Note
The entire line becomes i--;, eliminating the need for the equal sign. +
+ +## Instructions +
+Change the code to use the -- operator on myVar. +
+ +## Tests +
+ +```yml +- text: myVar should equal 10 + testString: 'assert(myVar === 10, "myVar should equal 10");' +- text: myVar = myVar - 1; should be changed + testString: 'assert(/var\s*myVar\s*=\s*11;\s*\/*.*\s*([-]{2}\s*myVar|myVar\s*[-]{2});/.test(code), "myVar = myVar - 1; should be changed");' +- text: Use the -- operator on myVar + testString: 'assert(/[-]{2}\s*myVar|myVar\s*[-]{2}/.test(code), "Use the -- operator on myVar");' +- text: Do not change code above the line + testString: 'assert(/var myVar = 11;/.test(code), "Do not change code above the line");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +var myVar = 11; + +// Only change code below this line +myVar = myVar - 1; + +``` + +
+ + +### After Test +
+ +```js +console.info('after the test'); +``` + +
+ +
+ +## Solution +
+ + +```js +var myVar = 11; +myVar--; +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Delete Properties from a JavaScript Object.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Delete Properties from a JavaScript Object.md new file mode 100644 index 0000000000..e1a85e7b86 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Delete Properties from a JavaScript Object.md @@ -0,0 +1,98 @@ +--- +id: 56bbb991ad1ed5201cd392d3 +title: Delete Properties from a JavaScript Object +challengeType: 1 +--- + +## Description +
+We can also delete properties from objects like this: +delete ourDog.bark; +
+ +## Instructions +
+Delete the "tails" property from myDog. You may use either dot or bracket notation. +
+ +## Tests +
+ +```yml +- text: Delete the property "tails" from myDog. + testString: 'assert(typeof myDog === "object" && myDog.tails === undefined, "Delete the property "tails" from myDog.");' +- text: Do not modify the myDog setup + testString: 'assert(code.match(/"tails": 1/g).length > 1, "Do not modify the myDog setup");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +// Example +var ourDog = { + "name": "Camper", + "legs": 4, + "tails": 1, + "friends": ["everything!"], + "bark": "bow-wow" +}; + +delete ourDog.bark; + +// Setup +var myDog = { + "name": "Happy Coder", + "legs": 4, + "tails": 1, + "friends": ["freeCodeCamp Campers"], + "bark": "woof" +}; + +// Only change code below this line. + + +``` + +
+ + +### After Test +
+ +```js +console.info('after the test'); +``` + +
+ +
+ +## Solution +
+ + +```js +var ourDog = { + "name": "Camper", + "legs": 4, + "tails": 1, + "friends": ["everything!"], + "bark": "bow-wow" +}; +var myDog = { + "name": "Happy Coder", + "legs": 4, + "tails": 1, + "friends": ["freeCodeCamp Campers"], + "bark": "woof" +}; +delete myDog.tails; +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Divide One Decimal by Another with JavaScript.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Divide One Decimal by Another with JavaScript.md new file mode 100644 index 0000000000..8c0d7edd43 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Divide One Decimal by Another with JavaScript.md @@ -0,0 +1,63 @@ +--- +id: bd7993c9ca9feddfaeb7bdef +title: Divide One Decimal by Another with JavaScript +challengeType: 1 +--- + +## Description +
+Now let's divide one decimal by another. +
+ +## Instructions +
+Change the 0.0 so that quotient will equal to 2.2. +
+ +## Tests +
+ +```yml +- text: The variable quotient should equal 2.2 + testString: 'assert(quotient === 2.2, "The variable quotient should equal 2.2");' +- text: You should use the / operator to divide 4.4 by 2 + testString: 'assert(/4\.40*\s*\/\s*2\.*0*/.test(code), "You should use the / operator to divide 4.4 by 2");' +- text: The quotient variable should only be assigned once + testString: 'assert(code.match(/quotient/g).length === 1, "The quotient variable should only be assigned once");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +var quotient = 0.0 / 2.0; // Fix this line + + +``` + +
+ + +### After Test +
+ +```js +console.info('after the test'); +``` + +
+ +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Divide One Number by Another with JavaScript.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Divide One Number by Another with JavaScript.md new file mode 100644 index 0000000000..bd0c76f4f0 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Divide One Number by Another with JavaScript.md @@ -0,0 +1,68 @@ +--- +id: cf1111c1c11feddfaeb6bdef +title: Divide One Number by Another with JavaScript +challengeType: 1 +--- + +## Description +
+We can also divide one number by another. +JavaScript uses the / symbol for division. + +Example +
myVar = 16 / 2; // assigned 8
+ +
+ +## Instructions +
+Change the 0 so that the quotient is equal to 2. +
+ +## Tests +
+ +```yml +- text: Make the variable quotient equal to 2. + testString: 'assert(quotient === 2, "Make the variable quotient equal to 2.");' +- text: Use the / operator + testString: 'assert(/\d+\s*\/\s*\d+/.test(code), "Use the / operator");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +var quotient = 66 / 0; + + +``` + +
+ + +### After Test +
+ +```js +console.info('after the test'); +``` + +
+ +
+ +## Solution +
+ + +```js +var quotient = 66 / 33; +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Escape Sequences in Strings.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Escape Sequences in Strings.md new file mode 100644 index 0000000000..5fe4b01300 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Escape Sequences in Strings.md @@ -0,0 +1,77 @@ +--- +id: 56533eb9ac21ba0edf2244b6 +title: Escape Sequences in Strings +challengeType: 1 +--- + +## Description +
+Quotes are not the only characters that can be escaped inside a string. There are two reasons to use escaping characters: First is to allow you to use characters you might not otherwise be able to type out, such as a backspace. Second is to allow you to represent multiple quotes in a string without JavaScript misinterpreting what you mean. We learned this in the previous challenge. +
CodeOutput
\'single quote
\"double quote
\\backslash
\nnewline
\rcarriage return
\ttab
\bbackspace
\fform feed
+Note that the backslash itself must be escaped in order to display as a backslash. +
+ +## Instructions +
+Assign the following three lines of text into the single variable myStr using escape sequences. +
FirstLine
    \SecondLine
ThirdLine
+You will need to use escape sequences to insert special characters correctly. You will also need to follow the spacing as it looks above, with no spaces between escape sequences or words. +Here is the text with the escape sequences written out. +FirstLinenewlinetabbackslashSecondLinenewlineThirdLine +
+ +## Tests +
+ +```yml +- text: myStr should not contain any spaces + testString: 'assert(!/ /.test(myStr), "myStr should not contain any spaces");' +- text: 'myStr should contain the strings FirstLine, SecondLine and ThirdLine (remember case sensitivity)' + testString: 'assert(/FirstLine/.test(myStr) && /SecondLine/.test(myStr) && /ThirdLine/.test(myStr), "myStr should contain the strings FirstLine, SecondLine and ThirdLine (remember case sensitivity)");' +- text: FirstLine should be followed by the newline character \n + testString: 'assert(/FirstLine\n/.test(myStr), "FirstLine should be followed by the newline character \n");' +- text: myStr should contain a tab character \t which follows a newline character + testString: 'assert(/\n\t/.test(myStr), "myStr should contain a tab character \t which follows a newline character");' +- text: SecondLine should be preceded by the backslash character \\ + testString: 'assert(/\SecondLine/.test(myStr), "SecondLine should be preceded by the backslash character \\");' +- text: There should be a newline character between SecondLine and ThirdLine + testString: 'assert(/SecondLine\nThirdLine/.test(myStr), "There should be a newline character between SecondLine and ThirdLine");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +var myStr; // Change this line + + +``` + +
+ + +### After Test +
+ +```js +console.info('after the test'); +``` + +
+ +
+ +## Solution +
+ + +```js +var myStr = "FirstLine\n\t\\SecondLine\nThirdLine"; +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Escaping Literal Quotes in Strings.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Escaping Literal Quotes in Strings.md new file mode 100644 index 0000000000..1ef7e2f0f7 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Escaping Literal Quotes in Strings.md @@ -0,0 +1,68 @@ +--- +id: 56533eb9ac21ba0edf2244b5 +title: Escaping Literal Quotes in Strings +challengeType: 1 +--- + +## Description +
+When you are defining a string you must start and end with a single or double quote. What happens when you need a literal quote: " or ' inside of your string? +In JavaScript, you can escape a quote from considering it as an end of string quote by placing a backslash (\) in front of the quote. +var sampleStr = "Alan said, \"Peter is learning JavaScript\"."; +This signals to JavaScript that the following quote is not the end of the string, but should instead appear inside the string. So if you were to print this to the console, you would get: +Alan said, "Peter is learning JavaScript". +
+ +## Instructions +
+Use backslashes to assign a string to the myStr variable so that if you were to print it to the console, you would see: +I am a "double quoted" string inside "double quotes". +
+ +## Tests +
+ +```yml +- text: 'You should use two double quotes (") and four escaped double quotes (\").' + testString: 'assert(code.match(/\\"/g).length === 4 && code.match(/[^\\]"/g).length === 2, "You should use two double quotes (") and four escaped double quotes (\").");' +- text: 'Variable myStr should contain the string: I am a "double quoted" string inside "double quotes".' + testString: 'assert(myStr === "I am a \"double quoted\" string inside \"double quotes\".", "Variable myStr should contain the string: I am a "double quoted" string inside "double quotes".");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +var myStr = ""; // Change this line + + +``` + +
+ + +### After Test +
+ +```js +console.info('after the test'); +``` + +
+ +
+ +## Solution +
+ + +```js +var myStr = "I am a \"double quoted\" string inside \"double quotes\"."; +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Find the Length of a String.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Find the Length of a String.md new file mode 100644 index 0000000000..1302331efc --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Find the Length of a String.md @@ -0,0 +1,83 @@ +--- +id: bd7123c9c448eddfaeb5bdef +title: Find the Length of a String +challengeType: 1 +--- + +## Description +
+You can find the length of a String value by writing .length after the string variable or string literal. +"Alan Peter".length; // 10 +For example, if we created a variable var firstName = "Charles", we could find out how long the string "Charles" is by using the firstName.length property. +
+ +## Instructions +
+Use the .length property to count the number of characters in the lastName variable and assign it to lastNameLength. +
+ +## Tests +
+ +```yml +- text: lastNameLength should be equal to eight. + testString: 'assert((function(){if(typeof lastNameLength !== "undefined" && typeof lastNameLength === "number" && lastNameLength === 8){return true;}else{return false;}})(), "lastNameLength should be equal to eight.");' +- text: 'You should be getting the length of lastName by using .length like this: lastName.length.' + testString: 'assert((function(){if(code.match(/\.length/gi) && code.match(/\.length/gi).length >= 2 && code.match(/var lastNameLength \= 0;/gi) && code.match(/var lastNameLength \= 0;/gi).length >= 1){return true;}else{return false;}})(), "You should be getting the length of lastName by using .length like this: lastName.length.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +// Example +var firstNameLength = 0; +var firstName = "Ada"; + +firstNameLength = firstName.length; + +// Setup +var lastNameLength = 0; +var lastName = "Lovelace"; + +// Only change code below this line. + +lastNameLength = lastName; + + +``` + +
+ + +### After Test +
+ +```js +console.info('after the test'); +``` + +
+ +
+ +## Solution +
+ + +```js +var firstNameLength = 0; +var firstName = "Ada"; +firstNameLength = firstName.length; + +var lastNameLength = 0; +var lastName = "Lovelace"; +lastNameLength = lastName.length; +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Finding a Remainder in JavaScript.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Finding a Remainder in JavaScript.md new file mode 100644 index 0000000000..f9431e826b --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Finding a Remainder in JavaScript.md @@ -0,0 +1,71 @@ +--- +id: 56533eb9ac21ba0edf2244ae +title: Finding a Remainder in JavaScript +challengeType: 1 +--- + +## Description +
+The remainder operator % gives the remainder of the division of two numbers. +Example +
5 % 2 = 1 because
Math.floor(5 / 2) = 2 (Quotient)
2 * 2 = 4
5 - 4 = 1 (Remainder)
+Usage
In mathematics, a number can be checked to be even or odd by checking the remainder of the division of the number by 2. +
17 % 2 = 1 (17 is Odd)
48 % 2 = 0 (48 is Even)
+Note
The remainder operator is sometimes incorrectly referred to as the "modulus" operator. It is very similar to modulus, but does not work properly with negative numbers. +
+ +## Instructions +
+Set remainder equal to the remainder of 11 divided by 3 using the remainder (%) operator. +
+ +## Tests +
+ +```yml +- text: The variable remainder should be initialized + testString: 'assert(/var\s+?remainder/.test(code), "The variable remainder should be initialized");' +- text: The value of remainder should be 2 + testString: 'assert(remainder === 2, "The value of remainder should be 2");' +- text: You should use the % operator + testString: 'assert(/\s+?remainder\s*?=\s*?.*%.*;/.test(code), "You should use the % operator");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +// Only change code below this line + +var remainder; + +``` + +
+ + +### After Test +
+ +```js +console.info('after the test'); +``` + +
+ +
+ +## Solution +
+ + +```js +var remainder = 11 % 3; +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Generate Random Fractions with JavaScript.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Generate Random Fractions with JavaScript.md new file mode 100644 index 0000000000..5f6723f161 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Generate Random Fractions with JavaScript.md @@ -0,0 +1,74 @@ +--- +id: cf1111c1c11feddfaeb9bdef +title: Generate Random Fractions with JavaScript +challengeType: 1 +--- + +## Description +
+Random numbers are useful for creating random behavior. +JavaScript has a Math.random() function that generates a random decimal number between 0 (inclusive) and not quite up to 1 (exclusive). Thus Math.random() can return a 0 but never quite return a 1 +Note
Like Storing Values with the Equal Operator, all function calls will be resolved before the return executes, so we can return the value of the Math.random() function. +
+ +## Instructions +
+Change randomFraction to return a random number instead of returning 0. +
+ +## Tests +
+ +```yml +- text: randomFraction should return a random number. + testString: 'assert(typeof randomFraction() === "number", "randomFraction should return a random number.");' +- text: The number returned by randomFraction should be a decimal. + testString: 'assert((randomFraction()+""). match(/\./g), "The number returned by randomFraction should be a decimal.");' +- text: You should be using Math.random to generate the random decimal number. + testString: 'assert(code.match(/Math\.random/g).length >= 0, "You should be using Math.random to generate the random decimal number.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +function randomFraction() { + + // Only change code below this line. + + return 0; + + // Only change code above this line. +} +``` + +
+ + +### After Test +
+ +```js +console.info('after the test'); +``` + +
+ +
+ +## Solution +
+ + +```js +function randomFraction() { + return Math.random(); +} +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Generate Random Whole Numbers with JavaScript.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Generate Random Whole Numbers with JavaScript.md new file mode 100644 index 0000000000..57203d88b9 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Generate Random Whole Numbers with JavaScript.md @@ -0,0 +1,80 @@ +--- +id: cf1111c1c12feddfaeb1bdef +title: Generate Random Whole Numbers with JavaScript +challengeType: 1 +--- + +## Description +
+It's great that we can generate random decimal numbers, but it's even more useful if we use it to generate random whole numbers. +
  1. Use Math.random() to generate a random decimal.
  2. Multiply that random decimal by 20.
  3. Use another function, Math.floor() to round the number down to its nearest whole number.
+Remember that Math.random() can never quite return a 1 and, because we're rounding down, it's impossible to actually get 20. This technique will give us a whole number between 0 and 19. +Putting everything together, this is what our code looks like: +Math.floor(Math.random() * 20); +We are calling Math.random(), multiplying the result by 20, then passing the value to Math.floor() function to round the value down to the nearest whole number. +
+ +## Instructions +
+Use this technique to generate and return a random whole number between 0 and 9. +
+ +## Tests +
+ +```yml +- text: The result of randomWholeNum should be a whole number. + testString: 'assert(typeof randomWholeNum() === "number" && (function(){var r = randomWholeNum();return Math.floor(r) === r;})(), "The result of randomWholeNum should be a whole number.");' +- text: You should be using Math.random to generate a random number. + testString: 'assert(code.match(/Math.random/g).length > 1, "You should be using Math.random to generate a random number.");' +- text: You should have multiplied the result of Math.random by 10 to make it a number that is between zero and nine. + testString: 'assert(code.match(/\s*?Math.random\s*?\(\s*?\)\s*?\*\s*?10[\D]\s*?/g) || code.match(/\s*?10\s*?\*\s*?Math.random\s*?\(\s*?\)\s*?/g), "You should have multiplied the result of Math.random by 10 to make it a number that is between zero and nine.");' +- text: You should use Math.floor to remove the decimal part of the number. + testString: 'assert(code.match(/Math.floor/g).length > 1, "You should use Math.floor to remove the decimal part of the number.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +var randomNumberBetween0and19 = Math.floor(Math.random() * 20); + +function randomWholeNum() { + + // Only change code below this line. + + return Math.random(); +} +``` + +
+ + +### After Test +
+ +```js +console.info('after the test'); +``` + +
+ +
+ +## Solution +
+ + +```js +var randomNumberBetween0and19 = Math.floor(Math.random() * 20); +function randomWholeNum() { + return Math.floor(Math.random() * 10); +} +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Generate Random Whole Numbers within a Range.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Generate Random Whole Numbers within a Range.md new file mode 100644 index 0000000000..4240cb5fac --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Generate Random Whole Numbers within a Range.md @@ -0,0 +1,87 @@ +--- +id: cf1111c1c12feddfaeb2bdef +title: Generate Random Whole Numbers within a Range +challengeType: 1 +--- + +## Description +
+Instead of generating a random number between zero and a given number like we did before, we can generate a random number that falls within a range of two specific numbers. +To do this, we'll define a minimum number min and a maximum number max. +Here's the formula we'll use. Take a moment to read it and try to understand what this code is doing: +Math.floor(Math.random() * (max - min + 1)) + min +
+ +## Instructions +
+Create a function called randomRange that takes a range myMin and myMax and returns a random number that's greater than or equal to myMin, and is less than or equal to myMax, inclusive. +
+ +## Tests +
+ +```yml +- text: 'The lowest random number that can be generated by randomRange should be equal to your minimum number, myMin.' + testString: 'assert(calcMin === 5, "The lowest random number that can be generated by randomRange should be equal to your minimum number, myMin.");' +- text: 'The highest random number that can be generated by randomRange should be equal to your maximum number, myMax.' + testString: 'assert(calcMax === 15, "The highest random number that can be generated by randomRange should be equal to your maximum number, myMax.");' +- text: 'The random number generated by randomRange should be an integer, not a decimal.' + testString: 'assert(randomRange(0,1) % 1 === 0 , "The random number generated by randomRange should be an integer, not a decimal.");' +- text: 'randomRange should use both myMax and myMin, and return a random number in your range.' + testString: 'assert((function(){if(code.match(/myMax/g).length > 1 && code.match(/myMin/g).length > 2 && code.match(/Math.floor/g) && code.match(/Math.random/g)){return true;}else{return false;}})(), "randomRange should use both myMax and myMin, and return a random number in your range.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +// Example +function ourRandomRange(ourMin, ourMax) { + + return Math.floor(Math.random() * (ourMax - ourMin + 1)) + ourMin; +} + +ourRandomRange(1, 9); + +// Only change code below this line. + +function randomRange(myMin, myMax) { + + return 0; // Change this line + +} + +// Change these values to test your function +var myRandom = randomRange(5, 15); +``` + +
+ + +### After Test +
+ +```js +console.info('after the test'); +``` + +
+ +
+ +## Solution +
+ + +```js +function randomRange(myMin, myMax) { + return Math.floor(Math.random() * (myMax - myMin + 1)) + myMin; +} +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Global Scope and Functions.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Global Scope and Functions.md new file mode 100644 index 0000000000..26424c336e --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Global Scope and Functions.md @@ -0,0 +1,130 @@ +--- +id: 56533eb9ac21ba0edf2244be +title: Global Scope and Functions +challengeType: 1 +--- + +## Description +
+In JavaScript, scope refers to the visibility of variables. Variables which are defined outside of a function block have Global scope. This means, they can be seen everywhere in your JavaScript code. +Variables which are used without the var keyword are automatically created in the global scope. This can create unintended consequences elsewhere in your code or when running a function again. You should always declare your variables with var. +
+ +## Instructions +
+Using var, declare a global variable myGlobal outside of any function. Initialize it with a value of 10. +Inside function fun1, assign 5 to oopsGlobal without using the var keyword. +
+ +## Tests +
+ +```yml +- text: myGlobal should be defined + testString: 'assert(typeof myGlobal != "undefined", "myGlobal should be defined");' +- text: myGlobal should have a value of 10 + testString: 'assert(myGlobal === 10, "myGlobal should have a value of 10");' +- text: myGlobal should be declared using the var keyword + testString: 'assert(/var\s+myGlobal/.test(code), "myGlobal should be declared using the var keyword");' +- text: oopsGlobal should be a global variable and have a value of 5 + testString: 'assert(typeof oopsGlobal != "undefined" && oopsGlobal === 5, "oopsGlobal should be a global variable and have a value of 5");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +// Declare your variable here + + +function fun1() { + // Assign 5 to oopsGlobal Here + +} + +// Only change code above this line +function fun2() { + var output = ""; + if (typeof myGlobal != "undefined") { + output += "myGlobal: " + myGlobal; + } + if (typeof oopsGlobal != "undefined") { + output += " oopsGlobal: " + oopsGlobal; + } + console.log(output); +} +``` + +
+ +### Before Test +
+ +```js +var logOutput = ""; +var originalConsole = console +function capture() { + var nativeLog = console.log; + console.log = function (message) { + logOutput = message; + if(nativeLog.apply) { + nativeLog.apply(originalConsole, arguments); + } else { + var nativeMsg = Array.prototype.slice.apply(arguments).join(' '); + nativeLog(nativeMsg); + } + }; +} + +function uncapture() { + console.log = originalConsole.log; +} +var oopsGlobal; +capture(); +``` + +
+ +### After Test +
+ +```js +console.info('after the test'); +``` + +
+ +
+ +## Solution +
+ + +```js +// Declare your variable here +var myGlobal = 10; + +function fun1() { + // Assign 5 to oopsGlobal Here + oopsGlobal = 5; +} + +// Only change code above this line +function fun2() { + var output = ""; + if(typeof myGlobal != "undefined") { + output += "myGlobal: " + myGlobal; + } + if(typeof oopsGlobal != "undefined") { + output += " oopsGlobal: " + oopsGlobal; + } + console.log(output); +} +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Global vs. Local Scope in Functions.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Global vs. Local Scope in Functions.md new file mode 100644 index 0000000000..16a549a6ae --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Global vs. Local Scope in Functions.md @@ -0,0 +1,74 @@ +--- +id: 56533eb9ac21ba0edf2244c0 +title: Global vs. Local Scope in Functions +challengeType: 1 +--- + +## Description +
+It is possible to have both local and global variables with the same name. When you do this, the local variable takes precedence over the global variable. +In this example: +
var someVar = "Hat";
function myFun() {
  var someVar = "Head";
  return someVar;
}
+The function myFun will return "Head" because the local version of the variable is present. +
+ +## Instructions +
+Add a local variable to myOutfit function to override the value of outerWear with "sweater". +
+ +## Tests +
+ +```yml +- text: Do not change the value of the global outerWear + testString: 'assert(outerWear === "T-Shirt", "Do not change the value of the global outerWear");' +- text: myOutfit should return "sweater" + testString: 'assert(myOutfit() === "sweater", "myOutfit should return "sweater"");' +- text: Do not change the return statement + testString: 'assert(/return outerWear/.test(code), "Do not change the return statement");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +// Setup +var outerWear = "T-Shirt"; + +function myOutfit() { + // Only change code below this line + + + + // Only change code above this line + return outerWear; +} + +myOutfit(); +``` + +
+ + + +
+ +## Solution +
+ + +```js +var outerWear = "T-Shirt"; +function myOutfit() { + var outerWear = "sweater"; + return outerWear; +} +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Golf Code.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Golf Code.md new file mode 100644 index 0000000000..8d89c2d37a --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Golf Code.md @@ -0,0 +1,110 @@ +--- +id: 5664820f61c48e80c9fa476c +title: Golf Code +challengeType: 1 +--- + +## Description +
+In the game of golf each hole has a par meaning the average number of strokes a golfer is expected to make in order to sink the ball in a hole to complete the play. Depending on how far above or below par your strokes are, there is a different nickname. +Your function will be passed par and strokes arguments. Return the correct string according to this table which lists the strokes in order of priority; top (highest) to bottom (lowest): +
StrokesReturn
1"Hole-in-one!"
<= par - 2"Eagle"
par - 1"Birdie"
par"Par"
par + 1"Bogey"
par + 2"Double Bogey"
>= par + 3"Go Home!"
+par and strokes will always be numeric and positive. We have added an array of all the names for your convenience. +
+ +## Instructions +
+ +
+ +## Tests +
+ +```yml +- text: 'golfScore(4, 1) should return "Hole-in-one!"' + testString: 'assert(golfScore(4, 1) === "Hole-in-one!", "golfScore(4, 1) should return "Hole-in-one!"");' +- text: 'golfScore(4, 2) should return "Eagle"' + testString: 'assert(golfScore(4, 2) === "Eagle", "golfScore(4, 2) should return "Eagle"");' +- text: 'golfScore(5, 2) should return "Eagle"' + testString: 'assert(golfScore(5, 2) === "Eagle", "golfScore(5, 2) should return "Eagle"");' +- text: 'golfScore(4, 3) should return "Birdie"' + testString: 'assert(golfScore(4, 3) === "Birdie", "golfScore(4, 3) should return "Birdie"");' +- text: 'golfScore(4, 4) should return "Par"' + testString: 'assert(golfScore(4, 4) === "Par", "golfScore(4, 4) should return "Par"");' +- text: 'golfScore(1, 1) should return "Hole-in-one!"' + testString: 'assert(golfScore(1, 1) === "Hole-in-one!", "golfScore(1, 1) should return "Hole-in-one!"");' +- text: 'golfScore(5, 5) should return "Par"' + testString: 'assert(golfScore(5, 5) === "Par", "golfScore(5, 5) should return "Par"");' +- text: 'golfScore(4, 5) should return "Bogey"' + testString: 'assert(golfScore(4, 5) === "Bogey", "golfScore(4, 5) should return "Bogey"");' +- text: 'golfScore(4, 6) should return "Double Bogey"' + testString: 'assert(golfScore(4, 6) === "Double Bogey", "golfScore(4, 6) should return "Double Bogey"");' +- text: 'golfScore(4, 7) should return "Go Home!"' + testString: 'assert(golfScore(4, 7) === "Go Home!", "golfScore(4, 7) should return "Go Home!"");' +- text: 'golfScore(5, 9) should return "Go Home!"' + testString: 'assert(golfScore(5, 9) === "Go Home!", "golfScore(5, 9) should return "Go Home!"");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +var names = ["Hole-in-one!", "Eagle", "Birdie", "Par", "Bogey", "Double Bogey", "Go Home!"]; +function golfScore(par, strokes) { + // Only change code below this line + + + return "Change Me"; + // Only change code above this line +} + +// Change these values to test +golfScore(5, 4); +``` + +
+ + + +
+ +## Solution +
+ + +```js +function golfScore(par, strokes) { + if (strokes === 1) { + return "Hole-in-one!"; + } + + if (strokes <= par - 2) { + return "Eagle"; + } + + if (strokes === par - 1) { + return "Birdie"; + } + + if (strokes === par) { + return "Par"; + } + + if (strokes === par + 1) { + return "Bogey"; + } + + if(strokes === par + 2) { + return "Double Bogey"; + } + + return "Go Home!"; +} +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Increment a Number with JavaScript.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Increment a Number with JavaScript.md new file mode 100644 index 0000000000..0d8c5cee03 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Increment a Number with JavaScript.md @@ -0,0 +1,75 @@ +--- +id: 56533eb9ac21ba0edf2244ac +title: Increment a Number with JavaScript +challengeType: 1 +--- + +## Description +
+You can easily increment or add one to a variable with the ++ operator. +i++; +is the equivalent of +i = i + 1; +Note
The entire line becomes i++;, eliminating the need for the equal sign. +
+ +## Instructions +
+Change the code to use the ++ operator on myVar. +Hint
Learn more about Arithmetic operators - Increment (++). +
+ +## Tests +
+ +```yml +- text: myVar should equal 88 + testString: 'assert(myVar === 88, "myVar should equal 88");' +- text: myVar = myVar + 1; should be changed + testString: 'assert(/var\s*myVar\s*=\s*87;\s*\/*.*\s*([+]{2}\s*myVar|myVar\s*[+]{2});/.test(code), "myVar = myVar + 1; should be changed");' +- text: Use the ++ operator + testString: 'assert(/[+]{2}\s*myVar|myVar\s*[+]{2}/.test(code), "Use the ++ operator");' +- text: Do not change code above the line + testString: 'assert(/var myVar = 87;/.test(code), "Do not change code above the line");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +var myVar = 87; + +// Only change code below this line +myVar = myVar + 1; + +``` + +
+ + +### After Test +
+ +```js +console.info('after the test'); +``` + +
+ +
+ +## Solution +
+ + +```js +var myVar = 87; +myVar++; +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Initializing Variables with the Assignment Operator.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Initializing Variables with the Assignment Operator.md new file mode 100644 index 0000000000..2518b48e6a --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Initializing Variables with the Assignment Operator.md @@ -0,0 +1,65 @@ +--- +id: 56533eb9ac21ba0edf2244a9 +title: Initializing Variables with the Assignment Operator +challengeType: 1 +--- + +## Description +
+It is common to initialize a variable to an initial value in the same line as it is declared. +var myVar = 0; +Creates a new variable called myVar and assigns it an initial value of 0. +
+ +## Instructions +
+Define a variable a with var and initialize it to a value of 9. +
+ +## Tests +
+ +```yml +- text: Initialize a to a value of 9 + testString: 'assert(/var\s+a\s*=\s*9\s*/.test(code), "Initialize a to a value of 9");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +// Example +var ourVar = 19; + +// Only change code below this line + +``` + +
+ + +### After Test +
+ +```js +console.info('after the test'); +``` + +
+ +
+ +## Solution +
+ + +```js +var a = 9; +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Introducing Else If Statements.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Introducing Else If Statements.md new file mode 100644 index 0000000000..1f6baaa902 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Introducing Else If Statements.md @@ -0,0 +1,88 @@ +--- +id: 56533eb9ac21ba0edf2244db +title: Introducing Else If Statements +challengeType: 1 +--- + +## Description +
+If you have multiple conditions that need to be addressed, you can chain if statements together with else if statements. +
if (num > 15) {
  return "Bigger than 15";
} else if (num < 5) {
  return "Smaller than 5";
} else {
  return "Between 5 and 15";
}
+
+ +## Instructions +
+Convert the logic to use else if statements. +
+ +## Tests +
+ +```yml +- text: You should have at least two else statements + testString: 'assert(code.match(/else/g).length > 1, "You should have at least two else statements");' +- text: You should have at least two if statements + testString: 'assert(code.match(/if/g).length > 1, "You should have at least two if statements");' +- text: You should have closing and opening curly braces for each condition + testString: 'assert(code.match(/if\s*\((.+)\)\s*\{[\s\S]+\}\s*else if\s*\((.+)\)\s*\{[\s\S]+\}\s*else\s*\{[\s\S]+\s*\}/), "You should have closing and opening curly braces for each condition in your if else statement");' +- text: testElseIf(0) should return "Smaller than 5" + testString: 'assert(testElseIf(0) === "Smaller than 5", "testElseIf(0) should return "Smaller than 5"");' +- text: testElseIf(5) should return "Between 5 and 10" + testString: 'assert(testElseIf(5) === "Between 5 and 10", "testElseIf(5) should return "Between 5 and 10"");' +- text: testElseIf(7) should return "Between 5 and 10" + testString: 'assert(testElseIf(7) === "Between 5 and 10", "testElseIf(7) should return "Between 5 and 10"");' +- text: testElseIf(10) should return "Between 5 and 10" + testString: 'assert(testElseIf(10) === "Between 5 and 10", "testElseIf(10) should return "Between 5 and 10"");' +- text: testElseIf(12) should return "Greater than 10" + testString: 'assert(testElseIf(12) === "Greater than 10", "testElseIf(12) should return "Greater than 10"");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +function testElseIf(val) { + if (val > 10) { + return "Greater than 10"; + } + + if (val < 5) { + return "Smaller than 5"; + } + + return "Between 5 and 10"; +} + +// Change this value to test +testElseIf(7); + +``` + +
+ + + +
+ +## Solution +
+ + +```js +function testElseIf(val) { + if(val > 10) { + return "Greater than 10"; + } else if(val < 5) { + return "Smaller than 5"; + } else { + return "Between 5 and 10"; + } +} +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Introducing Else Statements.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Introducing Else Statements.md new file mode 100644 index 0000000000..e1b1913802 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Introducing Else Statements.md @@ -0,0 +1,90 @@ +--- +id: 56533eb9ac21ba0edf2244da +title: Introducing Else Statements +challengeType: 1 +--- + +## Description +
+When a condition for an if statement is true, the block of code following it is executed. What about when that condition is false? Normally nothing would happen. With an else statement, an alternate block of code can be executed. +
if (num > 10) {
  return "Bigger than 10";
} else {
  return "10 or Less";
}
+
+ +## Instructions +
+Combine the if statements into a single if/else statement. +
+ +## Tests +
+ +```yml +- text: You should only have one if statement in the editor + testString: 'assert(code.match(/if/g).length === 1, "You should only have one if statement in the editor");' +- text: You should use an else statement + testString: 'assert(/else/g.test(code), "You should use an else statement");' +- text: testElse(4) should return "5 or Smaller" + testString: 'assert(testElse(4) === "5 or Smaller", "testElse(4) should return "5 or Smaller"");' +- text: testElse(5) should return "5 or Smaller" + testString: 'assert(testElse(5) === "5 or Smaller", "testElse(5) should return "5 or Smaller"");' +- text: testElse(6) should return "Bigger than 5" + testString: 'assert(testElse(6) === "Bigger than 5", "testElse(6) should return "Bigger than 5"");' +- text: testElse(10) should return "Bigger than 5" + testString: 'assert(testElse(10) === "Bigger than 5", "testElse(10) should return "Bigger than 5"");' +- text: Do not change the code above or below the lines. + testString: 'assert(/var result = "";/.test(code) && /return result;/.test(code), "Do not change the code above or below the lines.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +function testElse(val) { + var result = ""; + // Only change code below this line + + if (val > 5) { + result = "Bigger than 5"; + } + + if (val <= 5) { + result = "5 or Smaller"; + } + + // Only change code above this line + return result; +} + +// Change this value to test +testElse(4); + +``` + +
+ + + +
+ +## Solution +
+ + +```js +function testElse(val) { + var result = ""; + if(val > 5) { + result = "Bigger than 5"; + } else { + result = "5 or Smaller"; + } + return result; +} +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Iterate Odd Numbers With a For Loop.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Iterate Odd Numbers With a For Loop.md new file mode 100644 index 0000000000..94554840c6 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Iterate Odd Numbers With a For Loop.md @@ -0,0 +1,84 @@ +--- +id: 56104e9e514f539506016a5c +title: Iterate Odd Numbers With a For Loop +challengeType: 1 +--- + +## Description +
+For loops don't have to iterate one at a time. By changing our final-expression, we can count by even numbers. +We'll start at i = 0 and loop while i < 10. We'll increment i by 2 each loop with i += 2. +
var ourArray = [];
for (var i = 0; i < 10; i += 2) {
  ourArray.push(i);
}
+ourArray will now contain [0,2,4,6,8]. +Let's change our initialization so we can count by odd numbers. +
+ +## Instructions +
+Push the odd numbers from 1 through 9 to myArray using a for loop. +
+ +## Tests +
+ +```yml +- text: You should be using a for loop for this. + testString: 'assert(code.match(/for\s*\(/g).length > 1, "You should be using a for loop for this.");' +- text: 'myArray should equal [1,3,5,7,9].' + testString: 'assert.deepEqual(myArray, [1,3,5,7,9], "myArray should equal [1,3,5,7,9].");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +// Example +var ourArray = []; + +for (var i = 0; i < 10; i += 2) { + ourArray.push(i); +} + +// Setup +var myArray = []; + +// Only change code below this line. + + +``` + +
+ + +### After Test +
+ +```js +console.info('after the test'); +``` + +
+ +
+ +## Solution +
+ + +```js +var ourArray = []; +for (var i = 0; i < 10; i += 2) { + ourArray.push(i); +} +var myArray = []; +for (var i = 1; i < 10; i += 2) { + myArray.push(i); +} +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Iterate Through an Array with a For Loop.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Iterate Through an Array with a For Loop.md new file mode 100644 index 0000000000..7d7ec55318 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Iterate Through an Array with a For Loop.md @@ -0,0 +1,92 @@ +--- +id: 5675e877dbd60be8ad28edc6 +title: Iterate Through an Array with a For Loop +challengeType: 1 +--- + +## Description +
+A common task in JavaScript is to iterate through the contents of an array. One way to do that is with a for loop. This code will output each element of the array arr to the console: +
var arr = [10,9,8,7,6];
for (var i = 0; i < arr.length; i++) {
   console.log(arr[i]);
}
+Remember that Arrays have zero-based numbering, which means the last index of the array is length - 1. Our condition for this loop is i < arr.length, which stops when i is at length - 1. +
+ +## Instructions +
+Declare and initialize a variable total to 0. Use a for loop to add the value of each element of the myArr array to total. +
+ +## Tests +
+ +```yml +- text: total should be declared and initialized to 0 + testString: 'assert(code.match(/var.*?total\s*=\s*0.*?;/), "total should be declared and initialized to 0");' +- text: total should equal 20 + testString: 'assert(total === 20, "total should equal 20");' +- text: You should use a for loop to iterate through myArr + testString: 'assert(code.match(/for\s*\(/g).length > 1 && code.match(/myArr\s*\[/), "You should use a for loop to iterate through myArr");' +- text: Do not set total to 20 directly + testString: 'assert(!code.match(/total[\s\+\-]*=\s*(\d(?!\s*[;,])|[1-9])/g), "Do not set total to 20 directly");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +// Example +var ourArr = [ 9, 10, 11, 12]; +var ourTotal = 0; + +for (var i = 0; i < ourArr.length; i++) { + ourTotal += ourArr[i]; +} + +// Setup +var myArr = [ 2, 3, 4, 5, 6]; + +// Only change code below this line + + +``` + +
+ + +### After Test +
+ +```js +console.info('after the test'); +``` + +
+ +
+ +## Solution +
+ + +```js +var ourArr = [ 9, 10, 11, 12]; +var ourTotal = 0; + +for (var i = 0; i < ourArr.length; i++) { + ourTotal += ourArr[i]; +} + +var myArr = [ 2, 3, 4, 5, 6]; +var total = 0; + +for (var i = 0; i < myArr.length; i++) { + total += myArr[i]; +} +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Iterate with JavaScript Do...While Loops.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Iterate with JavaScript Do...While Loops.md new file mode 100644 index 0000000000..cca588b1b8 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Iterate with JavaScript Do...While Loops.md @@ -0,0 +1,89 @@ +--- +id: 5a2efd662fb457916e1fe604 +title: Iterate with JavaScript Do...While Loops +challengeType: 1 +--- + +## Description +
+You can run the same code multiple times by using a loop. +The next type of loop you will learn is called a "do...while" loop because it first will "do" one pass of the code inside the loop no matter what, and then it runs "while" a specified condition is true and stops once that condition is no longer true. Let's look at an example. +
var ourArray = [];
var i = 0;
do {
  ourArray.push(i);
  i++;
} while (i < 5);
+This behaves just as you would expect with any other type of loop, and the resulting array will look like [0, 1, 2, 3, 4]. However, what makes the do...while different from other loops is how it behaves when the condition fails on the first check. Let's see this in action. +Here is a regular while loop that will run the code in the loop as long as i < 5. +
var ourArray = [];
var i = 5;
while (i < 5) {
  ourArray.push(i);
  i++;
}
+Notice that we initialize the value of i to be 5. When we execute the next line, we notice that i is not less than 5. So we do not execute the code inside the loop. The result is that ourArray will end up with nothing added to it, so it will still look like this [] when all the code in the example above finishes running. +Now, take a look at a do...while loop. +
var ourArray = [];
var i = 5;
do {
  ourArray.push(i);
  i++;
} while (i < 5);
+In this case, we initialize the value of i as 5, just like we did with the while loop. When we get to the next line, there is no check for the value of i, so we go to the code inside the curly braces and execute it. We will add one element to the array and increment i before we get to the condition check. Then, when we get to checking if i < 5 see that i is now 6, which fails the conditional check. So we exit the loop and are done. At the end of the above example, the value of ourArray is [5]. +Essentially, a do...while loop ensures that the code inside the loop will run at least once. +Let's try getting a do...while loop to work by pushing values to an array. +
+ +## Instructions +
+Change the while loop in the code to a do...while loop so that the loop will push the number 10 to myArray, and i will be equal to 11 when your code finishes running. +
+ +## Tests +
+ +```yml +- text: You should be using a do...while loop for this. + testString: 'assert(code.match(/do/g), "You should be using a do...while loop for this.");' +- text: 'myArray should equal [10].' + testString: 'assert.deepEqual(myArray, [10], "myArray should equal [10].");' +- text: i should equal 11 + testString: 'assert.deepEqual(i, 11, "i should equal 11");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +// Setup +var myArray = []; +var i = 10; + +// Only change code below this line. + +while (i < 5) { + myArray.push(i); + i++; +} + +``` + +
+ + +### After Test +
+ +```js +console.info('after the test'); +``` + +
+ +
+ +## Solution +
+ + +```js +var myArray = []; +var i = 10; +do { + myArray.push(i); + i++; +} while (i < 5) +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Iterate with JavaScript For Loops.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Iterate with JavaScript For Loops.md new file mode 100644 index 0000000000..cf07a86392 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Iterate with JavaScript For Loops.md @@ -0,0 +1,89 @@ +--- +id: cf1111c1c11feddfaeb5bdef +title: Iterate with JavaScript For Loops +challengeType: 1 +--- + +## Description +
+You can run the same code multiple times by using a loop. +The most common type of JavaScript loop is called a "for loop" because it runs "for" a specific number of times. +For loops are declared with three optional expressions separated by semicolons: +for ([initialization]; [condition]; [final-expression]) +The initialization statement is executed one time only before the loop starts. It is typically used to define and setup your loop variable. +The condition statement is evaluated at the beginning of every loop iteration and will continue as long as it evaluates to true. When condition is false at the start of the iteration, the loop will stop executing. This means if condition starts as false, your loop will never execute. +The final-expression is executed at the end of each loop iteration, prior to the next condition check and is usually used to increment or decrement your loop counter. +In the following example we initialize with i = 0 and iterate while our condition i < 5 is true. We'll increment i by 1 in each loop iteration with i++ as our final-expression. +
var ourArray = [];
for (var i = 0; i < 5; i++) {
  ourArray.push(i);
}
+ourArray will now contain [0,1,2,3,4]. +
+ +## Instructions +
+Use a for loop to work to push the values 1 through 5 onto myArray. +
+ +## Tests +
+ +```yml +- text: You should be using a for loop for this. + testString: 'assert(code.match(/for\s*\(/g).length > 1, "You should be using a for loop for this.");' +- text: 'myArray should equal [1,2,3,4,5].' + testString: 'assert.deepEqual(myArray, [1,2,3,4,5], "myArray should equal [1,2,3,4,5].");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +// Example +var ourArray = []; + +for (var i = 0; i < 5; i++) { + ourArray.push(i); +} + +// Setup +var myArray = []; + +// Only change code below this line. + + +``` + +
+ + +### After Test +
+ +```js +console.info('after the test'); +``` + +
+ +
+ +## Solution +
+ + +```js +var ourArray = []; +for (var i = 0; i < 5; i++) { + ourArray.push(i); +} +var myArray = []; +for (var i = 1; i < 6; i++) { + myArray.push(i); +} +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Iterate with JavaScript While Loops.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Iterate with JavaScript While Loops.md new file mode 100644 index 0000000000..82f7fe7714 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Iterate with JavaScript While Loops.md @@ -0,0 +1,74 @@ +--- +id: cf1111c1c11feddfaeb1bdef +title: Iterate with JavaScript While Loops +challengeType: 1 +--- + +## Description +
+You can run the same code multiple times by using a loop. +The first type of loop we will learn is called a "while" loop because it runs "while" a specified condition is true and stops once that condition is no longer true. +
var ourArray = [];
var i = 0;
while(i < 5) {
  ourArray.push(i);
  i++;
}
+Let's try getting a while loop to work by pushing values to an array. +
+ +## Instructions +
+Push the numbers 0 through 4 to myArray using a while loop. +
+ +## Tests +
+ +```yml +- text: You should be using a while loop for this. + testString: 'assert(code.match(/while/g), "You should be using a while loop for this.");' +- text: 'myArray should equal [0,1,2,3,4].' + testString: 'assert.deepEqual(myArray, [0,1,2,3,4], "myArray should equal [0,1,2,3,4].");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +// Setup +var myArray = []; + +// Only change code below this line. + + +``` + +
+ + +### After Test +
+ +```js +console.info('after the test'); +``` + +
+ +
+ +## Solution +
+ + +```js +var myArray = []; +var i = 0; +while(i < 5) { + myArray.push(i); + i++; +} +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Local Scope and Functions.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Local Scope and Functions.md new file mode 100644 index 0000000000..c9307f731a --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Local Scope and Functions.md @@ -0,0 +1,109 @@ +--- +id: 56533eb9ac21ba0edf2244bf +title: Local Scope and Functions +challengeType: 1 +--- + +## Description +
+Variables which are declared within a function, as well as the function parameters have local scope. That means, they are only visible within that function. +Here is a function myTest with a local variable called loc. +
function myTest() {
  var loc = "foo";
  console.log(loc);
}
myTest(); // logs "foo"
console.log(loc); // loc is not defined
+loc is not defined outside of the function. +
+ +## Instructions +
+Declare a local variable myVar inside myLocalScope. Run the tests and then follow the instructions commented out in the editor. +Hint
Refreshing the page may help if you get stuck. +
+ +## Tests +
+ +```yml +- text: No global myVar variable + testString: 'assert(typeof myVar === "undefined", "No global myVar variable");' +- text: Add a local myVar variable + testString: 'assert(/var\s+myVar/.test(code), "Add a local myVar variable");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +function myLocalScope() { + 'use strict'; // you shouldn't need to edit this line + + console.log(myVar); +} +myLocalScope(); + +// Run and check the console +// myVar is not defined outside of myLocalScope +console.log(myVar); + +// Now remove the console log line to pass the test + +``` + +
+ +### Before Test +
+ +```js +var logOutput = ""; +var originalConsole = console +function capture() { + var nativeLog = console.log; + console.log = function (message) { + logOutput = message; + if(nativeLog.apply) { + nativeLog.apply(originalConsole, arguments); + } else { + var nativeMsg = Array.prototype.slice.apply(arguments).join(' '); + nativeLog(nativeMsg); + } + }; +} + +function uncapture() { + console.log = originalConsole.log; +} + +``` + +
+ +### After Test +
+ +```js +console.info('after the test'); +``` + +
+ +
+ +## Solution +
+ + +```js +function myLocalScope() { + 'use strict'; + + var myVar; + console.log(myVar); +} +myLocalScope(); +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Logical Order in If Else Statements.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Logical Order in If Else Statements.md new file mode 100644 index 0000000000..b925decf0e --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Logical Order in If Else Statements.md @@ -0,0 +1,82 @@ +--- +id: 5690307fddb111c6084545d7 +title: Logical Order in If Else Statements +challengeType: 1 +--- + +## Description +
+Order is important in if, else if statements. +The function is executed from top to bottom so you will want to be careful of what statement comes first. +Take these two functions as an example. +Here's the first: +
function foo(x) {
  if (x < 1) {
    return "Less than one";
  } else if (x < 2) {
    return "Less than two";
  } else {
    return "Greater than or equal to two";
  }
}
+And the second just switches the order of the statements: +
function bar(x) {
  if (x < 2) {
    return "Less than two";
  } else if (x < 1) {
    return "Less than one";
  } else {
    return "Greater than or equal to two";
  }
}
+While these two functions look nearly identical if we pass a number to both we get different outputs. +
foo(0) // "Less than one"
bar(0) // "Less than two"
+
+ +## Instructions +
+Change the order of logic in the function so that it will return the correct statements in all cases. +
+ +## Tests +
+ +```yml +- text: orderMyLogic(4) should return "Less than 5" + testString: 'assert(orderMyLogic(4) === "Less than 5", "orderMyLogic(4) should return "Less than 5"");' +- text: orderMyLogic(6) should return "Less than 10" + testString: 'assert(orderMyLogic(6) === "Less than 10", "orderMyLogic(6) should return "Less than 10"");' +- text: orderMyLogic(11) should return "Greater than or equal to 10" + testString: 'assert(orderMyLogic(11) === "Greater than or equal to 10", "orderMyLogic(11) should return "Greater than or equal to 10"");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +function orderMyLogic(val) { + if (val < 10) { + return "Less than 10"; + } else if (val < 5) { + return "Less than 5"; + } else { + return "Greater than or equal to 10"; + } +} + +// Change this value to test +orderMyLogic(7); +``` + +
+ + + +
+ +## Solution +
+ + +```js +function orderMyLogic(val) { + if(val < 5) { + return "Less than 5"; + } else if (val < 10) { + return "Less than 10"; + } else { + return "Greater than or equal to 10"; + } +} +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Manipulate Arrays With pop().md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Manipulate Arrays With pop().md new file mode 100644 index 0000000000..8a969d37fe --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Manipulate Arrays With pop().md @@ -0,0 +1,78 @@ +--- +id: 56bbb991ad1ed5201cd392cc +title: Manipulate Arrays With pop() +challengeType: 1 +--- + +## Description +
+Another way to change the data in an array is with the .pop() function. +.pop() is used to "pop" a value off of the end of an array. We can store this "popped off" value by assigning it to a variable. In other words, .pop() removes the last element from an array and returns that element. +Any type of entry can be "popped" off of an array - numbers, strings, even nested arrays. +
var threeArr = [1, 4, 6];
var oneDown = threeArr.pop();
console.log(oneDown); // Returns 6
console.log(threeArr); // Returns [1, 4]
+
+ +## Instructions +
+Use the .pop() function to remove the last item from myArray, assigning the "popped off" value to removedFromMyArray. +
+ +## Tests +
+ +```yml +- text: 'myArray should only contain [["John", 23]].' + testString: 'assert((function(d){if(d[0][0] == "John" && d[0][1] === 23 && d[1] == undefined){return true;}else{return false;}})(myArray), "myArray should only contain [["John", 23]].");' +- text: Use pop() on myArray + testString: 'assert(/removedFromMyArray\s*=\s*myArray\s*.\s*pop\s*(\s*)/.test(code), "Use pop() on myArray");' +- text: 'removedFromMyArray should only contain ["cat", 2].' + testString: 'assert((function(d){if(d[0] == "cat" && d[1] === 2 && d[2] == undefined){return true;}else{return false;}})(removedFromMyArray), "removedFromMyArray should only contain ["cat", 2].");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +// Example +var ourArray = [1,2,3]; +var removedFromOurArray = ourArray.pop(); +// removedFromOurArray now equals 3, and ourArray now equals [1,2] + +// Setup +var myArray = [["John", 23], ["cat", 2]]; + +// Only change code below this line. +var removedFromMyArray; + + +``` + +
+ + +### After Test +
+ +```js +console.info('after the test'); +``` + +
+ +
+ +## Solution +
+ + +```js +var myArray = [["John", 23], ["cat", 2]]; +var removedFromMyArray = myArray.pop(); +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Manipulate Arrays With push().md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Manipulate Arrays With push().md new file mode 100644 index 0000000000..3afedda507 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Manipulate Arrays With push().md @@ -0,0 +1,72 @@ +--- +id: 56bbb991ad1ed5201cd392cb +title: Manipulate Arrays With push() +challengeType: 1 +--- + +## Description +
+An easy way to append data to the end of an array is via the push() function. +.push() takes one or more parameters and "pushes" them onto the end of the array. +
var arr = [1,2,3];
arr.push(4);
// arr is now [1,2,3,4]
+
+ +## Instructions +
+Push ["dog", 3] onto the end of the myArray variable. +
+ +## Tests +
+ +```yml +- text: 'myArray should now equal [["John", 23], ["cat", 2], ["dog", 3]].' + testString: 'assert((function(d){if(d[2] != undefined && d[0][0] == "John" && d[0][1] === 23 && d[2][0] == "dog" && d[2][1] === 3 && d[2].length == 2){return true;}else{return false;}})(myArray), "myArray should now equal [["John", 23], ["cat", 2], ["dog", 3]].");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +// Example +var ourArray = ["Stimpson", "J", "cat"]; +ourArray.push(["happy", "joy"]); +// ourArray now equals ["Stimpson", "J", "cat", ["happy", "joy"]] + +// Setup +var myArray = [["John", 23], ["cat", 2]]; + +// Only change code below this line. + + +``` + +
+ + +### After Test +
+ +```js +console.info('after the test'); +``` + +
+ +
+ +## Solution +
+ + +```js +var myArray = [["John", 23], ["cat", 2]]; +myArray.push(["dog",3]); +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Manipulate Arrays With shift().md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Manipulate Arrays With shift().md new file mode 100644 index 0000000000..fc24c04f1e --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Manipulate Arrays With shift().md @@ -0,0 +1,76 @@ +--- +id: 56bbb991ad1ed5201cd392cd +title: Manipulate Arrays With shift() +challengeType: 1 +--- + +## Description +
+pop() always removes the last element of an array. What if you want to remove the first? +That's where .shift() comes in. It works just like .pop(), except it removes the first element instead of the last. +
+ +## Instructions +
+Use the .shift() function to remove the first item from myArray, assigning the "shifted off" value to removedFromMyArray. +
+ +## Tests +
+ +```yml +- text: 'myArray should now equal [["dog", 3]].' + testString: 'assert((function(d){if(d[0][0] == "dog" && d[0][1] === 3 && d[1] == undefined){return true;}else{return false;}})(myArray), "myArray should now equal [["dog", 3]].");' +- text: 'removedFromMyArray should contain ["John", 23].' + testString: 'assert((function(d){if(d[0] == "John" && d[1] === 23 && typeof removedFromMyArray === "object"){return true;}else{return false;}})(removedFromMyArray), "removedFromMyArray should contain ["John", 23].");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +// Example +var ourArray = ["Stimpson", "J", ["cat"]]; +var removedFromOurArray = ourArray.shift(); +// removedFromOurArray now equals "Stimpson" and ourArray now equals ["J", ["cat"]]. + +// Setup +var myArray = [["John", 23], ["dog", 3]]; + +// Only change code below this line. +var removedFromMyArray; + + +``` + +
+ + +### After Test +
+ +```js +console.info('after the test'); +``` + +
+ +
+ +## Solution +
+ + +```js +var myArray = [["John", 23], ["dog", 3]]; + +// Only change code below this line. +var removedFromMyArray = myArray.shift(); +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Manipulate Arrays With unshift().md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Manipulate Arrays With unshift().md new file mode 100644 index 0000000000..7e2f8675a3 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Manipulate Arrays With unshift().md @@ -0,0 +1,74 @@ +--- +id: 56bbb991ad1ed5201cd392ce +title: Manipulate Arrays With unshift() +challengeType: 1 +--- + +## Description +
+Not only can you shift elements off of the beginning of an array, you can also unshift elements to the beginning of an array i.e. add elements in front of the array. +.unshift() works exactly like .push(), but instead of adding the element at the end of the array, unshift() adds the element at the beginning of the array. +
+ +## Instructions +
+Add ["Paul",35] to the beginning of the myArray variable using unshift(). +
+ +## Tests +
+ +```yml +- text: 'myArray should now have [["Paul", 35], ["dog", 3]].' + testString: 'assert((function(d){if(typeof d[0] === "object" && d[0][0] == "Paul" && d[0][1] === 35 && d[1][0] != undefined && d[1][0] == "dog" && d[1][1] != undefined && d[1][1] == 3){return true;}else{return false;}})(myArray), "myArray should now have [["Paul", 35], ["dog", 3]].");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +// Example +var ourArray = ["Stimpson", "J", "cat"]; +ourArray.shift(); // ourArray now equals ["J", "cat"] +ourArray.unshift("Happy"); +// ourArray now equals ["Happy", "J", "cat"] + +// Setup +var myArray = [["John", 23], ["dog", 3]]; +myArray.shift(); + +// Only change code below this line. + + +``` + +
+ + +### After Test +
+ +```js +console.info('after the test'); +``` + +
+ +
+ +## Solution +
+ + +```js +var myArray = [["John", 23], ["dog", 3]]; +myArray.shift(); +myArray.unshift(["Paul", 35]); +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Manipulating Complex Objects.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Manipulating Complex Objects.md new file mode 100644 index 0000000000..e8e03aee6f --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Manipulating Complex Objects.md @@ -0,0 +1,118 @@ +--- +id: 56533eb9ac21ba0edf2244cb +title: Manipulating Complex Objects +challengeType: 1 +--- + +## Description +
+Sometimes you may want to store data in a flexible Data Structure. A JavaScript object is one way to handle flexible data. They allow for arbitrary combinations of strings, numbers, booleans, arrays, functions, and objects. +Here's an example of a complex data structure: +
var ourMusic = [
  {
    "artist": "Daft Punk",
    "title": "Homework",
    "release_year": 1997,
    "formats": [
      "CD",
      "Cassette",
      "LP"
    ],
    "gold": true
  }
];
+This is an array which contains one object inside. The object has various pieces of metadata about an album. It also has a nested "formats" array. If you want to add more album records, you can do this by adding records to the top level array. +Objects hold data in a property, which has a key-value format. In the example above, "artist": "Daft Punk" is a property that has a key of "artist" and a value of "Daft Punk". +JavaScript Object Notation or JSON is a related data interchange format used to store data. +
{
  "artist": "Daft Punk",
  "title": "Homework",
  "release_year": 1997,
  "formats": [
    "CD",
    "Cassette",
    "LP"
  ],
  "gold": true
}
+Note
You will need to place a comma after every object in the array, unless it is the last object in the array. +
+ +## Instructions +
+Add a new album to the myMusic array. Add artist and title strings, release_year number, and a formats array of strings. +
+ +## Tests +
+ +```yml +- text: myMusic should be an array + testString: 'assert(Array.isArray(myMusic), "myMusic should be an array");' +- text: myMusic should have at least two elements + testString: 'assert(myMusic.length > 1, "myMusic should have at least two elements");' +- text: 'myMusic[1] should be an object' + testString: 'assert(typeof myMusic[1] === "object", "myMusic[1] should be an object");' +- text: 'myMusic[1] should have at least 4 properties' + testString: 'assert(Object.keys(myMusic[1]).length > 3, "myMusic[1] should have at least 4 properties");' +- text: 'myMusic[1] should contain an artist property which is a string' + testString: 'assert(myMusic[1].hasOwnProperty("artist") && typeof myMusic[1].artist === "string", "myMusic[1] should contain an artist property which is a string");' +- text: 'myMusic[1] should contain a title property which is a string' + testString: 'assert(myMusic[1].hasOwnProperty("title") && typeof myMusic[1].title === "string", "myMusic[1] should contain a title property which is a string");' +- text: 'myMusic[1] should contain a release_year property which is a number' + testString: 'assert(myMusic[1].hasOwnProperty("release_year") && typeof myMusic[1].release_year === "number", "myMusic[1] should contain a release_year property which is a number");' +- text: 'myMusic[1] should contain a formats property which is an array' + testString: 'assert(myMusic[1].hasOwnProperty("formats") && Array.isArray(myMusic[1].formats), "myMusic[1] should contain a formats property which is an array");' +- text: formats should be an array of strings with at least two elements + testString: 'assert(myMusic[1].formats.every(function(item) { return (typeof item === "string")}) && myMusic[1].formats.length > 1, "formats should be an array of strings with at least two elements");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +var myMusic = [ + { + "artist": "Billy Joel", + "title": "Piano Man", + "release_year": 1973, + "formats": [ + "CD", + "8T", + "LP" + ], + "gold": true + } + // Add record here +]; + +``` + +
+ + +### After Test +
+ +```js +console.info('after the test'); +``` + +
+ +
+ +## Solution +
+ + +```js +var myMusic = [ + { + "artist": "Billy Joel", + "title": "Piano Man", + "release_year": 1973, + "formats": [ + "CS", + "8T", + "LP" ], + "gold": true + }, + { + "artist": "ABBA", + "title": "Ring Ring", + "release_year": 1973, + "formats": [ + "CS", + "8T", + "LP", + "CD", + ] + } +]; +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Modify Array Data With Indexes.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Modify Array Data With Indexes.md new file mode 100644 index 0000000000..1fca93b584 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Modify Array Data With Indexes.md @@ -0,0 +1,74 @@ +--- +id: cf1111c1c11feddfaeb8bdef +title: Modify Array Data With Indexes +challengeType: 1 +--- + +## Description +
+Unlike strings, the entries of arrays are mutable and can be changed freely. +Example +
var ourArray = [50,40,30];
ourArray[0] = 15; // equals [15,40,30]
+Note
There shouldn't be any spaces between the array name and the square brackets, like array [0]. Although JavaScript is able to process this correctly, this may confuse other programmers reading your code. +
+ +## Instructions +
+Modify the data stored at index 0 of myArray to a value of 45. +
+ +## Tests +
+ +```yml +- text: 'myArray should now be [45,64,99].' + testString: 'assert((function(){if(typeof myArray != "undefined" && myArray[0] == 45 && myArray[1] == 64 && myArray[2] == 99){return true;}else{return false;}})(), "myArray should now be [45,64,99].");' +- text: You should be using correct index to modify the value in myArray. + testString: 'assert((function(){if(code.match(/myArray\[0\]\s*=\s*/g)){return true;}else{return false;}})(), "You should be using correct index to modify the value in myArray.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +// Example +var ourArray = [18,64,99]; +ourArray[1] = 45; // ourArray now equals [18,45,99]. + +// Setup +var myArray = [18,64,99]; + +// Only change code below this line. + + +``` + +
+ + +### After Test +
+ +```js +console.info('after the test'); +``` + +
+ +
+ +## Solution +
+ + +```js +var myArray = [18,64,99]; +myArray[0] = 45; +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Multiple Identical Options in Switch Statements.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Multiple Identical Options in Switch Statements.md new file mode 100644 index 0000000000..6e83e869f6 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Multiple Identical Options in Switch Statements.md @@ -0,0 +1,107 @@ +--- +id: 56533eb9ac21ba0edf2244df +title: Multiple Identical Options in Switch Statements +challengeType: 1 +--- + +## Description +
+If the break statement is omitted from a switch statement's case, the following case statement(s) are executed until a break is encountered. If you have multiple inputs with the same output, you can represent them in a switch statement like this: +
switch(val) {
  case 1:
  case 2:
  case 3:
    result = "1, 2, or 3";
    break;
  case 4:
    result = "4 alone";
}
+Cases for 1, 2, and 3 will all produce the same result. +
+ +## Instructions +
+Write a switch statement to set answer for the following ranges:
1-3 - "Low"
4-6 - "Mid"
7-9 - "High" +Note
You will need to have a case statement for each number in the range. +
+ +## Tests +
+ +```yml +- text: sequentialSizes(1) should return "Low" + testString: 'assert(sequentialSizes(1) === "Low", "sequentialSizes(1) should return "Low"");' +- text: sequentialSizes(2) should return "Low" + testString: 'assert(sequentialSizes(2) === "Low", "sequentialSizes(2) should return "Low"");' +- text: sequentialSizes(3) should return "Low" + testString: 'assert(sequentialSizes(3) === "Low", "sequentialSizes(3) should return "Low"");' +- text: sequentialSizes(4) should return "Mid" + testString: 'assert(sequentialSizes(4) === "Mid", "sequentialSizes(4) should return "Mid"");' +- text: sequentialSizes(5) should return "Mid" + testString: 'assert(sequentialSizes(5) === "Mid", "sequentialSizes(5) should return "Mid"");' +- text: sequentialSizes(6) should return "Mid" + testString: 'assert(sequentialSizes(6) === "Mid", "sequentialSizes(6) should return "Mid"");' +- text: sequentialSizes(7) should return "High" + testString: 'assert(sequentialSizes(7) === "High", "sequentialSizes(7) should return "High"");' +- text: sequentialSizes(8) should return "High" + testString: 'assert(sequentialSizes(8) === "High", "sequentialSizes(8) should return "High"");' +- text: sequentialSizes(9) should return "High" + testString: 'assert(sequentialSizes(9) === "High", "sequentialSizes(9) should return "High"");' +- text: You should not use any if or else statements + testString: 'assert(!/else/g.test(code) || !/if/g.test(code), "You should not use any if or else statements");' +- text: You should have nine case statements + testString: 'assert(code.match(/case/g).length === 9, "You should have nine case statements");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +function sequentialSizes(val) { + var answer = ""; + // Only change code below this line + + + + // Only change code above this line + return answer; +} + +// Change this value to test +sequentialSizes(1); + +``` + +
+ + + +
+ +## Solution +
+ + +```js +function sequentialSizes(val) { + var answer = ""; + + switch(val) { + case 1: + case 2: + case 3: + answer = "Low"; + break; + case 4: + case 5: + case 6: + answer = "Mid"; + break; + case 7: + case 8: + case 9: + answer = "High"; + } + + return answer; +} +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Multiply Two Decimals with JavaScript.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Multiply Two Decimals with JavaScript.md new file mode 100644 index 0000000000..3373d0f281 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Multiply Two Decimals with JavaScript.md @@ -0,0 +1,64 @@ +--- +id: bd7993c9c69feddfaeb7bdef +title: Multiply Two Decimals with JavaScript +challengeType: 1 +--- + +## Description +
+In JavaScript, you can also perform calculations with decimal numbers, just like whole numbers. +Let's multiply two decimals together to get their product. +
+ +## Instructions +
+Change the 0.0 so that product will equal 5.0. +
+ +## Tests +
+ +```yml +- text: The variable product should equal 5.0. + testString: 'assert(product === 5.0, "The variable product should equal 5.0.");' +- text: You should use the * operator + testString: 'assert(/\*/.test(code), "You should use the * operator");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +var product = 2.0 * 0.0; + + +``` + +
+ + +### After Test +
+ +```js +console.info('after the test'); +``` + +
+ +
+ +## Solution +
+ + +```js +var product = 2.0 * 2.5; +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Multiply Two Numbers with JavaScript.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Multiply Two Numbers with JavaScript.md new file mode 100644 index 0000000000..8206482eba --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Multiply Two Numbers with JavaScript.md @@ -0,0 +1,68 @@ +--- +id: cf1231c1c11feddfaeb5bdef +title: Multiply Two Numbers with JavaScript +challengeType: 1 +--- + +## Description +
+We can also multiply one number by another. +JavaScript uses the * symbol for multiplication of two numbers. + +Example +
myVar = 13 * 13; // assigned 169
+ +
+ +## Instructions +
+Change the 0 so that product will equal 80. +
+ +## Tests +
+ +```yml +- text: Make the variable product equal 80 + testString: 'assert(product === 80,"Make the variable product equal 80");' +- text: Use the * operator + testString: 'assert(/\*/.test(code), "Use the * operator");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +var product = 8 * 0; + + +``` + +
+ + +### After Test +
+ +```js +console.info('after the test'); +``` + +
+ +
+ +## Solution +
+ + +```js +var product = 8 * 10; +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Nest one Array within Another Array.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Nest one Array within Another Array.md new file mode 100644 index 0000000000..d77d900e69 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Nest one Array within Another Array.md @@ -0,0 +1,64 @@ +--- +id: cf1111c1c11feddfaeb7bdef +title: Nest one Array within Another Array +challengeType: 1 +--- + +## Description +
+You can also nest arrays within other arrays, like this: [["Bulls", 23], ["White Sox", 45]]. This is also called a Multi-dimensional Array. +
+ +## Instructions +
+Create a nested array called myArray. +
+ +## Tests +
+ +```yml +- text: myArray should have at least one array nested within another array. + testString: 'assert(Array.isArray(myArray) && myArray.some(Array.isArray), "myArray should have at least one array nested within another array.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +// Example +var ourArray = [["the universe", 42], ["everything", 101010]]; + +// Only change code below this line. +var myArray = []; + +``` + +
+ + +### After Test +
+ +```js +console.info('after the test'); +``` + +
+ +
+ +## Solution +
+ + +```js +var myArray = [[1,2,3]]; +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Nesting For Loops.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Nesting For Loops.md new file mode 100644 index 0000000000..6f9690864b --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Nesting For Loops.md @@ -0,0 +1,77 @@ +--- +id: 56533eb9ac21ba0edf2244e1 +title: Nesting For Loops +challengeType: 1 +--- + +## Description +
+If you have a multi-dimensional array, you can use the same logic as the prior waypoint to loop through both the array and any sub-arrays. Here is an example: +
var arr = [
  [1,2], [3,4], [5,6]
];
for (var i=0; i < arr.length; i++) {
  for (var j=0; j < arr[i].length; j++) {
    console.log(arr[i][j]);
  }
}
+This outputs each sub-element in arr one at a time. Note that for the inner loop, we are checking the .length of arr[i], since arr[i] is itself an array. +
+ +## Instructions +
+Modify function multiplyAll so that it multiplies the product variable by each number in the sub-arrays of arr +
+ +## Tests +
+ +```yml +- text: 'multiplyAll([[1],[2],[3]]) should return 6' + testString: 'assert(multiplyAll([[1],[2],[3]]) === 6, "multiplyAll([[1],[2],[3]]) should return 6");' +- text: 'multiplyAll([[1,2],[3,4],[5,6,7]]) should return 5040' + testString: 'assert(multiplyAll([[1,2],[3,4],[5,6,7]]) === 5040, "multiplyAll([[1,2],[3,4],[5,6,7]]) should return 5040");' +- text: 'multiplyAll([[5,1],[0.2, 4, 0.5],[3, 9]]) should return 54' + testString: 'assert(multiplyAll([[5,1],[0.2, 4, 0.5],[3, 9]]) === 54, "multiplyAll([[5,1],[0.2, 4, 0.5],[3, 9]]) should return 54");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +function multiplyAll(arr) { + var product = 1; + // Only change code below this line + + // Only change code above this line + return product; +} + +// Modify values below to test your code +multiplyAll([[1,2],[3,4],[5,6,7]]); + +``` + +
+ + + +
+ +## Solution +
+ + +```js +function multiplyAll(arr) { + var product = 1; + for (var i = 0; i < arr.length; i++) { + for (var j = 0; j < arr[i].length; j++) { + product *= arr[i][j]; + } + } + return product; +} + +multiplyAll([[1,2],[3,4],[5,6,7]]); +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Passing Values to Functions with Arguments.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Passing Values to Functions with Arguments.md new file mode 100644 index 0000000000..ff1d0a47b6 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Passing Values to Functions with Arguments.md @@ -0,0 +1,108 @@ +--- +id: 56533eb9ac21ba0edf2244bd +title: Passing Values to Functions with Arguments +challengeType: 1 +--- + +## Description +
+Parameters are variables that act as placeholders for the values that are to be input to a function when it is called. When a function is defined, it is typically defined along with one or more parameters. The actual values that are input (or "passed") into a function when it is called are known as arguments. +Here is a function with two parameters, param1 and param2: +
function testFun(param1, param2) {
  console.log(param1, param2);
}
+Then we can call testFun: +testFun("Hello", "World"); +We have passed two arguments, "Hello" and "World". Inside the function, param1 will equal "Hello" and param2 will equal "World". Note that you could call testFun again with different arguments and the parameters would take on the value of the new arguments. +
+ +## Instructions +
+
  1. Create a function called functionWithArgs that accepts two arguments and outputs their sum to the dev console.
  2. Call the function with two numbers as arguments.
+
+ +## Tests +
+ +```yml +- text: functionWithArgs should be a function + testString: 'assert(typeof functionWithArgs === "function", "functionWithArgs should be a function");' +- text: 'functionWithArgs(1,2) should output 3' + testString: 'if(typeof functionWithArgs === "function") { capture(); functionWithArgs(1,2); uncapture(); } assert(logOutput == 3, "functionWithArgs(1,2) should output 3");' +- text: 'functionWithArgs(7,9) should output 16' + testString: 'if(typeof functionWithArgs === "function") { capture(); functionWithArgs(7,9); uncapture(); } assert(logOutput == 16, "functionWithArgs(7,9) should output 16");' +- text: Call functionWithArgs with two numbers after you define it. + testString: 'assert(/^\s*functionWithArgs\s*\(\s*\d+\s*,\s*\d+\s*\)\s*;/m.test(code), "Call functionWithArgs with two numbers after you define it.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +// Example +function ourFunctionWithArgs(a, b) { + console.log(a - b); +} +ourFunctionWithArgs(10, 5); // Outputs 5 + +// Only change code below this line. + + +``` + +
+ +### Before Test +
+ +```js +var logOutput = ""; +var originalConsole = console +function capture() { + var nativeLog = console.log; + console.log = function (message) { + if(message) logOutput = JSON.stringify(message).trim(); + if(nativeLog.apply) { + nativeLog.apply(originalConsole, arguments); + } else { + var nativeMsg = Array.prototype.slice.apply(arguments).join(' '); + nativeLog(nativeMsg); + } + }; +} + +function uncapture() { + console.log = originalConsole.log; +} + +capture(); +``` + +
+ +### After Test +
+ +```js +console.info('after the test'); +``` + +
+ +
+ +## Solution +
+ + +```js +function functionWithArgs(a, b) { + console.log(a + b); +} +functionWithArgs(10, 5); +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Practice comparing different values.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Practice comparing different values.md new file mode 100644 index 0000000000..0efa05bd4e --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Practice comparing different values.md @@ -0,0 +1,74 @@ +--- +id: 599a789b454f2bbd91a3ff4d +title: Practice comparing different values +challengeType: 1 +--- + +## Description +
+In the last two challenges, we learned about the equality operator (==) and the strict equality operator (===). Let's do a quick review and practice using these operators some more. +If the values being compared are not of the same type, the equality operator will perform a type conversion, and then evaluate the values. However, the strict equality operator will compare both the data type and value as-is, without converting one type to the other. +Examples +
3 == '3' // returns true because JavaScript performs type conversion from string to number
3 === '3' // returns false because the types are different and type conversion is not performed
+Note
In JavaScript, you can determine the type of a variable or a value with the typeof operator, as follows: +
typeof 3 // returns 'number'
typeof '3' // returns 'string'
+
+ +## Instructions +
+The compareEquality function in the editor compares two values using the equality operator. Modify the function so that it returns "Equal" only when the values are strictly equal. +
+ +## Tests +
+ +```yml +- text: 'compareEquality(10, "10") should return "Not Equal"' + testString: 'assert(compareEquality(10, "10") === "Not Equal", "compareEquality(10, "10") should return "Not Equal"");' +- text: 'compareEquality("20", 20) should return "Not Equal"' + testString: 'assert(compareEquality("20", 20) === "Not Equal", "compareEquality("20", 20) should return "Not Equal"");' +- text: You should use the === operator + testString: 'assert(code.match(/===/g), "You should use the === operator");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +// Setup +function compareEquality(a, b) { + if (a == b) { // Change this line + return "Equal"; + } + return "Not Equal"; +} + +// Change this value to test +compareEquality(10, "10"); +``` + +
+ + + +
+ +## Solution +
+ + +```js +function compareEquality(a,b) { + if (a === b) { + return "Equal"; + } + return "Not Equal"; +} +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Profile Lookup.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Profile Lookup.md new file mode 100644 index 0000000000..a1e7ef6272 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Profile Lookup.md @@ -0,0 +1,141 @@ +--- +id: 5688e62ea601b2482ff8422b +title: Profile Lookup +challengeType: 1 +--- + +## Description +
+We have an array of objects representing different people in our contacts lists. +A lookUpProfile function that takes name and a property (prop) as arguments has been pre-written for you. +The function should check if name is an actual contact's firstName and the given property (prop) is a property of that contact. +If both are true, then return the "value" of that property. +If name does not correspond to any contacts then return "No such contact" +If prop does not correspond to any valid properties of a contact found to match name then return "No such property" +
+ +## Instructions +
+ +
+ +## Tests +
+ +```yml +- text: '"Kristian", "lastName" should return "Vos"' + testString: 'assert(lookUpProfile("Kristian","lastName") === "Vos", ""Kristian", "lastName" should return "Vos"");' +- text: '"Sherlock", "likes" should return ["Intriguing Cases", "Violin"]' + testString: 'assert.deepEqual(lookUpProfile("Sherlock", "likes"), ["Intriguing Cases", "Violin"], ""Sherlock", "likes" should return ["Intriguing Cases", "Violin"]");' +- text: '"Harry","likes" should return an array' + testString: 'assert(typeof lookUpProfile("Harry", "likes") === "object", ""Harry","likes" should return an array");' +- text: '"Bob", "number" should return "No such contact"' + testString: 'assert(lookUpProfile("Bob", "number") === "No such contact", ""Bob", "number" should return "No such contact"");' +- text: '"Bob", "potato" should return "No such contact"' + testString: 'assert(lookUpProfile("Bob", "potato") === "No such contact", ""Bob", "potato" should return "No such contact"");' +- text: '"Akira", "address" should return "No such property"' + testString: 'assert(lookUpProfile("Akira", "address") === "No such property", ""Akira", "address" should return "No such property"");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +//Setup +var contacts = [ + { + "firstName": "Akira", + "lastName": "Laine", + "number": "0543236543", + "likes": ["Pizza", "Coding", "Brownie Points"] + }, + { + "firstName": "Harry", + "lastName": "Potter", + "number": "0994372684", + "likes": ["Hogwarts", "Magic", "Hagrid"] + }, + { + "firstName": "Sherlock", + "lastName": "Holmes", + "number": "0487345643", + "likes": ["Intriguing Cases", "Violin"] + }, + { + "firstName": "Kristian", + "lastName": "Vos", + "number": "unknown", + "likes": ["JavaScript", "Gaming", "Foxes"] + } +]; + + +function lookUpProfile(name, prop){ +// Only change code below this line + +// Only change code above this line +} + +// Change these values to test your function +lookUpProfile("Akira", "likes"); +``` + +
+ + + +
+ +## Solution +
+ + +```js +var contacts = [ + { + "firstName": "Akira", + "lastName": "Laine", + "number": "0543236543", + "likes": ["Pizza", "Coding", "Brownie Points"] + }, + { + "firstName": "Harry", + "lastName": "Potter", + "number": "0994372684", + "likes": ["Hogwarts", "Magic", "Hagrid"] + }, + { + "firstName": "Sherlock", + "lastName": "Holmes", + "number": "0487345643", + "likes": ["Intriguing Cases", "Violin"] + }, + { + "firstName": "Kristian", + "lastName": "Vos", + "number": "unknown", + "likes": ["JavaScript", "Gaming", "Foxes"] + }, +]; + + +//Write your function in between these comments +function lookUpProfile(name, prop){ + for(var i in contacts){ + if(contacts[i].firstName === name) { + return contacts[i][prop] || "No such property"; + } + } + return "No such contact"; +} +//Write your function in between these comments + +lookUpProfile("Akira", "likes"); +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Quoting Strings with Single Quotes.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Quoting Strings with Single Quotes.md new file mode 100644 index 0000000000..fc5da694a7 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Quoting Strings with Single Quotes.md @@ -0,0 +1,71 @@ +--- +id: 56533eb9ac21ba0edf2244b4 +title: Quoting Strings with Single Quotes +challengeType: 1 +--- + +## Description +
+String values in JavaScript may be written with single or double quotes, as long as you start and end with the same type of quote. Unlike some other programming languages, single and double quotes work the same in JavaScript. +
doubleQuoteStr = "This is a string";
singleQuoteStr = 'This is also a string';
+The reason why you might want to use one type of quote over the other is if you want to use both in a string. This might happen if you want to save a conversation in a string and have the conversation in quotes. Another use for it would be saving an <a> tag with various attributes in quotes, all within a string. +
conversation = 'Finn exclaims to Jake, "Algebraic!"';
+However, this becomes a problem if you need to use the outermost quotes within it. Remember, a string has the same kind of quote at the beginning and end. But if you have that same quote somewhere in the middle, the string will stop early and throw an error. +
goodStr = 'Jake asks Finn, "Hey, let\'s go on an adventure?"';
badStr = 'Finn responds, "Let's go!"'; // Throws an error
+In the goodStr above, you can use both quotes safely by using the backslash \ as an escape character. +Note
The backslash \ should not be be confused with the forward slash /. They do not do the same thing. +
+ +## Instructions +
+Change the provided string to a string with single quotes at the beginning and end and no escape characters. +Right now, the <a> tag in the string uses double quotes everywhere. You will need to change the outer quotes to single quotes so you can remove the escape characters. +
+ +## Tests +
+ +```yml +- text: Remove all the backslashes (\) + testString: 'assert(!/\\/g.test(code) && myStr.match("\\s*\\s*Link\\s*\\s*"), "Remove all the backslashes (\)");' +- text: 'You should have two single quotes ' and four double quotes "' + testString: 'assert(code.match(/"/g).length === 4 && code.match(/"/g).length === 2, "You should have two single quotes ' and four double quotes "");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +var myStr = "Link"; + + +``` + +
+ + +### After Test +
+ +```js +console.info('after the test'); +``` + +
+ +
+ +## Solution +
+ + +```js +var myStr = 'Link'; +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Record Collection.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Record Collection.md new file mode 100644 index 0000000000..a8066d3c33 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Record Collection.md @@ -0,0 +1,158 @@ +--- +id: 56533eb9ac21ba0edf2244cf +title: Record Collection +challengeType: 1 +--- + +## Description +
+You are given a JSON object representing a part of your musical album collection. Each album has several properties and a unique id number as its key. Not all albums have complete information. +Write a function which takes an album's id (like 2548), a property prop (like "artist" or "tracks"), and a value (like "Addicted to Love") to modify the data in this collection. +If prop isn't "tracks" and value isn't empty (""), update or set the value for that record album's property. +Your function must always return the entire collection object. +There are several rules for handling incomplete data: +If prop is "tracks" but the album doesn't have a "tracks" property, create an empty array before adding the new value to the album's corresponding property. +If prop is "tracks" and value isn't empty (""), push the value onto the end of the album's existing tracks array. +If value is empty (""), delete the given prop property from the album. +Hints
Use bracket notation when accessing object properties with variables. +Push is an array method you can read about on Mozilla Developer Network. +You may refer back to Manipulating Complex Objects Introducing JavaScript Object Notation (JSON) for a refresher. +
+ +## Instructions +
+ +
+ +## Tests +
+ +```yml +- text: 'After updateRecords(5439, "artist", "ABBA"), artist should be "ABBA"' + testString: 'collection = collectionCopy; assert(updateRecords(5439, "artist", "ABBA")[5439]["artist"] === "ABBA", "After updateRecords(5439, "artist", "ABBA"), artist should be "ABBA"");' +- text: 'After updateRecords(5439, "tracks", "Take a Chance on Me"), tracks should have "Take a Chance on Me" as the last element.' + testString: 'assert(updateRecords(5439, "tracks", "Take a Chance on Me")[5439]["tracks"].pop() === "Take a Chance on Me", "After updateRecords(5439, "tracks", "Take a Chance on Me"), tracks should have "Take a Chance on Me" as the last element.");' +- text: 'After updateRecords(2548, "artist", ""), artist should not be set' + testString: 'updateRecords(2548, "artist", ""); assert(!collection[2548].hasOwnProperty("artist"), "After updateRecords(2548, "artist", ""), artist should not be set");' +- text: 'After updateRecords(1245, "tracks", "Addicted to Love"), tracks should have "Addicted to Love" as the last element.' + testString: 'assert(updateRecords(1245, "tracks", "Addicted to Love")[1245]["tracks"].pop() === "Addicted to Love", "After updateRecords(1245, "tracks", "Addicted to Love"), tracks should have "Addicted to Love" as the last element.");' +- text: 'After updateRecords(2468, "tracks", "Free"), tracks should have "1999" as the first element.' + testString: 'assert(updateRecords(2468, "tracks", "Free")[2468]["tracks"][0] === "1999", "After updateRecords(2468, "tracks", "Free"), tracks should have "1999" as the first element.");' +- text: 'After updateRecords(2548, "tracks", ""), tracks should not be set' + testString: 'updateRecords(2548, "tracks", ""); assert(!collection[2548].hasOwnProperty("tracks"), "After updateRecords(2548, "tracks", ""), tracks should not be set");' +- text: 'After updateRecords(1245, "album", "Riptide"), album should be "Riptide"' + testString: 'assert(updateRecords(1245, "album", "Riptide")[1245]["album"] === "Riptide", "After updateRecords(1245, "album", "Riptide"), album should be "Riptide"");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +// Setup +var collection = { + "2548": { + "album": "Slippery When Wet", + "artist": "Bon Jovi", + "tracks": [ + "Let It Rock", + "You Give Love a Bad Name" + ] + }, + "2468": { + "album": "1999", + "artist": "Prince", + "tracks": [ + "1999", + "Little Red Corvette" + ] + }, + "1245": { + "artist": "Robert Palmer", + "tracks": [ ] + }, + "5439": { + "album": "ABBA Gold" + } +}; +// Keep a copy of the collection for tests +var collectionCopy = JSON.parse(JSON.stringify(collection)); + +// Only change code below this line +function updateRecords(id, prop, value) { + + + return collection; +} + +// Alter values below to test your code +updateRecords(5439, "artist", "ABBA"); + +``` + +
+ + +### After Test +
+ +```js +console.info('after the test'); +``` + +
+ +
+ +## Solution +
+ + +```js +var collection = { + 2548: { + album: "Slippery When Wet", + artist: "Bon Jovi", + tracks: [ + "Let It Rock", + "You Give Love a Bad Name" + ] + }, + 2468: { + album: "1999", + artist: "Prince", + tracks: [ + "1999", + "Little Red Corvette" + ] + }, + 1245: { + artist: "Robert Palmer", + tracks: [ ] + }, + 5439: { + album: "ABBA Gold" + } +}; +// Keep a copy of the collection for tests +var collectionCopy = JSON.parse(JSON.stringify(collection)); + +// Only change code below this line +function updateRecords(id, prop, value) { + if(value === "") delete collection[id][prop]; + else if(prop === "tracks") { + collection[id][prop] = collection[id][prop] || []; + collection[id][prop].push(value); + } else { + collection[id][prop] = value; + } + + return collection; +} +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Replacing If Else Chains with Switch.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Replacing If Else Chains with Switch.md new file mode 100644 index 0000000000..f69bc11e4d --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Replacing If Else Chains with Switch.md @@ -0,0 +1,114 @@ +--- +id: 56533eb9ac21ba0edf2244e0 +title: Replacing If Else Chains with Switch +challengeType: 1 +--- + +## Description +
+If you have many options to choose from, a switch statement can be easier to write than many chained if/else if statements. The following: +
if (val === 1) {
  answer = "a";
} else if (val === 2) {
  answer = "b";
} else {
  answer = "c";
}
+can be replaced with: +
switch(val) {
  case 1:
    answer = "a";
    break;
  case 2:
    answer = "b";
    break;
  default:
    answer = "c";
}
+
+ +## Instructions +
+Change the chained if/else if statements into a switch statement. +
+ +## Tests +
+ +```yml +- text: You should not use any else statements anywhere in the editor + testString: 'assert(!/else/g.test(code), "You should not use any else statements anywhere in the editor");' +- text: You should not use any if statements anywhere in the editor + testString: 'assert(!/if/g.test(code), "You should not use any if statements anywhere in the editor");' +- text: You should have at least four break statements + testString: 'assert(code.match(/break/g).length >= 4, "You should have at least four break statements");' +- text: chainToSwitch("bob") should be "Marley" + testString: 'assert(chainToSwitch("bob") === "Marley", "chainToSwitch("bob") should be "Marley"");' +- text: chainToSwitch(42) should be "The Answer" + testString: 'assert(chainToSwitch(42) === "The Answer", "chainToSwitch(42) should be "The Answer"");' +- text: 'chainToSwitch(1) should be "There is no #1"' + testString: 'assert(chainToSwitch(1) === "There is no #1", "chainToSwitch(1) should be "There is no #1"");' +- text: chainToSwitch(99) should be "Missed me by this much!" + testString: 'assert(chainToSwitch(99) === "Missed me by this much!", "chainToSwitch(99) should be "Missed me by this much!"");' +- text: chainToSwitch(7) should be "Ate Nine" + testString: 'assert(chainToSwitch(7) === "Ate Nine", "chainToSwitch(7) should be "Ate Nine"");' +- text: chainToSwitch("John") should be "" (empty string) + testString: 'assert(chainToSwitch("John") === "", "chainToSwitch("John") should be "" (empty string)");' +- text: chainToSwitch(156) should be "" (empty string) + testString: 'assert(chainToSwitch(156) === "", "chainToSwitch(156) should be "" (empty string)");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +function chainToSwitch(val) { + var answer = ""; + // Only change code below this line + + if (val === "bob") { + answer = "Marley"; + } else if (val === 42) { + answer = "The Answer"; + } else if (val === 1) { + answer = "There is no #1"; + } else if (val === 99) { + answer = "Missed me by this much!"; + } else if (val === 7) { + answer = "Ate Nine"; + } + + // Only change code above this line + return answer; +} + +// Change this value to test +chainToSwitch(7); + +``` + +
+ + + +
+ +## Solution +
+ + +```js +function chainToSwitch(val) { + var answer = ""; + + switch(val) { + case "bob": + answer = "Marley"; + break; + case 42: + answer = "The Answer"; + break; + case 1: + answer = "There is no #1"; + break; + case 99: + answer = "Missed me by this much!"; + break; + case 7: + answer = "Ate Nine"; + } + return answer; +} +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Return Early Pattern for Functions.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Return Early Pattern for Functions.md new file mode 100644 index 0000000000..6b69e95c5a --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Return Early Pattern for Functions.md @@ -0,0 +1,82 @@ +--- +id: 56533eb9ac21ba0edf2244c4 +title: Return Early Pattern for Functions +challengeType: 1 +--- + +## Description +
+When a return statement is reached, the execution of the current function stops and control returns to the calling location. +Example +
function myFun() {
  console.log("Hello");
  return "World";
  console.log("byebye")
}
myFun();
+The above outputs "Hello" to the console, returns "World", but "byebye" is never output, because the function exits at the return statement. +
+ +## Instructions +
+Modify the function abTest so that if a or b are less than 0 the function will immediately exit with a value of undefined. +Hint
Remember that undefined is a keyword, not a string. +
+ +## Tests +
+ +```yml +- text: 'abTest(2,2) should return a number' + testString: 'assert(typeof abTest(2,2) === "number" , "abTest(2,2) should return a number");' +- text: 'abTest(2,2) should return 8' + testString: 'assert(abTest(2,2) === 8 , "abTest(2,2) should return 8");' +- text: 'abTest(-2,2) should return undefined' + testString: 'assert(abTest(-2,2) === undefined , "abTest(-2,2) should return undefined");' +- text: 'abTest(2,-2) should return undefined' + testString: 'assert(abTest(2,-2) === undefined , "abTest(2,-2) should return undefined");' +- text: 'abTest(2,8) should return 18' + testString: 'assert(abTest(2,8) === 18 , "abTest(2,8) should return 18");' +- text: 'abTest(3,3) should return 12' + testString: 'assert(abTest(3,3) === 12 , "abTest(3,3) should return 12");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +// Setup +function abTest(a, b) { + // Only change code below this line + + + + // Only change code above this line + + return Math.round(Math.pow(Math.sqrt(a) + Math.sqrt(b), 2)); +} + +// Change values below to test your code +abTest(2,2); +``` + +
+ + + +
+ +## Solution +
+ + +```js +function abTest(a, b) { + if(a < 0 || b < 0) { + return undefined; + } + return Math.round(Math.pow(Math.sqrt(a) + Math.sqrt(b), 2)); +} +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Return a Value from a Function with Return.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Return a Value from a Function with Return.md new file mode 100644 index 0000000000..16013f85d8 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Return a Value from a Function with Return.md @@ -0,0 +1,72 @@ +--- +id: 56533eb9ac21ba0edf2244c2 +title: Return a Value from a Function with Return +challengeType: 1 +--- + +## Description +
+We can pass values into a function with arguments. You can use a return statement to send a value back out of a function. +Example +
function plusThree(num) {
  return num + 3;
}
var answer = plusThree(5); // 8
+plusThree takes an argument for num and returns a value equal to num + 3. +
+ +## Instructions +
+Create a function timesFive that accepts one argument, multiplies it by 5, and returns the new value. See the last line in the editor for an example of how you can test your timesFive function. +
+ +## Tests +
+ +```yml +- text: timesFive should be a function + testString: 'assert(typeof timesFive === "function", "timesFive should be a function");' +- text: timesFive(5) should return 25 + testString: 'assert(timesFive(5) === 25, "timesFive(5) should return 25");' +- text: timesFive(2) should return 10 + testString: 'assert(timesFive(2) === 10, "timesFive(2) should return 10");' +- text: timesFive(0) should return 0 + testString: 'assert(timesFive(0) === 0, "timesFive(0) should return 0");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +// Example +function minusSeven(num) { + return num - 7; +} + +// Only change code below this line + + + +console.log(minusSeven(10)); +``` + +
+ + + +
+ +## Solution +
+ + +```js +function timesFive(num) { + return num * 5; +} +timesFive(10); +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Returning Boolean Values from Functions.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Returning Boolean Values from Functions.md new file mode 100644 index 0000000000..206eb1169e --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Returning Boolean Values from Functions.md @@ -0,0 +1,71 @@ +--- +id: 5679ceb97cbaa8c51670a16b +title: Returning Boolean Values from Functions +challengeType: 1 +--- + +## Description +
+You may recall from Comparison with the Equality Operator that all comparison operators return a boolean true or false value. +Sometimes people use an if/else statement to do a comparison, like this: +
function isEqual(a,b) {
  if (a === b) {
    return true;
  } else {
    return false;
  }
}
+But there's a better way to do this. Since === returns true or false, we can return the result of the comparison: +
function isEqual(a,b) {
  return a === b;
}
+
+ +## Instructions +
+Fix the function isLess to remove the if/else statements. +
+ +## Tests +
+ +```yml +- text: 'isLess(10,15) should return true' + testString: 'assert(isLess(10,15) === true, "isLess(10,15) should return true");' +- text: 'isLess(15,10) should return false' + testString: 'assert(isLess(15, 10) === false, "isLess(15,10) should return false");' +- text: You should not use any if or else statements + testString: 'assert(!/if|else/g.test(code), "You should not use any if or else statements");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +function isLess(a, b) { + // Fix this code + if (a < b) { + return true; + } else { + return false; + } +} + +// Change these values to test +isLess(10, 15); +``` + +
+ + + +
+ +## Solution +
+ + +```js +function isLess(a, b) { + return a < b; +} +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Selecting from Many Options with Switch Statements.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Selecting from Many Options with Switch Statements.md new file mode 100644 index 0000000000..6ced857fda --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Selecting from Many Options with Switch Statements.md @@ -0,0 +1,93 @@ +--- +id: 56533eb9ac21ba0edf2244dd +title: Selecting from Many Options with Switch Statements +challengeType: 1 +--- + +## Description +
+If you have many options to choose from, use a switch statement. A switch statement tests a value and can have many case statements which define various possible values. Statements are executed from the first matched case value until a break is encountered. +Here is a pseudocode example: +
switch(num) {
  case value1:
    statement1;
    break;
  case value2:
    statement2;
    break;
...
  case valueN:
    statementN;
    break;
}
+case values are tested with strict equality (===). The break tells JavaScript to stop executing statements. If the break is omitted, the next statement will be executed. +
+ +## Instructions +
+Write a switch statement which tests val and sets answer for the following conditions:
1 - "alpha"
2 - "beta"
3 - "gamma"
4 - "delta" +
+ +## Tests +
+ +```yml +- text: caseInSwitch(1) should have a value of "alpha" + testString: 'assert(caseInSwitch(1) === "alpha", "caseInSwitch(1) should have a value of "alpha"");' +- text: caseInSwitch(2) should have a value of "beta" + testString: 'assert(caseInSwitch(2) === "beta", "caseInSwitch(2) should have a value of "beta"");' +- text: caseInSwitch(3) should have a value of "gamma" + testString: 'assert(caseInSwitch(3) === "gamma", "caseInSwitch(3) should have a value of "gamma"");' +- text: caseInSwitch(4) should have a value of "delta" + testString: 'assert(caseInSwitch(4) === "delta", "caseInSwitch(4) should have a value of "delta"");' +- text: You should not use any if or else statements + testString: 'assert(!/else/g.test(code) || !/if/g.test(code), "You should not use any if or else statements");' +- text: You should have at least 3 break statements + testString: 'assert(code.match(/break/g).length > 2, "You should have at least 3 break statements");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +function caseInSwitch(val) { + var answer = ""; + // Only change code below this line + + + + // Only change code above this line + return answer; +} + +// Change this value to test +caseInSwitch(1); + +``` + +
+ + + +
+ +## Solution +
+ + +```js +function caseInSwitch(val) { + var answer = ""; + + switch(val) { + case 1: + answer = "alpha"; + break; + case 2: + answer = "beta"; + break; + case 3: + answer = "gamma"; + break; + case 4: + answer = "delta"; + } + return answer; +} +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Shopping List.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Shopping List.md new file mode 100644 index 0000000000..9182c91da6 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Shopping List.md @@ -0,0 +1,76 @@ +--- +id: 56533eb9ac21ba0edf2244bc +title: Shopping List +challengeType: 1 +--- + +## Description +
+Create a shopping list in the variable myList. The list should be a multi-dimensional array containing several sub-arrays. +The first element in each sub-array should contain a string with the name of the item. The second element should be a number representing the quantity i.e. +["Chocolate Bar", 15] +There should be at least 5 sub-arrays in the list. +
+ +## Instructions +
+ +
+ +## Tests +
+ +```yml +- text: myList should be an array + testString: 'assert(isArray, "myList should be an array");' +- text: The first elements in each of your sub-arrays must all be strings + testString: 'assert(hasString, "The first elements in each of your sub-arrays must all be strings");' +- text: The second elements in each of your sub-arrays must all be numbers + testString: 'assert(hasNumber, "The second elements in each of your sub-arrays must all be numbers");' +- text: You must have at least 5 items in your list + testString: 'assert(count > 4, "You must have at least 5 items in your list");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +var myList = []; + + +``` + +
+ + +### After Test +
+ +```js +console.info('after the test'); +``` + +
+ +
+ +## Solution +
+ + +```js +var myList = [ + ["Candy", 10], + ["Potatoes", 12], + ["Eggs", 12], + ["Catfood", 1], + ["Toads", 9] +]; +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Stand in Line.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Stand in Line.md new file mode 100644 index 0000000000..fbf41b036d --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Stand in Line.md @@ -0,0 +1,114 @@ +--- +id: 56533eb9ac21ba0edf2244c6 +title: Stand in Line +challengeType: 1 +--- + +## Description +
+In Computer Science a queue is an abstract Data Structure where items are kept in order. New items can be added at the back of the queue and old items are taken off from the front of the queue. +Write a function nextInLine which takes an array (arr) and a number (item) as arguments. +Add the number to the end of the array, then remove the first element of the array. +The nextInLine function should then return the element that was removed. +
+ +## Instructions +
+ +
+ +## Tests +
+ +```yml +- text: 'nextInLine([], 5) should return a number.' + testString: 'assert.isNumber(nextInLine([],5), "nextInLine([], 5) should return a number.");' +- text: 'nextInLine([], 1) should return 1' + testString: 'assert(nextInLine([],1) === 1, "nextInLine([], 1) should return 1");' +- text: 'nextInLine([2], 1) should return 2' + testString: 'assert(nextInLine([2],1) === 2, "nextInLine([2], 1) should return 2");' +- text: 'nextInLine([5,6,7,8,9], 1) should return 5' + testString: 'assert(nextInLine([5,6,7,8,9],1) === 5, "nextInLine([5,6,7,8,9], 1) should return 5");' +- text: 'After nextInLine(testArr, 10), testArr[4] should be 10' + testString: 'nextInLine(testArr, 10); assert(testArr[4] === 10, "After nextInLine(testArr, 10), testArr[4] should be 10");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +function nextInLine(arr, item) { + // Your code here + + return item; // Change this line +} + +// Test Setup +var testArr = [1,2,3,4,5]; + +// Display Code +console.log("Before: " + JSON.stringify(testArr)); +console.log(nextInLine(testArr, 6)); // Modify this line to test +console.log("After: " + JSON.stringify(testArr)); +``` + +
+ +### Before Test +
+ +```js +var logOutput = []; +var originalConsole = console +function capture() { + var nativeLog = console.log; + console.log = function (message) { + logOutput.push(message); + if(nativeLog.apply) { + nativeLog.apply(originalConsole, arguments); + } else { + var nativeMsg = Array.prototype.slice.apply(arguments).join(' '); + nativeLog(nativeMsg); + } + }; +} + +function uncapture() { + console.log = originalConsole.log; +} + +capture(); +``` + +
+ +### After Test +
+ +```js +console.info('after the test'); +``` + +
+ +
+ +## Solution +
+ + +```js +var testArr = [ 1,2,3,4,5]; + +function nextInLine(arr, item) { + arr.push(item); + return arr.shift(); +} +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Store Multiple Values in one Variable using JavaScript Arrays.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Store Multiple Values in one Variable using JavaScript Arrays.md new file mode 100644 index 0000000000..69d2dc9d56 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Store Multiple Values in one Variable using JavaScript Arrays.md @@ -0,0 +1,71 @@ +--- +id: bd7993c9c69feddfaeb8bdef +title: Store Multiple Values in one Variable using JavaScript Arrays +challengeType: 1 +--- + +## Description +
+With JavaScript array variables, we can store several pieces of data in one place. +You start an array declaration with an opening square bracket, end it with a closing square bracket, and put a comma between each entry, like this: +var sandwich = ["peanut butter", "jelly", "bread"]. +
+ +## Instructions +
+Modify the new array myArray so that it contains both a string and a number (in that order). +Hint
Refer to the example code in the text editor if you get stuck. +
+ +## Tests +
+ +```yml +- text: myArray should be an array. + testString: 'assert(typeof myArray == "object", "myArray should be an array.");' +- text: The first item in myArray should be a string. + testString: 'assert(typeof myArray[0] !== "undefined" && typeof myArray[0] == "string", "The first item in myArray should be a string.");' +- text: The second item in myArray should be a number. + testString: 'assert(typeof myArray[1] !== "undefined" && typeof myArray[1] == "number", "The second item in myArray should be a number.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +// Example +var ourArray = ["John", 23]; + +// Only change code below this line. +var myArray = []; + +``` + +
+ + +### After Test +
+ +```js +console.info('after the test'); +``` + +
+ +
+ +## Solution +
+ + +```js +var myArray = ["The Answer", 42]; +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Storing Values with the Assignment Operator.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Storing Values with the Assignment Operator.md new file mode 100644 index 0000000000..08050ce24b --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Storing Values with the Assignment Operator.md @@ -0,0 +1,92 @@ +--- +id: 56533eb9ac21ba0edf2244a8 +title: Storing Values with the Assignment Operator +challengeType: 1 +--- + +## Description +
+In JavaScript, you can store a value in a variable with the assignment operator. +myVariable = 5; +This assigns the Number value 5 to myVariable. +Assignment always goes from right to left. Everything to the right of the = operator is resolved before the value is assigned to the variable to the left of the operator. +
myVar = 5;
myNum = myVar;
+This assigns 5 to myVar and then resolves myVar to 5 again and assigns it to myNum. +
+ +## Instructions +
+Assign the value 7 to variable a. +Assign the contents of a to variable b. +
+ +## Tests +
+ +```yml +- text: Do not change code above the line + testString: 'assert(/var a;/.test(code) && /var b = 2;/.test(code), "Do not change code above the line");' +- text: a should have a value of 7 + testString: 'assert(typeof a === "number" && a === 7, "a should have a value of 7");' +- text: b should have a value of 7 + testString: 'assert(typeof b === "number" && b === 7, "b should have a value of 7");' +- text: a should be assigned to b with = + testString: 'assert(/b\s*=\s*a\s*;/g.test(code), "a should be assigned to b with =");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +// Setup +var a; +var b = 2; + +// Only change code below this line + +``` + +
+ +### Before Test +
+ +```js +if (typeof a != 'undefined') { + a = undefined; +} +if (typeof b != 'undefined') { + b = undefined; +} +``` + +
+ +### After Test +
+ +```js +console.info('after the test'); +``` + +
+ +
+ +## Solution +
+ + +```js +var a; +var b = 2; +a = 7; +b = a; +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Subtract One Number from Another with JavaScript.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Subtract One Number from Another with JavaScript.md new file mode 100644 index 0000000000..d0c0892a86 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Subtract One Number from Another with JavaScript.md @@ -0,0 +1,68 @@ +--- +id: cf1111c1c11feddfaeb4bdef +title: Subtract One Number from Another with JavaScript +challengeType: 1 +--- + +## Description +
+We can also subtract one number from another. +JavaScript uses the - symbol for subtraction. + +Example +
myVar = 12 - 6; // assigned 6
+ +
+ +## Instructions +
+Change the 0 so the difference is 12. +
+ +## Tests +
+ +```yml +- text: Make the variable difference equal 12. + testString: 'assert(difference === 12, "Make the variable difference equal 12.");' +- text: Only subtract one number from 45. + testString: 'assert(/var\s*difference\s*=\s*45\s*-\s*[0-9]*;(?!\s*[a-zA-Z0-9]+)/.test(code),"Only subtract one number from 45.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +var difference = 45 - 0; + + +``` + +
+ + +### After Test +
+ +```js +console.info('after the test'); +``` + +
+ +
+ +## Solution +
+ + +```js +var difference = 45 - 33; +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Testing Objects for Properties.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Testing Objects for Properties.md new file mode 100644 index 0000000000..ffc2835dc1 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Testing Objects for Properties.md @@ -0,0 +1,82 @@ +--- +id: 567af2437cbaa8c51670a16c +title: Testing Objects for Properties +challengeType: 1 +--- + +## Description +
+Sometimes it is useful to check if the property of a given object exists or not. We can use the .hasOwnProperty(propname) method of objects to determine if that object has the given property name. .hasOwnProperty() returns true or false if the property is found or not. +Example +
var myObj = {
  top: "hat",
  bottom: "pants"
};
myObj.hasOwnProperty("top"); // true
myObj.hasOwnProperty("middle"); // false
+
+ +## Instructions +
+Modify the function checkObj to test myObj for checkProp. If the property is found, return that property's value. If not, return "Not Found". +
+ +## Tests +
+ +```yml +- text: checkObj("gift") should return "pony". + testString: 'assert(checkObj("gift") === "pony", "checkObj("gift") should return "pony".");' +- text: checkObj("pet") should return "kitten". + testString: 'assert(checkObj("pet") === "kitten", "checkObj("pet") should return "kitten".");' +- text: checkObj("house") should return "Not Found". + testString: 'assert(checkObj("house") === "Not Found", "checkObj("house") should return "Not Found".");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +// Setup +var myObj = { + gift: "pony", + pet: "kitten", + bed: "sleigh" +}; + +function checkObj(checkProp) { + // Your Code Here + + return "Change Me!"; +} + +// Test your code by modifying these values +checkObj("gift"); +``` + +
+ + + +
+ +## Solution +
+ + +```js +var myObj = { + gift: "pony", + pet: "kitten", + bed: "sleigh" +}; +function checkObj(checkProp) { + if(myObj.hasOwnProperty(checkProp)) { + return myObj[checkProp]; + } else { + return "Not Found"; + } +} +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Understand String Immutability.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Understand String Immutability.md new file mode 100644 index 0000000000..16113796b1 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Understand String Immutability.md @@ -0,0 +1,73 @@ +--- +id: 56533eb9ac21ba0edf2244ba +title: Understand String Immutability +challengeType: 1 +--- + +## Description +
+In JavaScript, String values are immutable, which means that they cannot be altered once created. +For example, the following code: +
var myStr = "Bob";
myStr[0] = "J";
+cannot change the value of myStr to "Job", because the contents of myStr cannot be altered. Note that this does not mean that myStr cannot be changed, just that the individual characters of a string literal cannot be changed. The only way to change myStr would be to assign it with a new string, like this: +
var myStr = "Bob";
myStr = "Job";
+
+ +## Instructions +
+Correct the assignment to myStr so it contains the string value of Hello World using the approach shown in the example above. +
+ +## Tests +
+ +```yml +- text: myStr should have a value of Hello World + testString: 'assert(myStr === "Hello World", "myStr should have a value of Hello World");' +- text: Do not change the code above the line + testString: 'assert(/myStr = "Jello World"/.test(code), "Do not change the code above the line");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +// Setup +var myStr = "Jello World"; + +// Only change code below this line + +myStr[0] = "H"; // Fix Me + + +``` + +
+ + +### After Test +
+ +```js +console.info('after the test'); +``` + +
+ +
+ +## Solution +
+ + +```js +var myStr = "Jello World"; +myStr = "Hello World"; +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Understanding Boolean Values.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Understanding Boolean Values.md new file mode 100644 index 0000000000..f257fa0f80 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Understanding Boolean Values.md @@ -0,0 +1,71 @@ +--- +id: bd7123c9c441eddfaeb5bdef +title: Understanding Boolean Values +challengeType: 1 +--- + +## Description +
+Another data type is the Boolean. Booleans may only be one of two values: true or false. They are basically little on-off switches, where true is "on" and false is "off." These two states are mutually exclusive. +Note
Boolean values are never written with quotes. The strings "true" and "false" are not Boolean and have no special meaning in JavaScript. +
+ +## Instructions +
+Modify the welcomeToBooleans function so that it returns true instead of false when the run button is clicked. +
+ +## Tests +
+ +```yml +- text: 'The welcomeToBooleans() function should return a boolean (true/false) value.' + testString: 'assert(typeof welcomeToBooleans() === "boolean", "The welcomeToBooleans() function should return a boolean (true/false) value.");' +- text: welcomeToBooleans() should return true. + testString: 'assert(welcomeToBooleans() === true, "welcomeToBooleans() should return true.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +function welcomeToBooleans() { + +// Only change code below this line. + +return false; // Change this line + +// Only change code above this line. +} +``` + +
+ + +### After Test +
+ +```js +console.info('after the test'); +``` + +
+ +
+ +## Solution +
+ + +```js +function welcomeToBooleans() { + return true; // Change this line +} +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Understanding Case Sensitivity in Variables.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Understanding Case Sensitivity in Variables.md new file mode 100644 index 0000000000..966e7cba16 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Understanding Case Sensitivity in Variables.md @@ -0,0 +1,80 @@ +--- +id: 56533eb9ac21ba0edf2244ab +title: Understanding Case Sensitivity in Variables +challengeType: 1 +--- + +## Description +
+In JavaScript all variables and function names are case sensitive. This means that capitalization matters. +MYVAR is not the same as MyVar nor myvar. It is possible to have multiple distinct variables with the same name but different casing. It is strongly recommended that for the sake of clarity, you do not use this language feature. +

Best Practice

+Write variable names in JavaScript in camelCase. In camelCase, multi-word variable names have the first word in lowercase and the first letter of each subsequent word is capitalized. +Examples: +
var someVariable;
var anotherVariableName;
var thisVariableNameIsSoLong;
+
+ +## Instructions +
+Modify the existing declarations and assignments so their names use camelCase.
Do not create any new variables. +
+ +## Tests +
+ +```yml +- text: studlyCapVar is defined and has a value of 10 + testString: 'assert(typeof studlyCapVar !== "undefined" && studlyCapVar === 10, "studlyCapVar is defined and has a value of 10");' +- text: properCamelCase is defined and has a value of "A String" + testString: 'assert(typeof properCamelCase !== "undefined" && properCamelCase === "A String", "properCamelCase is defined and has a value of "A String"");' +- text: titleCaseOver is defined and has a value of 9000 + testString: 'assert(typeof titleCaseOver !== "undefined" && titleCaseOver === 9000, "titleCaseOver is defined and has a value of 9000");' +- text: studlyCapVar should use camelCase in both declaration and assignment sections. + testString: 'assert(code.match(/studlyCapVar/g).length === 2, "studlyCapVar should use camelCase in both declaration and assignment sections.");' +- text: properCamelCase should use camelCase in both declaration and assignment sections. + testString: 'assert(code.match(/properCamelCase/g).length === 2, "properCamelCase should use camelCase in both declaration and assignment sections.");' +- text: titleCaseOver should use camelCase in both declaration and assignment sections. + testString: 'assert(code.match(/titleCaseOver/g).length === 2, "titleCaseOver should use camelCase in both declaration and assignment sections.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +// Declarations +var StUdLyCapVaR; +var properCamelCase; +var TitleCaseOver; + +// Assignments +STUDLYCAPVAR = 10; +PRoperCAmelCAse = "A String"; +tITLEcASEoVER = 9000; +``` + +
+ + + +
+ +## Solution +
+ + +```js +var studlyCapVar; +var properCamelCase; +var titleCaseOver; + +studlyCapVar = 10; +properCamelCase = "A String"; +titleCaseOver = 9000; +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Understanding Undefined Value returned from a Function.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Understanding Undefined Value returned from a Function.md new file mode 100644 index 0000000000..1ba011e744 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Understanding Undefined Value returned from a Function.md @@ -0,0 +1,81 @@ +--- +id: 598e8944f009e646fc236146 +title: Understanding Undefined Value returned from a Function +challengeType: 1 +--- + +## Description +
+A function can include the return statement but it does not have to. In the case that the function doesn't have a return statement, when you call it, the function processes the inner code but the returned value is undefined. +Example +
var sum = 0;
function addSum(num) {
  sum = sum + num;
}
var returnedValue = addSum(3); // sum will be modified but returned value is undefined
+addSum is a function without a return statement. The function will change the global sum variable but the returned value of the function is undefined +
+ +## Instructions +
+Create a function addFive without any arguments. This function adds 5 to the sum variable, but its returned value is undefined. +
+ +## Tests +
+ +```yml +- text: addFive should be a function + testString: 'assert(typeof addFive === "function", "addFive should be a function");' +- text: sum should be equal to 8 + testString: 'assert(sum === 8, "sum should be equal to 8");' +- text: Returned value from addFive should be undefined + testString: 'assert(addFive() === undefined, "Returned value from addFive should be undefined");' +- text: 'Inside of your functions, add 5 to the sum variable' + testString: 'assert(code.match(/(sum\s*\=\s*sum\s*\+\s*5)|(sum\s*\+\=\s*5)/g).length === 1, "Inside of your functions, add 5 to the sum variable");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +// Example +var sum = 0; +function addThree() { + sum = sum + 3; +} + +// Only change code below this line + + + +// Only change code above this line +var returnedValue = addFive(); +``` + +
+ + +### After Test +
+ +```js +console.info('after the test'); +``` + +
+ +
+ +## Solution +
+ + +```js +function addFive() { + sum = sum + 5; +} +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Understanding Uninitialized Variables.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Understanding Uninitialized Variables.md new file mode 100644 index 0000000000..e2e25ce56a --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Understanding Uninitialized Variables.md @@ -0,0 +1,80 @@ +--- +id: 56533eb9ac21ba0edf2244aa +title: Understanding Uninitialized Variables +challengeType: 1 +--- + +## Description +
+When JavaScript variables are declared, they have an initial value of undefined. If you do a mathematical operation on an undefined variable your result will be NaN which means "Not a Number". If you concatenate a string with an undefined variable, you will get a literal string of "undefined". +
+ +## Instructions +
+Initialize the three variables a, b, and c with 5, 10, and "I am a" respectively so that they will not be undefined. +
+ +## Tests +
+ +```yml +- text: a should be defined and evaluated to have the value of 6 + testString: 'assert(typeof a === "number" && a === 6, "a should be defined and evaluated to have the value of 6");' +- text: b should be defined and evaluated to have the value of 15 + testString: 'assert(typeof b === "number" && b === 15, "b should be defined and evaluated to have the value of 15");' +- text: c should not contain undefined and should have a value of "I am a String!" + testString: 'assert(!/undefined/.test(c) && c === "I am a String!", "c should not contain undefined and should have a value of "I am a String!"");' +- text: Do not change code below the line + testString: 'assert(/a = a \+ 1;/.test(code) && /b = b \+ 5;/.test(code) && /c = c \+ " String!";/.test(code), "Do not change code below the line");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +// Initialize these three variables +var a; +var b; +var c; + +// Do not change code below this line + +a = a + 1; +b = b + 5; +c = c + " String!"; + +``` + +
+ + +### After Test +
+ +```js +console.info('after the test'); +``` + +
+ +
+ +## Solution +
+ + +```js +var a = 5; +var b = 10; +var c = "I am a"; +a = a + 1; +b = b + 5; +c = c + " String!"; +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Updating Object Properties.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Updating Object Properties.md new file mode 100644 index 0000000000..a9c6019136 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Updating Object Properties.md @@ -0,0 +1,93 @@ +--- +id: 56bbb991ad1ed5201cd392d1 +title: Updating Object Properties +challengeType: 1 +--- + +## Description +
+After you've created a JavaScript object, you can update its properties at any time just like you would update any other variable. You can use either dot or bracket notation to update. +For example, let's look at ourDog: +
var ourDog = {
  "name": "Camper",
  "legs": 4,
  "tails": 1,
  "friends": ["everything!"]
};
+Since he's a particularly happy dog, let's change his name to "Happy Camper". Here's how we update his object's name property: +ourDog.name = "Happy Camper"; or +ourDog["name"] = "Happy Camper"; +Now when we evaluate ourDog.name, instead of getting "Camper", we'll get his new name, "Happy Camper". +
+ +## Instructions +
+Update the myDog object's name property. Let's change her name from "Coder" to "Happy Coder". You can use either dot or bracket notation. +
+ +## Tests +
+ +```yml +- text: Update myDog's "name" property to equal "Happy Coder". + testString: 'assert(/happy coder/gi.test(myDog.name), "Update myDog's "name" property to equal "Happy Coder".");' +- text: Do not edit the myDog definition + testString: 'assert(/"name": "Coder"/.test(code), "Do not edit the myDog definition");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +// Example +var ourDog = { + "name": "Camper", + "legs": 4, + "tails": 1, + "friends": ["everything!"] +}; + +ourDog.name = "Happy Camper"; + +// Setup +var myDog = { + "name": "Coder", + "legs": 4, + "tails": 1, + "friends": ["freeCodeCamp Campers"] +}; + +// Only change code below this line. + + +``` + +
+ + +### After Test +
+ +```js +console.info('after the test'); +``` + +
+ +
+ +## Solution +
+ + +```js +var myDog = { + "name": "Coder", + "legs": 4, + "tails": 1, + "friends": ["freeCodeCamp Campers"] +}; +myDog.name = "Happy Coder"; +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Use Bracket Notation to Find the First Character in a String.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Use Bracket Notation to Find the First Character in a String.md new file mode 100644 index 0000000000..2328331457 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Use Bracket Notation to Find the First Character in a String.md @@ -0,0 +1,81 @@ +--- +id: bd7123c9c549eddfaeb5bdef +title: Use Bracket Notation to Find the First Character in a String +challengeType: 1 +--- + +## Description +
+Bracket notation is a way to get a character at a specific index within a string. +Most modern programming languages, like JavaScript, don't start counting at 1 like humans do. They start at 0. This is referred to as Zero-based indexing. +For example, the character at index 0 in the word "Charles" is "C". So if var firstName = "Charles", you can get the value of the first letter of the string by using firstName[0]. +
+ +## Instructions +
+Use bracket notation to find the first character in the lastName variable and assign it to firstLetterOfLastName. +Hint
Try looking at the firstLetterOfFirstName variable declaration if you get stuck. +
+ +## Tests +
+ +```yml +- text: The firstLetterOfLastName variable should have the value of L. + testString: 'assert(firstLetterOfLastName === "L", "The firstLetterOfLastName variable should have the value of L.");' +- text: You should use bracket notation. + testString: 'assert(code.match(/firstLetterOfLastName\s*?=\s*?lastName\[.*?\]/), "You should use bracket notation.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +// Example +var firstLetterOfFirstName = ""; +var firstName = "Ada"; + +firstLetterOfFirstName = firstName[0]; + +// Setup +var firstLetterOfLastName = ""; +var lastName = "Lovelace"; + +// Only change code below this line +firstLetterOfLastName = lastName; + + +``` + +
+ + +### After Test +
+ +```js +console.info('after the test'); +``` + +
+ +
+ +## Solution +
+ + +```js +var firstLetterOfLastName = ""; +var lastName = "Lovelace"; + +// Only change code below this line +firstLetterOfLastName = lastName[0]; +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Use Bracket Notation to Find the Last Character in a String.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Use Bracket Notation to Find the Last Character in a String.md new file mode 100644 index 0000000000..193780bd14 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Use Bracket Notation to Find the Last Character in a String.md @@ -0,0 +1,77 @@ +--- +id: bd7123c9c451eddfaeb5bdef +title: Use Bracket Notation to Find the Last Character in a String +challengeType: 1 +--- + +## Description +
+In order to get the last letter of a string, you can subtract one from the string's length. +For example, if var firstName = "Charles", you can get the value of the last letter of the string by using firstName[firstName.length - 1]. +
+ +## Instructions +
+Use bracket notation to find the last character in the lastName variable. +Hint
Try looking at the lastLetterOfFirstName variable declaration if you get stuck. +
+ +## Tests +
+ +```yml +- text: lastLetterOfLastName should be "e". + testString: 'assert(lastLetterOfLastName === "e", "lastLetterOfLastName should be "e".");' +- text: You have to use .length to get the last letter. + testString: 'assert(code.match(/\.length/g).length === 2, "You have to use .length to get the last letter.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +// Example +var firstName = "Ada"; +var lastLetterOfFirstName = firstName[firstName.length - 1]; + +// Setup +var lastName = "Lovelace"; + +// Only change code below this line. +var lastLetterOfLastName = lastName; + + +``` + +
+ + +### After Test +
+ +```js +console.info('after the test'); +``` + +
+ +
+ +## Solution +
+ + +```js +var firstName = "Ada"; +var lastLetterOfFirstName = firstName[firstName.length - 1]; + +var lastName = "Lovelace"; +var lastLetterOfLastName = lastName[lastName.length - 1]; +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Use Bracket Notation to Find the Nth Character in a String.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Use Bracket Notation to Find the Nth Character in a String.md new file mode 100644 index 0000000000..c060bc2002 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Use Bracket Notation to Find the Nth Character in a String.md @@ -0,0 +1,74 @@ +--- +id: bd7123c9c450eddfaeb5bdef +title: Use Bracket Notation to Find the Nth Character in a String +challengeType: 1 +--- + +## Description +
+You can also use bracket notation to get the character at other positions within a string. +Remember that computers start counting at 0, so the first character is actually the zeroth character. +
+ +## Instructions +
+Let's try to set thirdLetterOfLastName to equal the third letter of the lastName variable using bracket notation. +Hint
Try looking at the secondLetterOfFirstName variable declaration if you get stuck. +
+ +## Tests +
+ +```yml +- text: The thirdLetterOfLastName variable should have the value of v. + testString: 'assert(thirdLetterOfLastName === "v", "The thirdLetterOfLastName variable should have the value of v.");' +- text: You should use bracket notation. + testString: 'assert(code.match(/thirdLetterOfLastName\s*?=\s*?lastName\[.*?\]/), "You should use bracket notation.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +// Example +var firstName = "Ada"; +var secondLetterOfFirstName = firstName[1]; + +// Setup +var lastName = "Lovelace"; + +// Only change code below this line. +var thirdLetterOfLastName = lastName; + + +``` + +
+ + +### After Test +
+ +```js +console.info('after the test'); +``` + +
+ +
+ +## Solution +
+ + +```js +var lastName = "Lovelace"; +var thirdLetterOfLastName = lastName[2]; +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Use Bracket Notation to Find the Nth-to-Last Character in a String.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Use Bracket Notation to Find the Nth-to-Last Character in a String.md new file mode 100644 index 0000000000..7480f51180 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Use Bracket Notation to Find the Nth-to-Last Character in a String.md @@ -0,0 +1,77 @@ +--- +id: bd7123c9c452eddfaeb5bdef +title: Use Bracket Notation to Find the Nth-to-Last Character in a String +challengeType: 1 +--- + +## Description +
+You can use the same principle we just used to retrieve the last character in a string to retrieve the Nth-to-last character. +For example, you can get the value of the third-to-last letter of the var firstName = "Charles" string by using firstName[firstName.length - 3] +
+ +## Instructions +
+Use bracket notation to find the second-to-last character in the lastName string. +Hint
Try looking at the thirdToLastLetterOfFirstName variable declaration if you get stuck. +
+ +## Tests +
+ +```yml +- text: secondToLastLetterOfLastName should be "c". + testString: 'assert(secondToLastLetterOfLastName === "c", "secondToLastLetterOfLastName should be "c".");' +- text: You have to use .length to get the second last letter. + testString: 'assert(code.match(/\.length/g).length === 2, "You have to use .length to get the second last letter.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +// Example +var firstName = "Ada"; +var thirdToLastLetterOfFirstName = firstName[firstName.length - 3]; + +// Setup +var lastName = "Lovelace"; + +// Only change code below this line +var secondToLastLetterOfLastName = lastName; + + +``` + +
+ + +### After Test +
+ +```js +console.info('after the test'); +``` + +
+ +
+ +## Solution +
+ + +```js +var firstName = "Ada"; +var thirdToLastLetterOfFirstName = firstName[firstName.length - 3]; + +var lastName = "Lovelace"; +var secondToLastLetterOfLastName = lastName[lastName.length - 2]; +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Use Conditional Logic with If Statements.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Use Conditional Logic with If Statements.md new file mode 100644 index 0000000000..f6d38e0f1e --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Use Conditional Logic with If Statements.md @@ -0,0 +1,90 @@ +--- +id: cf1111c1c12feddfaeb3bdef +title: Use Conditional Logic with If Statements +challengeType: 1 +--- + +## Description +
+If statements are used to make decisions in code. The keyword if tells JavaScript to execute the code in the curly braces under certain conditions, defined in the parentheses. These conditions are known as Boolean conditions and they may only be true or false. +When the condition evaluates to true, the program executes the statement inside the curly braces. When the Boolean condition evaluates to false, the statement inside the curly braces will not execute. +Pseudocode +
if (condition is true) {
  statement is executed
}
+Example +
function test (myCondition) {
  if (myCondition) {
     return "It was true";
  }
  return "It was false";
}
test(true); // returns "It was true"
test(false); // returns "It was false"
+When test is called with a value of true, the if statement evaluates myCondition to see if it is true or not. Since it is true, the function returns "It was true". When we call test with a value of false, myCondition is not true and the statement in the curly braces is not executed and the function returns "It was false". +
+ +## Instructions +
+Create an if statement inside the function to return "Yes, that was true" if the parameter wasThatTrue is true and return "No, that was false" otherwise. +
+ +## Tests +
+ +```yml +- text: trueOrFalse should be a function + testString: 'assert(typeof trueOrFalse === "function", "trueOrFalse should be a function");' +- text: trueOrFalse(true) should return a string + testString: 'assert(typeof trueOrFalse(true) === "string", "trueOrFalse(true) should return a string");' +- text: trueOrFalse(false) should return a string + testString: 'assert(typeof trueOrFalse(false) === "string", "trueOrFalse(false) should return a string");' +- text: 'trueOrFalse(true) should return "Yes, that was true"' + testString: 'assert(trueOrFalse(true) === "Yes, that was true", "trueOrFalse(true) should return "Yes, that was true"");' +- text: 'trueOrFalse(false) should return "No, that was false"' + testString: 'assert(trueOrFalse(false) === "No, that was false", "trueOrFalse(false) should return "No, that was false"");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +// Example +function ourTrueOrFalse(isItTrue) { + if (isItTrue) { + return "Yes, it's true"; + } + return "No, it's false"; +} + +// Setup +function trueOrFalse(wasThatTrue) { + + // Only change code below this line. + + + + // Only change code above this line. + +} + +// Change this value to test +trueOrFalse(true); +``` + +
+ + + +
+ +## Solution +
+ + +```js +function trueOrFalse(wasThatTrue) { + if (wasThatTrue) { + return "Yes, that was true"; + } + return "No, that was false"; +} +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Use Multiple Conditional (Ternary) Operators.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Use Multiple Conditional (Ternary) Operators.md new file mode 100644 index 0000000000..7b915642fe --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Use Multiple Conditional (Ternary) Operators.md @@ -0,0 +1,63 @@ +--- +id: 587d7b7e367417b2b2512b21 +title: Use Multiple Conditional (Ternary) Operators +challengeType: 1 +--- + +## Description +
+In the previous challenge, you used a single conditional operator. You can also chain them together to check for multiple conditions. +The following function uses if, else if, and else statements to check multiple conditions: +
function findGreaterOrEqual(a, b) {
  if(a === b) {
    return "a and b are equal";
  }
  else if(a > b) {
    return "a is greater";
  }
  else {
    return "b is greater";
  }
}
+The above function can be re-written using multiple conditional operators: +
function findGreaterOrEqual(a, b) {
  return (a === b) ? "a and b are equal" : (a > b) ? "a is greater" : "b is greater";
}
+
+ +## Instructions +
+Use multiple conditional operators in the checkSign function to check if a number is positive, negative or zero. +
+ +## Tests +
+ +```yml +- text: checkSign should use multiple conditional operators + testString: 'assert(/.+?\s*?\?\s*?.+?\s*?:\s*?.+?\s*?\?\s*?.+?\s*?:\s*?.+?/gi.test(code), "checkSign should use multiple conditional operators");' +- text: checkSign(10) should return "positive". Note that capitalization matters + testString: 'assert(checkSign(10) === "positive", "checkSign(10) should return "positive". Note that capitalization matters");' +- text: checkSign(-12) should return "negative". Note that capitalization matters + testString: 'assert(checkSign(-12) === "negative", "checkSign(-12) should return "negative". Note that capitalization matters");' +- text: checkSign(0) should return "zero". Note that capitalization matters + testString: 'assert(checkSign(0) === "zero", "checkSign(0) should return "zero". Note that capitalization matters");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +function checkSign(num) { + +} + +checkSign(10); +``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Use the Conditional (Ternary) Operator.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Use the Conditional (Ternary) Operator.md new file mode 100644 index 0000000000..9af7f48e33 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Use the Conditional (Ternary) Operator.md @@ -0,0 +1,65 @@ +--- +id: 587d7b7e367417b2b2512b24 +title: Use the Conditional (Ternary) Operator +challengeType: 1 +--- + +## Description +
+The conditional operator, also called the ternary operator, can be used as a one line if-else expression. +The syntax is: +condition ? statement-if-true : statement-if-false; +The following function uses an if-else statement to check a condition: +
function findGreater(a, b) {
  if(a > b) {
    return "a is greater";
  }
  else {
    return "b is greater";
  }
}
+This can be re-written using the conditional operator: +
function findGreater(a, b) {
  return a > b ? "a is greater" : "b is greater";
}
+
+ +## Instructions +
+Use the conditional operator in the checkEqual function to check if two numbers are equal or not. The function should return either true or false. +
+ +## Tests +
+ +```yml +- text: checkEqual should use the conditional operator + testString: 'assert(/.+?\s*?\?\s*?.+?\s*?:\s*?.+?/gi.test(code), "checkEqual should use the conditional operator");' +- text: 'checkEqual(1, 2) should return false' + testString: 'assert(checkEqual(1, 2) === false, "checkEqual(1, 2) should return false");' +- text: 'checkEqual(1, 1) should return true' + testString: 'assert(checkEqual(1, 1) === true, "checkEqual(1, 1) should return true");' +- text: 'checkEqual(1, -1) should return false' + testString: 'assert(checkEqual(1, -1) === false, "checkEqual(1, -1) should return false");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +function checkEqual(a, b) { + +} + +checkEqual(1, 2); +``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Use the parseInt Function with a Radix.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Use the parseInt Function with a Radix.md new file mode 100644 index 0000000000..930690d43b --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Use the parseInt Function with a Radix.md @@ -0,0 +1,66 @@ +--- +id: 587d7b7e367417b2b2512b22 +title: Use the parseInt Function with a Radix +challengeType: 1 +--- + +## Description +
+The parseInt() function parses a string and returns an integer. It takes a second argument for the radix, which specifies the base of the number in the string. The radix can be an integer between 2 and 36. +The function call looks like: +parseInt(string, radix); +And here's an example: +var a = parseInt("11", 2); +The radix variable says that "11" is in the binary system, or base 2. This example converts the string "11" to an integer 3. +
+ +## Instructions +
+Use parseInt() in the convertToInteger function so it converts a binary number to an integer and returns it. +
+ +## Tests +
+ +```yml +- text: convertToInteger should use the parseInt() function + testString: 'assert(/parseInt/g.test(code), "convertToInteger should use the parseInt() function");' +- text: convertToInteger("10011") should return a number + testString: 'assert(typeof(convertToInteger("10011")) === "number", "convertToInteger("10011") should return a number");' +- text: convertToInteger("10011") should return 19 + testString: 'assert(convertToInteger("10011") === 19, "convertToInteger("10011") should return 19");' +- text: convertToInteger("111001") should return 57 + testString: 'assert(convertToInteger("111001") === 57, "convertToInteger("111001") should return 57");' +- text: convertToInteger("JamesBond") should return NaN + testString: 'assert.isNaN(convertToInteger("JamesBond"), "convertToInteger("JamesBond") should return NaN");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +function convertToInteger(str) { + +} + +convertToInteger("10011"); +``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Use the parseInt Function.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Use the parseInt Function.md new file mode 100644 index 0000000000..e9c3b7c5f4 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Use the parseInt Function.md @@ -0,0 +1,63 @@ +--- +id: 587d7b7e367417b2b2512b23 +title: Use the parseInt Function +challengeType: 1 +--- + +## Description +
+The parseInt() function parses a string and returns an integer. Here's an example: +var a = parseInt("007"); +The above function converts the string "007" to an integer 7. If the first character in the string can't be converted into a number, then it returns NaN. +
+ +## Instructions +
+Use parseInt() in the convertToInteger function so it converts the input string str into an integer, and returns it. +
+ +## Tests +
+ +```yml +- text: convertToInteger should use the parseInt() function + testString: 'assert(/parseInt/g.test(code), "convertToInteger should use the parseInt() function");' +- text: convertToInteger("56") should return a number + testString: 'assert(typeof(convertToInteger("56")) === "number", "convertToInteger("56") should return a number");' +- text: convertToInteger("56") should return 56 + testString: 'assert(convertToInteger("56") === 56, "convertToInteger("56") should return 56");' +- text: convertToInteger("77") should return 77 + testString: 'assert(convertToInteger("77") === 77, "convertToInteger("77") should return 77");' +- text: convertToInteger("JamesBond") should return NaN + testString: 'assert.isNaN(convertToInteger("JamesBond"), "convertToInteger("JamesBond") should return NaN");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +function convertToInteger(str) { + +} + +convertToInteger("56"); +``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Using Objects for Lookups.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Using Objects for Lookups.md new file mode 100644 index 0000000000..2ad50ace9d --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Using Objects for Lookups.md @@ -0,0 +1,114 @@ +--- +id: 56533eb9ac21ba0edf2244ca +title: Using Objects for Lookups +challengeType: 1 +--- + +## Description +
+Objects can be thought of as a key/value storage, like a dictionary. If you have tabular data, you can use an object to "lookup" values rather than a switch statement or an if/else chain. This is most useful when you know that your input data is limited to a certain range. +Here is an example of a simple reverse alphabet lookup: +
var alpha = {
  1:"Z",
  2:"Y",
  3:"X",
  4:"W",
  ...
  24:"C",
  25:"B",
  26:"A"
};
alpha[2]; // "Y"
alpha[24]; // "C"

var value = 2;
alpha[value]; // "Y"
+
+ +## Instructions +
+Convert the switch statement into an object called lookup. Use it to look up val and assign the associated string to the result variable. +
+ +## Tests +
+ +```yml +- text: phoneticLookup("alpha") should equal "Adams" + testString: 'assert(phoneticLookup("alpha") === "Adams", "phoneticLookup("alpha") should equal "Adams"");' +- text: phoneticLookup("bravo") should equal "Boston" + testString: 'assert(phoneticLookup("bravo") === "Boston", "phoneticLookup("bravo") should equal "Boston"");' +- text: phoneticLookup("charlie") should equal "Chicago" + testString: 'assert(phoneticLookup("charlie") === "Chicago", "phoneticLookup("charlie") should equal "Chicago"");' +- text: phoneticLookup("delta") should equal "Denver" + testString: 'assert(phoneticLookup("delta") === "Denver", "phoneticLookup("delta") should equal "Denver"");' +- text: phoneticLookup("echo") should equal "Easy" + testString: 'assert(phoneticLookup("echo") === "Easy", "phoneticLookup("echo") should equal "Easy"");' +- text: phoneticLookup("foxtrot") should equal "Frank" + testString: 'assert(phoneticLookup("foxtrot") === "Frank", "phoneticLookup("foxtrot") should equal "Frank"");' +- text: phoneticLookup("") should equal undefined + testString: 'assert(typeof phoneticLookup("") === "undefined", "phoneticLookup("") should equal undefined");' +- text: You should not modify the return statement + testString: 'assert(code.match(/return\sresult;/), "You should not modify the return statement");' +- text: 'You should not use case, switch, or if statements' + testString: 'assert(!/case|switch|if/g.test(code.replace(/([/]{2}.*)|([/][*][^/*]*[*][/])/g,"")), "You should not use case, switch, or if statements"); ' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +// Setup +function phoneticLookup(val) { + var result = ""; + + // Only change code below this line + switch(val) { + case "alpha": + result = "Adams"; + break; + case "bravo": + result = "Boston"; + break; + case "charlie": + result = "Chicago"; + break; + case "delta": + result = "Denver"; + break; + case "echo": + result = "Easy"; + break; + case "foxtrot": + result = "Frank"; + } + + // Only change code above this line + return result; +} + +// Change this value to test +phoneticLookup("charlie"); +``` + +
+ + + +
+ +## Solution +
+ + +```js +function phoneticLookup(val) { + var result = ""; + + var lookup = { + alpha: "Adams", + bravo: "Boston", + charlie: "Chicago", + delta: "Denver", + echo: "Easy", + foxtrot: "Frank" + }; + + result = lookup[val]; + + return result; +} +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Word Blanks.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Word Blanks.md new file mode 100644 index 0000000000..a91e46e902 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Word Blanks.md @@ -0,0 +1,84 @@ +--- +id: 56533eb9ac21ba0edf2244bb +title: Word Blanks +challengeType: 1 +--- + +## Description +
+We will now use our knowledge of strings to build a "Mad Libs" style word game we're calling "Word Blanks". You will create an (optionally humorous) "Fill in the Blanks" style sentence. +In a "Mad Libs" game, you are provided sentences with some missing words, like nouns, verbs, adjectives and adverbs. You then fill in the missing pieces with words of your choice in a way that the completed sentence makes sense. +Consider this sentence - "It was really ____, and we ____ ourselves ____". This sentence has three missing pieces- an adjective, a verb and an adverb, and we can add words of our choice to complete it. We can then assign the completed sentence to a variable as follows: +
var sentence = "It was really" + "hot" + ", and we" + "laughed" + "ourselves" + "silly.";
+
+ +## Instructions +
+In this challenge, we provide you with a noun, a verb, an adjective and an adverb. You need to form a complete sentence using words of your choice, along with the words we provide. +You will need to use the string concatenation operator + to build a new string, using the provided variables: myNoun, myAdjective, myVerb, and myAdverb. You will then assign the formed string to the result variable. +You will also need to account for spaces in your string, so that the final sentence has spaces between all the words. The result should be a complete sentence. +
+ +## Tests +
+ +```yml +- text: 'wordBlanks("","","","") should return a string.' + testString: 'assert(typeof wordBlanks("","","","") === "string", "wordBlanks("","","","") should return a string.");' +- text: 'wordBlanks("dog", "big", "ran", "quickly") should contain all of the passed in words separated by non-word characters (and any additional words in your madlib).' + testString: 'assert(/\bdog\b/.test(test1) && /\bbig\b/.test(test1) && /\bran\b/.test(test1) && /\bquickly\b/.test(test1),"wordBlanks("dog", "big", "ran", "quickly") should contain all of the passed in words separated by non-word characters (and any additional words in your madlib).");' +- text: 'wordBlanks("cat", "little", "hit", "slowly") should contain all of the passed in words separated by non-word characters (and any additional words in your madlib).' + testString: 'assert(/\bcat\b/.test(test2) && /\blittle\b/.test(test2) && /\bhit\b/.test(test2) && /\bslowly\b/.test(test2),"wordBlanks("cat", "little", "hit", "slowly") should contain all of the passed in words separated by non-word characters (and any additional words in your madlib).");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +function wordBlanks(myNoun, myAdjective, myVerb, myAdverb) { + // Your code below this line + var result = ""; + + // Your code above this line + return result; +} + +// Change the words here to test your function +wordBlanks("dog", "big", "ran", "quickly"); +``` + +
+ + +### After Test +
+ +```js +console.info('after the test'); +``` + +
+ +
+ +## Solution +
+ + +```js +function wordBlanks(myNoun, myAdjective, myVerb, myAdverb) { + var result = ""; + + result = "Once there was a " + myNoun + " which was very " + myAdjective + ". "; + result += "It " + myVerb + " " + myAdverb + " around the yard."; + + return result; +} +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Write Reusable JavaScript with Functions.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Write Reusable JavaScript with Functions.md new file mode 100644 index 0000000000..b2616076aa --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/Write Reusable JavaScript with Functions.md @@ -0,0 +1,106 @@ +--- +id: 56bbb991ad1ed5201cd392cf +title: Write Reusable JavaScript with Functions +challengeType: 1 +--- + +## Description +
+In JavaScript, we can divide up our code into reusable parts called functions. +Here's an example of a function: +
function functionName() {
  console.log("Hello World");
}
+You can call or invoke this function by using its name followed by parentheses, like this: +functionName(); +Each time the function is called it will print out the message "Hello World" on the dev console. All of the code between the curly braces will be executed every time the function is called. +
+ +## Instructions +
+
  1. Create a function called reusableFunction which prints "Hi World" to the dev console.
  2. Call the function.
+
+ +## Tests +
+ +```yml +- text: reusableFunction should be a function + testString: 'assert(typeof reusableFunction === "function", "reusableFunction should be a function");' +- text: reusableFunction should output "Hi World" to the dev console + testString: 'assert("Hi World" === logOutput, "reusableFunction should output "Hi World" to the dev console");' +- text: Call reusableFunction after you define it + testString: 'assert(/^\s*reusableFunction\(\)\s*;/m.test(code), "Call reusableFunction after you define it");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +// Example +function ourReusableFunction() { + console.log("Heyya, World"); +} + +ourReusableFunction(); + +// Only change code below this line + +``` + +
+ +### Before Test +
+ +```js +var logOutput = ""; +var originalConsole = console +function capture() { + var nativeLog = console.log; + console.log = function (message) { + if(message && message.trim) logOutput = message.trim(); + if(nativeLog.apply) { + nativeLog.apply(originalConsole, arguments); + } else { + var nativeMsg = Array.prototype.slice.apply(arguments).join(' '); + nativeLog(nativeMsg); + } + }; +} + +function uncapture() { + console.log = originalConsole.log; +} + +capture(); +``` + +
+ +### After Test +
+ +```js +console.info('after the test'); +``` + +
+ +
+ +## Solution +
+ + +```js +function reusableFunction() { + console.log("Hi World"); +} +reusableFunction(); +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/meta.json b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/meta.json new file mode 100644 index 0000000000..5faa6f0b4a --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/basic-javascript/meta.json @@ -0,0 +1,8 @@ +{ + "name": "Basic JavaScript", + "dashedName": "basic-javascript", + "order": 1, + "time": "10 hours", + "superBlock": "javascript-algorithms-and-data-structures", + "superOrder": 2 +} \ No newline at end of file diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/debugging/Catch Arguments Passed in the Wrong Order When Calling a Function.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/debugging/Catch Arguments Passed in the Wrong Order When Calling a Function.md new file mode 100644 index 0000000000..185789ceac --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/debugging/Catch Arguments Passed in the Wrong Order When Calling a Function.md @@ -0,0 +1,58 @@ +--- +id: 587d7b85367417b2b2512b3a +title: Catch Arguments Passed in the Wrong Order When Calling a Function +challengeType: 1 +--- + +## Description +
+Continuing the discussion on calling functions, the next bug to watch out for is when a function's arguments are supplied in the incorrect order. If the arguments are different types, such as a function expecting an array and an integer, this will likely throw a runtime error. If the arguments are the same type (all integers, for example), then the logic of the code won't make sense. Make sure to supply all required arguments, in the proper order to avoid these issues. +
+ +## Instructions +
+The function raiseToPower raises a base to an exponent. Unfortunately, it's not called properly - fix the code so the value of power is the expected 8. +
+ +## Tests +
+ +```yml +- text: 'Your code should fix the variable power so it equals 2 raised to the 3rd power, not 3 raised to the 2nd power.' + testString: 'assert(power == 8, "Your code should fix the variable power so it equals 2 raised to the 3rd power, not 3 raised to the 2nd power.");' +- text: Your code should use the correct order of the arguments for the raiseToPower function call. + testString: 'assert(code.match(/raiseToPower\(\s*?base\s*?,\s*?exp\s*?\);/g), "Your code should use the correct order of the arguments for the raiseToPower function call.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +function raiseToPower(b, e) { + return Math.pow(b, e); +} + +let base = 2; +let exp = 3; +let power = raiseToPower(exp, base); +console.log(power); +``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/debugging/Catch Missing Open and Closing Parenthesis After a Function Call.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/debugging/Catch Missing Open and Closing Parenthesis After a Function Call.md new file mode 100644 index 0000000000..0b01ad45cc --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/debugging/Catch Missing Open and Closing Parenthesis After a Function Call.md @@ -0,0 +1,60 @@ +--- +id: 587d7b85367417b2b2512b39 +title: Catch Missing Open and Closing Parenthesis After a Function Call +challengeType: 1 +--- + +## Description +
+When a function or method doesn't take any arguments, you may forget to include the (empty) opening and closing parentheses when calling it. Often times the result of a function call is saved in a variable for other use in your code. This error can be detected by logging variable values (or their types) to the console and seeing that one is set to a function reference, instead of the expected value the function returns. +The variables in the following example are different: +
function myFunction() {
  return "You rock!";
}
let varOne = myFunction; // set to equal a function
let varTwo = myFunction(); // set to equal the string "You rock!"
+
+ +## Instructions +
+Fix the code so the variable result is set to the value returned from calling the function getNine. +
+ +## Tests +
+ +```yml +- text: Your code should fix the variable result so it is set to the number that the function getNine returns. + testString: 'assert(result == 9, "Your code should fix the variable result so it is set to the number that the function getNine returns.");' +- text: Your code should call the getNine function. + testString: 'assert(code.match(/getNine\(\)/g).length == 2, "Your code should call the getNine function.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +function getNine() { + let x = 6; + let y = 3; + return x + y; +} + +let result = getNine; +console.log(result); +``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/debugging/Catch Misspelled Variable and Function Names.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/debugging/Catch Misspelled Variable and Function Names.md new file mode 100644 index 0000000000..cf62b09dc6 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/debugging/Catch Misspelled Variable and Function Names.md @@ -0,0 +1,61 @@ +--- +id: 587d7b84367417b2b2512b35 +title: Catch Misspelled Variable and Function Names +challengeType: 1 +--- + +## Description +
+The console.log() and typeof methods are the two primary ways to check intermediate values and types of program output. Now it's time to get into the common forms that bugs take. One syntax-level issue that fast typers can commiserate with is the humble spelling error. +Transposed, missing, or mis-capitalized characters in a variable or function name will have the browser looking for an object that doesn't exist - and complain in the form of a reference error. JavaScript variable and function names are case-sensitive. +
+ +## Instructions +
+Fix the two spelling errors in the code so the netWorkingCapital calculation works. +
+ +## Tests +
+ +```yml +- text: 'Check the spelling of the two variables used in the netWorkingCapital calculation, the console output should show that "Net working capital is: 2".' + testString: 'assert(netWorkingCapital === 2, "Check the spelling of the two variables used in the netWorkingCapital calculation, the console output should show that "Net working capital is: 2".");' +- text: There should be no instances of mis-spelled variables in the code. + testString: 'assert(!code.match(/recievables/g), "There should be no instances of mis-spelled variables in the code.");' +- text: The receivables variable should be declared and used properly in the code. + testString: 'assert(code.match(/receivables/g).length == 2, "The receivables variable should be declared and used properly in the code.");' +- text: There should be no instances of mis-spelled variables in the code. + testString: 'assert(!code.match(/payable;/g), "There should be no instances of mis-spelled variables in the code.");' +- text: The payables variable should be declared and used properly in the code. + testString: 'assert(code.match(/payables/g).length == 2, "The payables variable should be declared and used properly in the code.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +let receivables = 10; +let payables = 8; +let netWorkingCapital = recievables - payable; +console.log(`Net working capital is: ${netWorkingCapital}`); +``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/debugging/Catch Mixed Usage of Single and Double Quotes.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/debugging/Catch Mixed Usage of Single and Double Quotes.md new file mode 100644 index 0000000000..91d08660de --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/debugging/Catch Mixed Usage of Single and Double Quotes.md @@ -0,0 +1,57 @@ +--- +id: 587d7b84367417b2b2512b37 +title: Catch Mixed Usage of Single and Double Quotes +challengeType: 1 +--- + +## Description +
+JavaScript allows the use of both single (") and double ("") quotes to declare a string. Deciding which one to use generally comes down to personal preference, with some exceptions. +Having two choices is great when a string has contractions or another piece of text that's in quotes. Just be careful that you don't close the string too early, which causes a syntax error. +Here are some examples of mixing quotes: +
// These are correct:
const grouchoContraction = "I've had a perfectly wonderful evening, but this wasn't it.";
const quoteInString = "Groucho Marx once said 'Quote me as saying I was mis-quoted.'";
// This is incorrect:
const uhOhGroucho = 'I've had a perfectly wonderful evening, but this wasn't it.';
+Of course, it is okay to use only one style of quotes. You can escape the quotes inside the string by using the backslash (\) escape character: +
// Correct use of same quotes:
const allSameQuotes = 'I\'ve had a perfectly wonderful evening, but this wasn\'t it.';
+
+ +## Instructions +
+Fix the string so it either uses different quotes for the href value, or escape the existing ones. Keep the double quote marks around the entire string. +
+ +## Tests +
+ +```yml +- text: 'Your code should fix the quotes around the href value "#Home" by either changing or escaping them.' + testString: 'assert(code.match(//g), "Your code should fix the quotes around the href value "#Home" by either changing or escaping them.");' +- text: Your code should keep the double quotes around the entire string. + testString: 'assert(code.match(/"

.*?<\/p>";/g), "Your code should keep the double quotes around the entire string.");' + +``` + +

+ +## Challenge Seed +
+ +
+ +```js +let innerHtml = "

Click here to return home

"; +console.log(innerHtml); +``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/debugging/Catch Off By One Errors When Using Indexing.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/debugging/Catch Off By One Errors When Using Indexing.md new file mode 100644 index 0000000000..248ffcad05 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/debugging/Catch Off By One Errors When Using Indexing.md @@ -0,0 +1,67 @@ +--- +id: 587d7b86367417b2b2512b3b +title: Catch Off By One Errors When Using Indexing +challengeType: 1 +--- + +## Description +
+Off by one errors (sometimes called OBOE) crop up when you're trying to target a specific index of a string or array (to slice or access a segment), or when looping over the indices of them. JavaScript indexing starts at zero, not one, which means the last index is always one less than the length of the item. If you try to access an index equal to the length, the program may throw an "index out of range" reference error or print undefined. +When you use string or array methods that take index ranges as arguments, it helps to read the documentation and understand if they are inclusive (the item at the given index is part of what's returned) or not. Here are some examples of off by one errors: +
let alphabet = "abcdefghijklmnopqrstuvwxyz";
let len = alphabet.length;
for (let i = 0; i <= len; i++) {
  // loops one too many times at the end
  console.log(alphabet[i]);
}
for (let j = 1; j < len; j++) {
  // loops one too few times and misses the first character at index 0
  console.log(alphabet[j]);
}
for (let k = 0; k < len; k++) {
  // Goldilocks approves - this is just right
  console.log(alphabet[k]);
}
+
+ +## Instructions +
+Fix the two indexing errors in the following function so all the numbers 1 through 5 are printed to the console. +
+ +## Tests +
+ +```yml +- text: Your code should set the initial condition of the loop so it starts at the first index. + testString: 'assert(code.match(/i\s*?=\s*?0\s*?;/g).length == 1, "Your code should set the initial condition of the loop so it starts at the first index.");' +- text: Your code should fix the initial condition of the loop so that the index starts at 0. + testString: 'assert(!code.match(/i\s?=\s*?1\s*?;/g), "Your code should fix the initial condition of the loop so that the index starts at 0.");' +- text: Your code should set the terminal condition of the loop so it stops at the last index. + testString: 'assert(code.match(/i\s*?<\s*?len\s*?;/g).length == 1, "Your code should set the terminal condition of the loop so it stops at the last index.");' +- text: Your code should fix the terminal condition of the loop so that it stops at 1 before the length. + testString: 'assert(!code.match(/i\s*?<=\s*?len;/g), "Your code should fix the terminal condition of the loop so that it stops at 1 before the length.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +function countToFive() { + let firstFive = "12345"; + let len = firstFive.length; + // Fix the line below + for (let i = 1; i <= len; i++) { + // Do not alter code below this line + console.log(firstFive[i]); + } +} + +countToFive(); +``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/debugging/Catch Unclosed Parentheses, Brackets, Braces and Quotes.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/debugging/Catch Unclosed Parentheses, Brackets, Braces and Quotes.md new file mode 100644 index 0000000000..b4cef16998 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/debugging/Catch Unclosed Parentheses, Brackets, Braces and Quotes.md @@ -0,0 +1,54 @@ +--- +id: 587d7b84367417b2b2512b36 +title: 'Catch Unclosed Parentheses, Brackets, Braces and Quotes' +challengeType: 1 +--- + +## Description +
+Another syntax error to be aware of is that all opening parentheses, brackets, curly braces, and quotes have a closing pair. Forgetting a piece tends to happen when you're editing existing code and inserting items with one of the pair types. Also, take care when nesting code blocks into others, such as adding a callback function as an argument to a method. +One way to avoid this mistake is as soon as the opening character is typed, immediately include the closing match, then move the cursor back between them and continue coding. Fortunately, most modern code editors generate the second half of the pair automatically. +
+ +## Instructions +
+Fix the two pair errors in the code. +
+ +## Tests +
+ +```yml +- text: Your code should fix the missing piece of the array. + testString: 'assert(code.match(/myArray\s*?=\s*?\[\s*?1\s*?,\s*?2\s*?,\s*?3\s*?\];/g), "Your code should fix the missing piece of the array.");' +- text: 'Your code should fix the missing piece of the .reduce() method. The console output should show that "Sum of array values is: 6".' + testString: 'assert(arraySum === 6, "Your code should fix the missing piece of the .reduce() method. The console output should show that "Sum of array values is: 6".");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +let myArray = [1, 2, 3; +let arraySum = myArray.reduce((previous, current => previous + current); +console.log(`Sum of array values is: ${arraySum}`); +``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/debugging/Catch Use of Assignment Operator Instead of Equality Operator.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/debugging/Catch Use of Assignment Operator Instead of Equality Operator.md new file mode 100644 index 0000000000..e9ee94ca35 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/debugging/Catch Use of Assignment Operator Instead of Equality Operator.md @@ -0,0 +1,65 @@ +--- +id: 587d7b85367417b2b2512b38 +title: Catch Use of Assignment Operator Instead of Equality Operator +challengeType: 1 +--- + +## Description +
+Branching programs, i.e. ones that do different things if certain conditions are met, rely on if, else if, and else statements in JavaScript. The condition sometimes takes the form of testing whether a result is equal to a value. +This logic is spoken (in English, at least) as "if x equals y, then ..." which can literally translate into code using the =, or assignment operator. This leads to unexpected control flow in your program. +As covered in previous challenges, the assignment operator (=) in JavaScript assigns a value to a variable name. And the == and === operators check for equality (the triple === tests for strict equality, meaning both value and type are the same). +The code below assigns x to be 2, which evaluates as true. Almost every value on its own in JavaScript evaluates to true, except what are known as the "falsy" values: false, 0, "" (an empty string), NaN, undefined, and null. +
let x = 1;
let y = 2;
if (x = y) {
  // this code block will run for any value of y (unless y were originally set as a falsy)
} else {
  // this code block is what should run (but won't) in this example
}
+
+ +## Instructions +
+Fix the condition so the program runs the right branch, and the appropriate value is assigned to result. +
+ +## Tests +
+ +```yml +- text: 'Your code should fix the condition so it checks for equality, instead of using assignment.' + testString: 'assert(result == "Not equal!", "Your code should fix the condition so it checks for equality, instead of using assignment.");' +- text: The condition can use either == or === to test for equality. + testString: 'assert(code.match(/x\s*?===?\s*?y/g), "The condition can use either == or === to test for equality.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +let x = 7; +let y = 9; +let result = "to come"; + +if(x = y) { + result = "Equal!"; +} else { + result = "Not equal!"; +} + +console.log(result); +``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/debugging/Prevent Infinite Loops with a Valid Terminal Condition.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/debugging/Prevent Infinite Loops with a Valid Terminal Condition.md new file mode 100644 index 0000000000..d8a7c04eb4 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/debugging/Prevent Infinite Loops with a Valid Terminal Condition.md @@ -0,0 +1,58 @@ +--- +id: 587d7b86367417b2b2512b3d +title: Prevent Infinite Loops with a Valid Terminal Condition +challengeType: 1 +--- + +## Description +
+The final topic is the dreaded infinite loop. Loops are great tools when you need your program to run a code block a certain number of times or until a condition is met, but they need a terminal condition that ends the looping. Infinite loops are likely to freeze or crash the browser, and cause general program execution mayhem, which no one wants. +There was an example of an infinite loop in the introduction to this section - it had no terminal condition to break out of the while loop inside loopy(). Do NOT call this function! +
function loopy() {
  while(true) {
    console.log("Hello, world!");
  }
}
+It's the programmer's job to ensure that the terminal condition, which tells the program when to break out of the loop code, is eventually reached. One error is incrementing or decrementing a counter variable in the wrong direction from the terminal condition. Another one is accidentally resetting a counter or index variable within the loop code, instead of incrementing or decrementing it. +
+ +## Instructions +
+The myFunc() function contains an infinite loop because the terminal condition i != 4 will never evaluate to false (and break the looping) - i will increment by 2 each pass, and jump right over 4 since i is odd to start. Fix the comparison operator in the terminal condition so the loop only runs for i less than or equal to 4. +
+ +## Tests +
+ +```yml +- text: Your code should change the comparison operator in the terminal condition (the middle part) of the for loop. + testString: 'assert(code.match(/i\s*?<=\s*?4;/g).length == 1, "Your code should change the comparison operator in the terminal condition (the middle part) of the for loop.");' +- text: Your code should fix the comparison operator in the terminal condition of the loop. + testString: 'assert(!code.match(/i\s*?!=\s*?4;/g), "Your code should fix the comparison operator in the terminal condition of the loop.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +function myFunc() { + for (let i = 1; i != 4; i += 2) { + console.log("Still going!"); + } +} +``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/debugging/Understanding the Differences between the freeCodeCamp and Browser Console.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/debugging/Understanding the Differences between the freeCodeCamp and Browser Console.md new file mode 100644 index 0000000000..68c90e5e18 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/debugging/Understanding the Differences between the freeCodeCamp and Browser Console.md @@ -0,0 +1,74 @@ +--- +id: 587d7b83367417b2b2512b37 +title: Understanding the Differences between the freeCodeCamp and Browser Console +challengeType: 1 +--- + +## Description +
+You may have noticed that some freeCodeCamp JavaScript challenges include their own console. This console behaves a little differently than the browser console you used in the last challenge. +The following challenge is meant to highlight some of the differences between the freeCodeCamp console and the browser console. +First, the browser console. When you load and run an ordinary JavaScript file in your browser the console.log() statements will print exactly what you tell them to print to the browser console the exact number of times you requested. In your in-browser text editor the process is slightly different and can be confusing at first. +Values passed to console.log() in the text editor block run each set of tests as well as one more time for any function calls that you have in your code. +This lends itself to some interesting behavior and might trip you up in the beginning, because a logged value that you expect to see only once may print out many more times depending on the number of tests and the values being passed to those tests. +If you would like to see only your single output and not have to worry about running through the test cycles, you can use console.clear(). +
+ +## Instructions +
+Use console.log() to print the variables in the code where indicated. + +
+ +## Tests +
+ +```yml +- text: Use console.log() to print the outputTwo variable. In your Browser Console this should print out the value of the variable two times. + testString: 'assert(code.match(/console\.log\(outputTwo\)/g), "Use console.log() to print the outputTwo variable. In your Browser Console this should print out the value of the variable two times.");' +- text: Use console.log() to print the outputOne variable. + testString: 'assert(code.match(/console\.log\(outputOne\)/g), "Use console.log() to print the outputOne variable.");' +- text: Use console.clear() to modify your output so that outputOne variable only outputs once. + testString: 'assert(code.match(/^(\s*console.clear\(\);?\s*)$/gm), "Use console.clear() to modify your output so that outputOne variable only outputs once.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +// Open your browser console +let outputTwo = "This will print to the browser console 2 times"; +// Use console.log() to print the outputTwo variable + + +let outputOne = "Try to get this to log only once to the browser console"; +// Use console.clear() in the next line to print the outputOne only once + + +// Use console.log() to print the outputOne variable + + +``` + +
+ + + +
+ +## Solution +
+ + +```js +let outputTwo = "This will print to the browser console 2 times"; console.log(outputTwo); let outputOne = "Try to get this to log only once to the browser console"; +console.clear(); +console.log(outputOne); +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/debugging/Use Caution When Reinitializing Variables Inside a Loop.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/debugging/Use Caution When Reinitializing Variables Inside a Loop.md new file mode 100644 index 0000000000..de9e016e8e --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/debugging/Use Caution When Reinitializing Variables Inside a Loop.md @@ -0,0 +1,72 @@ +--- +id: 587d7b86367417b2b2512b3c +title: Use Caution When Reinitializing Variables Inside a Loop +challengeType: 1 +--- + +## Description +
+Sometimes it's necessary to save information, increment counters, or re-set variables within a loop. A potential issue is when variables either should be reinitialized, and aren't, or vice versa. This is particularly dangerous if you accidentally reset the variable being used for the terminal condition, causing an infinite loop. +Printing variable values with each cycle of your loop by using console.log() can uncover buggy behavior related to resetting, or failing to reset a variable. +
+ +## Instructions +
+The following function is supposed to create a two-dimensional array with m rows and n columns of zeroes. Unfortunately, it's not producing the expected output because the row variable isn't being reinitialized (set back to an empty array) in the outer loop. Fix the code so it returns a correct 3x2 array of zeroes, which looks like [[0, 0], [0, 0], [0, 0]]. +
+ +## Tests +
+ +```yml +- text: Your code should set the matrix variable to an array holding 3 rows of 2 columns of zeroes each. + testString: 'assert(JSON.stringify(matrix) == "[[0,0],[0,0],[0,0]]", "Your code should set the matrix variable to an array holding 3 rows of 2 columns of zeroes each.");' +- text: The matrix variable should have 3 rows. + testString: 'assert(matrix.length == 3, "The matrix variable should have 3 rows.");' +- text: The matrix variable should have 2 columns in each row. + testString: 'assert(matrix[0].length == 2 && matrix[1].length === 2 && matrix[2].length === 2, "The matrix variable should have 2 columns in each row.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +function zeroArray(m, n) { + // Creates a 2-D array with m rows and n columns of zeroes + let newArray = []; + let row = []; + for (let i = 0; i < m; i++) { + // Adds the m-th row into newArray + + for (let j = 0; j < n; j++) { + // Pushes n zeroes into the current row to create the columns + row.push(0); + } + // Pushes the current row, which now has n zeroes in it, to the array + newArray.push(row); + } + return newArray; +} + +let matrix = zeroArray(3, 2); +console.log(matrix); +``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/debugging/Use the JavaScript Console to Check the Value of a Variable.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/debugging/Use the JavaScript Console to Check the Value of a Variable.md new file mode 100644 index 0000000000..0ad87c6ad2 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/debugging/Use the JavaScript Console to Check the Value of a Variable.md @@ -0,0 +1,62 @@ +--- +id: 587d7b83367417b2b2512b33 +title: Use the JavaScript Console to Check the Value of a Variable +challengeType: 1 +--- + +## Description +
+Both Chrome and Firefox have excellent JavaScript consoles, also known as DevTools, for debugging your JavaScript. +You can find Developer tools in your Chrome's menu or Web Console in FireFox's menu. If you're using a different browser, or a mobile phone, we strongly recommend switching to desktop Firefox or Chrome. +The console.log() method, which "prints" the output of what's within its parentheses to the console, will likely be the most helpful debugging tool. Placing it at strategic points in your code can show you the intermediate values of variables. It's good practice to have an idea of what the output should be before looking at what it is. Having check points to see the status of your calculations throughout your code will help narrow down where the problem is. +Here's an example to print 'Hello world!' to the console: +console.log('Hello world!'); +
+ +## Instructions +
+Use the console.log() method to print the value of the variable a where noted in the code. +
+ +## Tests +
+ +```yml +- text: Your code should use console.log() to check the value of the variable a. + testString: 'assert(code.match(/console\.log\(a\)/g), "Your code should use console.log() to check the value of the variable a.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +let a = 5; +let b = 1; +a++; +// Add your code below this line + + +let sumAB = a + b; +console.log(sumAB); +``` + +
+ + + +
+ +## Solution +
+ + +```js +var a = 5; console.log(a); +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/debugging/Use typeof to Check the Type of a Variable.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/debugging/Use typeof to Check the Type of a Variable.md new file mode 100644 index 0000000000..12df1bcf3a --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/debugging/Use typeof to Check the Type of a Variable.md @@ -0,0 +1,63 @@ +--- +id: 587d7b84367417b2b2512b34 +title: Use typeof to Check the Type of a Variable +challengeType: 1 +--- + +## Description +
+You can use typeof to check the data structure, or type, of a variable. This is useful in debugging when working with multiple data types. If you think you're adding two numbers, but one is actually a string, the results can be unexpected. Type errors can lurk in calculations or function calls. Be careful especially when you're accessing and working with external data in the form of a JavaScript Object Notation (JSON) object. +Here are some examples using typeof: +
console.log(typeof ""); // outputs "string"
console.log(typeof 0); // outputs "number"
console.log(typeof []); // outputs "object"
console.log(typeof {}); // outputs "object"
+JavaScript recognizes six primitive (immutable) data types: Boolean, Null, Undefined, Number, String, and Symbol (new with ES6) and one type for mutable items: Object. Note that in JavaScript, arrays are technically a type of object. +
+ +## Instructions +
+Add two console.log() statements to check the typeof each of the two variables seven and three in the code. +
+ +## Tests +
+ +```yml +- text: Your code should use typeof in two console.log() statements to check the type of the variables. + testString: 'assert(code.match(/console\.log\(typeof[\( ].*\)?\)/g).length == 2, "Your code should use typeof in two console.log() statements to check the type of the variables.");' +- text: Your code should use typeof to check the type of the variable seven. + testString: 'assert(code.match(/typeof[\( ]seven\)?/g), "Your code should use typeof to check the type of the variable seven.");' +- text: Your code should use typeof to check the type of the variable three. + testString: 'assert(code.match(/typeof[\( ]three\)?/g), "Your code should use typeof to check the type of the variable three.");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +let seven = 7; +let three = "3"; +console.log(seven + three); +// Add your code below this line + +``` + +
+ + + +
+ +## Solution +
+ + +```js +let seven = 7;let three = "3";console.log(typeof seven); +console.log(typeof three); +``` + +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/debugging/meta.json b/curriculum/challenges/02-javascript-algorithms-and-data-structures/debugging/meta.json new file mode 100644 index 0000000000..42d1e7551c --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/debugging/meta.json @@ -0,0 +1,8 @@ +{ + "name": "Debugging", + "dashedName": "debugging", + "order": 4, + "time": "1 hour", + "superBlock": "javascript-algorithms-and-data-structures", + "superOrder": 2 +} \ No newline at end of file diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/es6/Compare Scopes of the var and let Keywords.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/es6/Compare Scopes of the var and let Keywords.md new file mode 100644 index 0000000000..72be8c9f6e --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/es6/Compare Scopes of the var and let Keywords.md @@ -0,0 +1,73 @@ +--- +id: 587d7b87367417b2b2512b40 +title: Compare Scopes of the var and let Keywords +challengeType: 1 +--- + +## Description +
+When you declare a variable with the var keyword, it is declared globally, or locally if declared inside a function. +The let keyword behaves similarly, but with some extra features. When you declare a variable with the let keyword inside a block, statement, or expression, its scope is limited to that block, statement, or expression. +For example: +
var numArray = [];
for (var i = 0; i < 3; i++) {
  numArray.push(i);
}
console.log(numArray);
// returns [0, 1, 2]
console.log(i);
// returns 3
+With the var keyword, i is declared globally. So when i++ is executed, it updates the global variable. This code is similar to the following: +
var numArray = [];
var i;
for (i = 0; i < 3; i++) {
  numArray.push(i);
}
console.log(numArray);
// returns [0, 1, 2]
console.log(i);
// returns 3
+This behavior will cause problems if you were to create a function and store it for later use inside a for loop that uses the i variable. This is because the stored function will always refer to the value of the updated global i variable. +
var printNumTwo;
for (var i = 0; i < 3; i++) {
  if(i === 2){
    printNumTwo = function() {
      return i;
    };
  }
}
console.log(printNumTwo());
// returns 3
+As you can see, printNumTwo() prints 3 and not 2. This is because the value assigned to i was updated and the printNumTwo() returns the global i and not the value i had when the function was created in the for loop. The let keyword does not follow this behavior: +
'use strict';
let printNumTwo;
for (let i = 0; i < 3; i++) {
  if (i === 2) {
    printNumTwo = function() {
      return i;
    };
  }
}
console.log(printNumTwo());
// returns 2
console.log(i);
// returns "i is not defined"
+i is not defined because it was not declared in the global scope. It is only declared within the for loop statement. printNumTwo() returned the correct value because three different i variables with unique values (0, 1, and 2) were created by the let keyword within the loop statement. +
+ +## Instructions +
+Fix the code so that i declared in the if statement is a separate variable than i declared in the first line of the function. Be certain not to use the var keyword anywhere in your code. +This exercise is designed to illustrate the difference between how var and let keywords assign scope to the declared variable. When programming a function similar to the one used in this exercise, it is often better to use different variable names to avoid confusion. +
+ +## Tests +
+ +```yml +- text: var does not exist in code. + testString: 'getUserInput => assert(!getUserInput("index").match(/var/g),"var does not exist in code.");' +- text: The variable i declared in the if statement should equal "block scope". + testString: 'getUserInput => assert(getUserInput("index").match(/(i\s*=\s*).*\s*.*\s*.*\1("|")block\s*scope\2/g), "The variable i declared in the if statement should equal "block scope".");' +- text: checkScope() should return "function scope" + testString: 'assert(checkScope() === "function scope", "checkScope() should return "function scope"");' + +``` + +
+ +## Challenge Seed +
+ +
+ +```js +function checkScope() { +"use strict"; + var i = "function scope"; + if (true) { + i = "block scope"; + console.log("Block scope i is: ", i); + } + console.log("Function scope i is: ", i); + return i; +} +``` + +
+ + + +
+ +## Solution +
+ +```js +// solution required +``` +
diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/es6/Create Strings using Template Literals.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/es6/Create Strings using Template Literals.md new file mode 100644 index 0000000000..269e56a3f7 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/es6/Create Strings using Template Literals.md @@ -0,0 +1,81 @@ +--- +id: 587d7b8a367417b2b2512b4e +title: Create Strings using Template Literals +challengeType: 1 +--- + +## Description +
+A new feature of ES6 is the template literal. This is a special type of string that makes creating complex strings easier. +Template literals allow you to create multi-line strings and to use string interpolation features to create strings. +Consider the code below: +
const person = {
  name: "Zodiac Hasbro",
  age: 56
};

// Template literal with multi-line and string interpolation
const greeting = `Hello, my name is ${person.name}!
I am ${person.age} years old.`;

console.log(greeting); // prints
// Hello, my name is Zodiac Hasbro!
// I am 56 years old.
+A lot of things happened there. +Firstly, the example uses backticks (`), not quotes (' or "), to wrap the string. +Secondly, notice that the string is multi-line, both in the code and the output. This saves inserting \n within strings. +The ${variable} syntax used above is a placeholder. Basically, you won't have to use concatenation with the + operator anymore. To add variables to strings, you just drop the variable in a template string and wrap it with ${ and }. Similarly, you can include other expressions in your string literal, for example ${a + b}. +This new way of creating strings gives you more flexibility to create robust strings. +
+ +## Instructions +
+Use template literal syntax with backticks to display each entry of the result object's failure array. Each entry should be wrapped inside an li element with the class attribute text-warning, and listed within the resultDisplayArray. +
+ +## Tests +
+ +```yml +- text: resultDisplayArray is an array containing result failure messages. + testString: 'assert(typeof makeList(result.failure) === "object" && resultDisplayArray.length === 3, "resultDisplayArray is a list containing result failure messages.");' +- text: resultDisplayArray is the desired output. + testString: 'assert(makeList(result.failure).every((v, i) => v === `
  • ${result.failure[i]}
  • ` || v === `
  • ${result.failure[i]}
  • `), "resultDisplayArray is the desired output.");' +- text: Template strings were used + testString: 'getUserInput => assert(getUserInput("index").match(/`.*`/g), "Template strings were not used");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +const result = { + success: ["max-length", "no-amd", "prefer-arrow-functions"], + failure: ["no-var", "var-on-top", "linebreak"], + skipped: ["id-blacklist", "no-dup-keys"] +}; +function makeList(arr) { + "use strict"; + + // change code below this line + const resultDisplayArray = null; + // change code above this line + + return resultDisplayArray; +} +/** + * makeList(result.failure) should return: + * [ `
  • no-var
  • `, + * `
  • var-on-top
  • `, + * `
  • linebreak
  • ` ] + **/ +const resultDisplayArray = makeList(result.failure); +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/es6/Create an Export Fallback with export default.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/es6/Create an Export Fallback with export default.md new file mode 100644 index 0000000000..8956142e45 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/es6/Create an Export Fallback with export default.md @@ -0,0 +1,62 @@ +--- +id: 587d7b8c367417b2b2512b58 +title: Create an Export Fallback with export default +challengeType: 1 +--- + +## Description +
    +In the export lesson, you learned about the syntax referred to as a named export. This allowed you to make multiple functions and variables available for use in other files. +There is another export syntax you need to know, known as export default. Usually you will use this syntax if only one value is being exported from a file. It is also used to create a fallback value for a file or module. +Here is a quick example of export default: +
    export default function add(x,y) {
      return x + y;
    }
    +Note: Since export default is used to declare a fallback value for a module or file, you can only have one value be a default export in each module or file. Additionally, you cannot use export default with var, let, or const +
    + +## Instructions +
    +The following function should be the fallback value for the module. Please add the necessary code to do so. +
    + +## Tests +
    + +```yml +- text: Proper used of export fallback. + testString: 'getUserInput => assert(getUserInput("index").match(/export\s+default\s+function\s+subtract\(x,y\)\s+{return\s+x\s-\s+y;}/g), "Proper used of export fallback.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +"use strict"; +function subtract(x,y) {return x - y;} +``` + +
    + +### Before Test +
    + +```js +window.exports = function(){}; +``` + +
    + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/es6/Declare a Read-Only Variable with the const Keyword.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/es6/Declare a Read-Only Variable with the const Keyword.md new file mode 100644 index 0000000000..c8f0f89206 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/es6/Declare a Read-Only Variable with the const Keyword.md @@ -0,0 +1,71 @@ +--- +id: 587d7b87367417b2b2512b41 +title: Declare a Read-Only Variable with the const Keyword +challengeType: 1 +--- + +## Description +
    +let is not the only new way to declare variables. In ES6, you can also declare variables using the const keyword. +const has all the awesome features that let has, with the added bonus that variables declared using const are read-only. They are a constant value, which means that once a variable is assigned with const, it cannot be reassigned. +
    "use strict"
    const FAV_PET = "Cats";
    FAV_PET = "Dogs"; // returns error
    +As you can see, trying to reassign a variable declared with const will throw an error. You should always name variables you don't want to reassign using the const keyword. This helps when you accidentally attempt to reassign a variable that is meant to stay constant. A common practice when naming constants is to use all uppercase letters, with words separated by an underscore. +
    + +## Instructions +
    +Change the code so that all variables are declared using let or const. Use let when you want the variable to change, and const when you want the variable to remain constant. Also, rename variables declared with const to conform to common practices, meaning constants should be in all caps. +
    + +## Tests +
    + +```yml +- text: var does not exist in your code. + testString: 'getUserInput => assert(!getUserInput("index").match(/var/g),"var does not exist in your code.");' +- text: SENTENCE should be a constant variable declared with const. + testString: 'getUserInput => assert(getUserInput("index").match(/(const SENTENCE)/g), "SENTENCE should be a constant variable declared with const.");' +- text: i should be declared with let. + testString: 'getUserInput => assert(getUserInput("index").match(/(let i)/g), "i should be declared with let.");' +- text: console.log should be changed to print the SENTENCE variable. + testString: 'getUserInput => assert(getUserInput("index").match(/console\.log\(\s*SENTENCE\s*\)\s*;?/g), "console.log should be adjusted to print the variable SENTENCE.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +function printManyTimes(str) { + "use strict"; + + // change code below this line + + var sentence = str + " is cool!"; + for(var i = 0; i < str.length; i+=2) { + console.log(sentence); + } + + // change code above this line + +} +printManyTimes("freeCodeCamp"); +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/es6/Explore Differences Between the var and let Keywords.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/es6/Explore Differences Between the var and let Keywords.md new file mode 100644 index 0000000000..7c7584792d --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/es6/Explore Differences Between the var and let Keywords.md @@ -0,0 +1,73 @@ +--- +id: 587d7b87367417b2b2512b3f +title: Explore Differences Between the var and let Keywords +challengeType: 1 +--- + +## Description +
    +One of the biggest problems with declaring variables with the var keyword is that you can overwrite variable declarations without an error. +
    var camper = 'James';
    var camper = 'David';
    console.log(camper);
    // logs 'David'
    +As you can see in the code above, the camper variable is originally declared as James and then overridden to be David. +In a small application, you might not run into this type of problem, but when your code becomes larger, you might accidentally overwrite a variable that you did not intend to overwrite. +Because this behavior does not throw an error, searching and fixing bugs becomes more difficult.
    +A new keyword called let was introduced in ES6 to solve this potential issue with the var keyword. +If you were to replace var with let in the variable declarations of the code above, the result would be an error. +
    let camper = 'James';
    let camper = 'David'; // throws an error
    +This error can be seen in the console of your browser. +So unlike var, when using let, a variable with the same name can only be declared once. +Note the "use strict". This enables Strict Mode, which catches common coding mistakes and "unsafe" actions. For instance: +
    "use strict";
    x = 3.14; // throws an error because x is not declared
    +
    + +## Instructions +
    +Update the code so it only uses the let keyword. +
    + +## Tests +
    + +```yml +- text: var does not exist in code. + testString: 'getUserInput => assert(!getUserInput("index").match(/var/g),"var does not exist in code.");' +- text: catName should be Oliver. + testString: 'assert(catName === "Oliver", "catName should be Oliver.");' +- text: quote should be "Oliver says Meow!" + testString: 'assert(quote === "Oliver says Meow!", "quote should be "Oliver says Meow!"");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +var catName; +var quote; +function catTalk() { + "use strict"; + + catName = "Oliver"; + quote = catName + " says Meow!"; + +} +catTalk(); +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/es6/Import a Default Export.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/es6/Import a Default Export.md new file mode 100644 index 0000000000..14ab8f37e7 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/es6/Import a Default Export.md @@ -0,0 +1,65 @@ +--- +id: 587d7b8d367417b2b2512b59 +title: Import a Default Export +challengeType: 1 +--- + +## Description +
    +In the last challenge, you learned about export default and its uses. It is important to note that, to import a default export, you need to use a different import syntax. +In the following example, we have a function, add, that is the default export of a file, "math_functions". Here is how to import it: +
    import add from "math_functions";
    add(5,4); //Will return 9
    +The syntax differs in one key place - the imported value, add, is not surrounded by curly braces, {}. Unlike exported values, the primary method of importing a default export is to simply write the value's name after import. +
    + +## Instructions +
    +In the following code, please import the default export, subtract, from the file "math_functions", found in the same directory as this file. +
    + +## Tests +
    + +```yml +- text: Properly imports export default method. + testString: 'getUserInput => assert(getUserInput("index").match(/import\s+subtract\s+from\s+"math_functions"/g), "Properly imports export default method.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +"use strict"; +subtract(7,4); +``` + +
    + +### Before Test +
    + +```js +window.require = function(str) { +if (str === 'math_functions') { +return function(a, b) { +return a - b; +}}}; +``` + +
    + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/es6/Mutate an Array Declared with const.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/es6/Mutate an Array Declared with const.md new file mode 100644 index 0000000000..b89b98c45d --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/es6/Mutate an Array Declared with const.md @@ -0,0 +1,68 @@ +--- +id: 587d7b87367417b2b2512b42 +title: Mutate an Array Declared with const +challengeType: 1 +--- + +## Description +
    +The const declaration has many use cases in modern JavaScript. +Some developers prefer to assign all their variables using const by default, unless they know they will need to reassign the value. Only in that case, they use let. +However, it is important to understand that objects (including arrays and functions) assigned to a variable using const are still mutable. Using the const declaration only prevents reassignment of the variable identifier. +
    "use strict";
    const s = [5, 6, 7];
    s = [1, 2, 3]; // throws error, trying to assign a const
    s[2] = 45; // works just as it would with an array declared with var or let
    console.log(s); // returns [5, 6, 45]
    +As you can see, you can mutate the object [5, 6, 7] itself and the variable s will still point to the altered array [5, 6, 45]. Like all arrays, the array elements in s are mutable, but because const was used, you cannot use the variable identifier s to point to a different array using the assignment operator. +
    + +## Instructions +
    +An array is declared as const s = [5, 7, 2]. Change the array to [2, 5, 7] using various element assignment. +
    + +## Tests +
    + +```yml +- text: Do not replace const keyword. + testString: 'getUserInput => assert(getUserInput("index").match(/const/g), "Do not replace const keyword.");' +- text: s should be a constant variable (by using const). + testString: 'getUserInput => assert(getUserInput("index").match(/const\s+s/g), "s should be a constant variable (by using const).");' +- text: Do not change the original array declaration. + testString: 'getUserInput => assert(getUserInput("index").match(/const\s+s\s*=\s*\[\s*5\s*,\s*7\s*,\s*2\s*\]\s*;?/g), "Do not change the original array declaration.");' +- text: 's should be equal to [2, 5, 7].' + testString: 'assert.deepEqual(s, [2, 5, 7], "s should be equal to [2, 5, 7].");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +const s = [5, 7, 2]; +function editInPlace() { + "use strict"; + // change code below this line + + // s = [2, 5, 7]; <- this is invalid + + // change code above this line +} +editInPlace(); +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/es6/Prevent Object Mutation.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/es6/Prevent Object Mutation.md new file mode 100644 index 0000000000..e2fa5c7079 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/es6/Prevent Object Mutation.md @@ -0,0 +1,73 @@ +--- +id: 598f48a36c8c40764b4e52b3 +title: Prevent Object Mutation +challengeType: 1 +--- + +## Description +
    +As seen in the previous challenge, const declaration alone doesn't really protect your data from mutation. To ensure your data doesn't change, JavaScript provides a function Object.freeze to prevent data mutation. +Once the object is frozen, you can no longer add, update, or delete properties from it. Any attempt at changing the object will be rejected without an error. +
    let obj = {
      name:"FreeCodeCamp",
      review:"Awesome"
    };
    Object.freeze(obj);
    obj.review = "bad"; //will be ignored. Mutation not allowed
    obj.newProp = "Test"; // will be ignored. Mutation not allowed
    console.log(obj);
    // { name: "FreeCodeCamp", review:"Awesome"}
    +
    + +## Instructions +
    +In this challenge you are going to use Object.freeze to prevent mathematical constants from changing. You need to freeze the MATH_CONSTANTS object so that no one is able alter the value of PI, add, or delete properties . +
    + +## Tests +
    + +```yml +- text: Do not replace const keyword. + testString: 'getUserInput => assert(getUserInput("index").match(/const/g), "Do not replace const keyword.");' +- text: MATH_CONSTANTS should be a constant variable (by using const). + testString: 'getUserInput => assert(getUserInput("index").match(/const\s+MATH_CONSTANTS/g), "MATH_CONSTANTS should be a constant variable (by using const).");' +- text: Do not change original MATH_CONSTANTS. + testString: 'getUserInput => assert(getUserInput("index").match(/const\s+MATH_CONSTANTS\s+=\s+{\s+PI:\s+3.14\s+};/g), "Do not change original MATH_CONSTANTS.");' +- text: PI equals 3.14. + testString: 'assert(PI === 3.14, "PI equals 3.14.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +function freezeObj() { + "use strict"; + const MATH_CONSTANTS = { + PI: 3.14 + }; + // change code below this line + + + // change code above this line + try { + MATH_CONSTANTS.PI = 99; + } catch( ex ) { + console.log(ex); + } + return MATH_CONSTANTS.PI; +} +const PI = freezeObj(); +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/es6/Set Default Parameters for Your Functions.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/es6/Set Default Parameters for Your Functions.md new file mode 100644 index 0000000000..b4401403fe --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/es6/Set Default Parameters for Your Functions.md @@ -0,0 +1,63 @@ +--- +id: 587d7b88367417b2b2512b46 +title: Set Default Parameters for Your Functions +challengeType: 1 +--- + +## Description +
    +In order to help us create more flexible functions, ES6 introduces default parameters for functions. +Check out this code: +
    function greeting(name = "Anonymous") {
      return "Hello " + name;
    }
    console.log(greeting("John")); // Hello John
    console.log(greeting()); // Hello Anonymous
    +The default parameter kicks in when the argument is not specified (it is undefined). As you can see in the example above, the parameter name will receive its default value "Anonymous" when you do not provide a value for the parameter. You can add default values for as many parameters as you want. +
    + +## Instructions +
    +Modify the function increment by adding default parameters so that it will add 1 to number if value is not specified. +
    + +## Tests +
    + +```yml +- text: 'The result of increment(5, 2) should be 7.' + testString: 'assert(increment(5, 2) === 7, "The result of increment(5, 2) should be 7.");' +- text: The result of increment(5) should be 6. + testString: 'assert(increment(5) === 6, "The result of increment(5) should be 6.");' +- text: default parameter 1 was used for value. + testString: 'getUserInput => assert(getUserInput("index").match(/value\s*=\s*1/g), "default parameter 1 was used for value.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +const increment = (function() { + "use strict"; + return function increment(number, value) { + return number + value; + }; +})(); +console.log(increment(5, 2)); // returns 7 +console.log(increment(5)); // returns 6 +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/es6/Understand the Differences Between import and require.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/es6/Understand the Differences Between import and require.md new file mode 100644 index 0000000000..b331fae862 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/es6/Understand the Differences Between import and require.md @@ -0,0 +1,71 @@ +--- +id: 587d7b8c367417b2b2512b55 +title: Understand the Differences Between import and require +challengeType: 1 +--- + +## Description +
    +In the past, the function require() would be used to import the functions and code in external files and modules. While handy, this presents a problem: some files and modules are rather large, and you may only need certain code from those external resources. +ES6 gives us a very handy tool known as import. With it, we can choose which parts of a module or file to load into a given file, saving time and memory. +Consider the following example. Imagine that math_array_functions has about 20 functions, but I only need one, countItems, in my current file. The old require() approach would force me to bring in all 20 functions. With this new import syntax, I can bring in just the desired function, like so: +
    import { countItems } from "math_array_functions"
    +A description of the above code: +
    import { function } from "file_path_goes_here"
    // We can also import variables the same way!
    +There are a few ways to write an import statement, but the above is a very common use-case. +Note
    The whitespace surrounding the function inside the curly braces is a best practice - it makes it easier to read the import statement. +Note
    The lessons in this section handle non-browser features. import, and the statements we introduce in the rest of these lessons, won't work on a browser directly. However, we can use various tools to create code out of this to make it work in browser. +Note
    In most cases, the file path requires a ./ before it; otherwise, node will look in the node_modules directory first trying to load it as a dependency. +
    + +## Instructions +
    +Add the appropriate import statement that will allow the current file to use the capitalizeString function. The file where this function lives is called "string_functions", and it is in the same directory as the current file. +
    + +## Tests +
    + +```yml +- text: valid import statement + testString: 'getUserInput => assert(getUserInput("index").match(/import\s+\{\s*capitalizeString\s*\}\s+from\s+("|")string_functions\1/g), "valid import statement");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +"use strict"; +capitalizeString("hello!"); +``` + +
    + +### Before Test +
    + +```js +window.require = function (str) { +if (str === 'string_functions') { +return { +capitalizeString: str => str.toUpperCase() +}}}; +``` + +
    + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/es6/Use * to Import Everything from a File.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/es6/Use * to Import Everything from a File.md new file mode 100644 index 0000000000..b59f8baf09 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/es6/Use * to Import Everything from a File.md @@ -0,0 +1,67 @@ +--- +id: 587d7b8c367417b2b2512b57 +title: Use * to Import Everything from a File +challengeType: 1 +--- + +## Description +
    +Suppose you have a file that you wish to import all of its contents into the current file. This can be done with the import * syntax. +Here's an example where the contents of a file named "math_functions" are imported into a file in the same directory: +
    import * as myMathModule from "math_functions";
    myMathModule.add(2,3);
    myMathModule.subtract(5,3);
    +And breaking down that code: +
    import * as object_with_name_of_your_choice from "file_path_goes_here"
    object_with_name_of_your_choice.imported_function
    +You may use any name following the import * as portion of the statement. In order to utilize this method, it requires an object that receives the imported values. From here, you will use the dot notation to call your imported values. +
    + +## Instructions +
    +The code below requires the contents of a file, "capitalize_strings", found in the same directory as it, imported. Add the appropriate import * statement to the top of the file, using the object provided. +
    + +## Tests +
    + +```yml +- text: Properly uses import * as syntax. + testString: 'assert(code.match(/import\s+\*\s+as\s+[a-zA-Z0-9_$]+\s+from\s*"\s*capitalize_strings\s*"\s*;/gi), "Properly uses import * as syntax.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +"use strict"; +``` + +
    + +### Before Test +
    + +```js +window.require = function(str) { +if (str === 'capitalize_strings') { +return { +capitalize: str => str.toUpperCase(), +lowercase: str => str.toLowerCase() +}}}; +``` + +
    + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/es6/Use Arrow Functions to Write Concise Anonymous Functions.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/es6/Use Arrow Functions to Write Concise Anonymous Functions.md new file mode 100644 index 0000000000..c5b0068d9e --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/es6/Use Arrow Functions to Write Concise Anonymous Functions.md @@ -0,0 +1,67 @@ +--- +id: 587d7b87367417b2b2512b43 +title: Use Arrow Functions to Write Concise Anonymous Functions +challengeType: 1 +--- + +## Description +
    +In JavaScript, we often don't need to name our functions, especially when passing a function as an argument to another function. Instead, we create inline functions. We don't need to name these functions because we do not reuse them anywhere else. +To achieve this, we often use the following syntax: +
    const myFunc = function() {
      const myVar = "value";
      return myVar;
    }
    +ES6 provides us with the syntactic sugar to not have to write anonymous functions this way. Instead, you can use arrow function syntax: +
    const myFunc = () => {
      const myVar = "value";
      return myVar;
    }
    +When there is no function body, and only a return value, arrow function syntax allows you to omit the keyword return as well as the brackets surrounding the code. This helps simplify smaller functions into one-line statements: +
    const myFunc = () => "value"
    +This code will still return value by default. +
    + +## Instructions +
    +Rewrite the function assigned to the variable magic which returns a new Date() to use arrow function syntax. Also make sure nothing is defined using the keyword var. +
    + +## Tests +
    + +```yml +- text: User did replace var keyword. + testString: 'getUserInput => assert(!getUserInput("index").match(/var/g), "User did replace var keyword.");' +- text: magic should be a constant variable (by using const). + testString: 'getUserInput => assert(getUserInput("index").match(/const\s+magic/g), "magic should be a constant variable (by using const).");' +- text: magic is a function. + testString: 'assert(typeof magic === "function", "magic is a function.");' +- text: magic() returns correct date. + testString: 'assert(magic().getDate() == new Date().getDate(), "magic() returns correct date.");' +- text: function keyword was not used. + testString: 'getUserInput => assert(!getUserInput("index").match(/function/g), "function keyword was not used.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +var magic = function() { + "use strict"; + return new Date(); +}; +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/es6/Use Destructuring Assignment to Assign Variables from Arrays.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/es6/Use Destructuring Assignment to Assign Variables from Arrays.md new file mode 100644 index 0000000000..f890053d2e --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/es6/Use Destructuring Assignment to Assign Variables from Arrays.md @@ -0,0 +1,67 @@ +--- +id: 587d7b89367417b2b2512b4b +title: Use Destructuring Assignment to Assign Variables from Arrays +challengeType: 1 +--- + +## Description +
    +ES6 makes destructuring arrays as easy as destructuring objects. +One key difference between the spread operator and array destructuring is that the spread operator unpacks all contents of an array into a comma-separated list. Consequently, you cannot pick or choose which elements you want to assign to variables. +Destructuring an array lets us do exactly that: +
    const [a, b] = [1, 2, 3, 4, 5, 6];
    console.log(a, b); // 1, 2
    +The variable a is assigned the first value of the array, and b is assigned the second value of the array. +We can also access the value at any index in an array with destructuring by using commas to reach the desired index: +
    const [a, b,,, c] = [1, 2, 3, 4, 5, 6];
    console.log(a, b, c); // 1, 2, 5
    +
    + +## Instructions +
    +Use destructuring assignment to swap the values of a and b so that a receives the value stored in b, and b receives the value stored in a. +
    + +## Tests +
    + +```yml +- text: 'Value of a should be 6, after swapping.' + testString: 'assert(a === 6, "Value of a should be 6, after swapping.");' +- text: 'Value of b should be 8, after swapping.' + testString: 'assert(b === 8, "Value of b should be 8, after swapping.");' +- text: Use array destructuring to swap a and b. + testString: '// assert(/\[\s*(\w)\s*,\s*(\w)\s*\]\s*=\s*\[\s*\2\s*,\s*\1\s*\]/g.test(code), "Use array destructuring to swap a and b.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +let a = 8, b = 6; +(() => { + "use strict"; + // change code below this line + + // change code above this line +})(); +console.log(a); // should be 6 +console.log(b); // should be 8 +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/es6/Use Destructuring Assignment to Assign Variables from Nested Objects.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/es6/Use Destructuring Assignment to Assign Variables from Nested Objects.md new file mode 100644 index 0000000000..c18f19e8be --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/es6/Use Destructuring Assignment to Assign Variables from Nested Objects.md @@ -0,0 +1,67 @@ +--- +id: 587d7b89367417b2b2512b4a +title: Use Destructuring Assignment to Assign Variables from Nested Objects +challengeType: 1 +--- + +## Description +
    +We can similarly destructure nested objects into variables. +Consider the following code: +
    const a = {
      start: { x: 5, y: 6},
      end: { x: 6, y: -9 }
    };
    const { start : { x: startX, y: startY }} = a;
    console.log(startX, startY); // 5, 6
    +In the example above, the variable start is assigned the value of a.start, which is also an object. +
    + +## Instructions +
    +Use destructuring assignment to obtain max of forecast.tomorrow and assign it to maxOfTomorrow. +
    + +## Tests +
    + +```yml +- text: maxOfTomorrow equals 84.6 + testString: 'assert(getMaxOfTmrw(LOCAL_FORECAST) === 84.6, "maxOfTomorrow equals 84.6");' +- text: nested destructuring was used + testString: 'getUserInput => assert(getUserInput("index").match(/\{\s*tomorrow\s*:\s*\{\s*max\s*:\s*maxOfTomorrow\s*\}\s*\}\s*=\s*forecast/g),"nested destructuring was used");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +const LOCAL_FORECAST = { + today: { min: 72, max: 83 }, + tomorrow: { min: 73.3, max: 84.6 } +}; + +function getMaxOfTmrw(forecast) { + "use strict"; + // change code below this line + const maxOfTomorrow = undefined; // change this line + // change code above this line + return maxOfTomorrow; +} + +console.log(getMaxOfTmrw(LOCAL_FORECAST)); // should be 84.6 +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/es6/Use Destructuring Assignment to Assign Variables from Objects.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/es6/Use Destructuring Assignment to Assign Variables from Objects.md new file mode 100644 index 0000000000..29e14cdbab --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/es6/Use Destructuring Assignment to Assign Variables from Objects.md @@ -0,0 +1,72 @@ +--- +id: 587d7b89367417b2b2512b49 +title: Use Destructuring Assignment to Assign Variables from Objects +challengeType: 1 +--- + +## Description +
    +We saw earlier how spread operator can effectively spread, or unpack, the contents of the array. +We can do something similar with objects as well. Destructuring assignment is special syntax for neatly assigning values taken directly from an object to variables. +Consider the following ES5 code: +
    var voxel = {x: 3.6, y: 7.4, z: 6.54 };
    var x = voxel.x; // x = 3.6
    var y = voxel.y; // y = 7.4
    var z = voxel.z; // z = 6.54
    +Here's the same assignment statement with ES6 destructuring syntax: +
    const { x, y, z } = voxel; // x = 3.6, y = 7.4, z = 6.54
    +If instead you want to store the values of voxel.x into a, voxel.y into b, and voxel.z into c, you have that freedom as well. +
    const { x : a, y : b, z : c } = voxel // a = 3.6, b = 7.4, c = 6.54
    +You may read it as "get the field x and copy the value into a," and so on. +
    + +## Instructions +
    +Use destructuring to obtain the average temperature for tomorrow from the input object AVG_TEMPERATURES, and assign value with key tomorrow to tempOfTomorrow in line. +
    + +## Tests +
    + +```yml +- text: getTempOfTmrw(AVG_TEMPERATURES) should be 79 + testString: 'assert(getTempOfTmrw(AVG_TEMPERATURES) === 79, "getTempOfTmrw(AVG_TEMPERATURES) should be 79");' +- text: destructuring with reassignment was used + testString: 'getUserInput => assert(getUserInput("index").match(/\{\s*tomorrow\s*:\s*tempOfTomorrow\s*}\s*=\s*avgTemperatures/g),"destructuring with reassignment was used");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +const AVG_TEMPERATURES = { + today: 77.5, + tomorrow: 79 +}; + +function getTempOfTmrw(avgTemperatures) { + "use strict"; + // change code below this line + const tempOfTomorrow = undefined; // change this line + // change code above this line + return tempOfTomorrow; +} + +console.log(getTempOfTmrw(AVG_TEMPERATURES)); // should be 79 +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/es6/Use Destructuring Assignment to Pass an Object as a Function's Parameters.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/es6/Use Destructuring Assignment to Pass an Object as a Function's Parameters.md new file mode 100644 index 0000000000..7c88384061 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/es6/Use Destructuring Assignment to Pass an Object as a Function's Parameters.md @@ -0,0 +1,79 @@ +--- +id: 587d7b8a367417b2b2512b4d +title: Use Destructuring Assignment to Pass an Object as a Function's Parameters +challengeType: 1 +--- + +## Description +
    +In some cases, you can destructure the object in a function argument itself. +Consider the code below: +
    const profileUpdate = (profileData) => {
      const { name, age, nationality, location } = profileData;
      // do something with these variables
    }
    +This effectively destructures the object sent into the function. This can also be done in-place: +
    const profileUpdate = ({ name, age, nationality, location }) => {
      /* do something with these fields */
    }
    +This removes some extra lines and makes our code look neat. +This has the added benefit of not having to manipulate an entire object in a function; only the fields that are needed are copied inside the function. +
    + +## Instructions +
    +Use destructuring assignment within the argument to the function half to send only max and min inside the function. +
    + +## Tests +
    + +```yml +- text: stats should be an object. + testString: 'assert(typeof stats === "object", "stats should be an object.");' +- text: half(stats) should be 28.015 + testString: 'assert(half(stats) === 28.015, "half(stats) should be 28.015");' +- text: Destructuring was used. + testString: 'getUserInput => assert(getUserInput("index").match(/\(\s*\{\s*\w+\s*,\s*\w+\s*\}\s*\)/g), "Destructuring was used.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +const stats = { + max: 56.78, + standard_deviation: 4.34, + median: 34.54, + mode: 23.87, + min: -0.75, + average: 35.85 +}; +const half = (function() { + "use strict"; // do not change this line + + // change code below this line + return function half(stats) { + // use function argument destructuring + return (stats.max + stats.min) / 2.0; + }; + // change code above this line + +})(); +console.log(stats); // should be object +console.log(half(stats)); // should be 28.015 +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/es6/Use Destructuring Assignment with the Rest Operator to Reassign Array Elements.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/es6/Use Destructuring Assignment with the Rest Operator to Reassign Array Elements.md new file mode 100644 index 0000000000..60d65bf008 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/es6/Use Destructuring Assignment with the Rest Operator to Reassign Array Elements.md @@ -0,0 +1,67 @@ +--- +id: 587d7b8a367417b2b2512b4c +title: Use Destructuring Assignment with the Rest Operator to Reassign Array Elements +challengeType: 1 +--- + +## Description +
    +In some situations involving array destructuring, we might want to collect the rest of the elements into a separate array. +The result is similar to Array.prototype.slice(), as shown below: +
    const [a, b, ...arr] = [1, 2, 3, 4, 5, 7];
    console.log(a, b); // 1, 2
    console.log(arr); // [3, 4, 5, 7]
    +Variables a and b take the first and second values from the array. After that, because of rest operator's presence, arr gets rest of the values in the form of an array. +The rest element only works correctly as the last variable in the list. As in, you cannot use the rest operator to catch a subarray that leaves out last element of the original array. +
    + +## Instructions +
    +Use destructuring assignment with the rest operator to perform an effective Array.prototype.slice() so that arr is a sub-array of the original array source with the first two elements omitted. +
    + +## Tests +
    + +```yml +- text: 'arr should be [3,4,5,6,7,8,9,10]' + testString: 'assert(arr.every((v, i) => v === i + 3) && arr.length === 8,"arr should be [3,4,5,6,7,8,9,10]");' +- text: Destructuring should be used. + testString: 'getUserInput => assert(getUserInput("index").match(/\[\s*\w*\s*,\s*\w*\s*,\s*...\w+\s*\]/g),"Destructuring should be used.");' +- text: Array.slice() should not be used. + testString: 'getUserInput => assert(!getUserInput("index").match(/slice/g), "Array.slice() should not be used.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +const source = [1,2,3,4,5,6,7,8,9,10]; +function removeFirstTwo(list) { + "use strict"; + // change code below this line + arr = list; // change this + // change code above this line + return arr; +} +const arr = removeFirstTwo(source); +console.log(arr); // should be [3,4,5,6,7,8,9,10] +console.log(source); // should be [1,2,3,4,5,6,7,8,9,10]; +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/es6/Use class Syntax to Define a Constructor Function.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/es6/Use class Syntax to Define a Constructor Function.md new file mode 100644 index 0000000000..afb9e9f9ae --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/es6/Use class Syntax to Define a Constructor Function.md @@ -0,0 +1,71 @@ +--- +id: 587d7b8b367417b2b2512b53 +title: Use class Syntax to Define a Constructor Function +challengeType: 1 +--- + +## Description +
    +ES6 provides a new syntax to help create objects, using the keyword class. +This is to be noted, that the class syntax is just a syntax, and not a full-fledged class based implementation of object oriented paradigm, unlike in languages like Java, or Python, or Ruby etc. +In ES5, we usually define a constructor function, and use the new keyword to instantiate an object. +
    var SpaceShuttle = function(targetPlanet){
      this.targetPlanet = targetPlanet;
    }
    var zeus = new SpaceShuttle('Jupiter');
    +The class syntax simply replaces the constructor function creation: +
    class SpaceShuttle {
      constructor(targetPlanet){
        this.targetPlanet = targetPlanet;
      }
    }
    const zeus = new SpaceShuttle('Jupiter');
    +Notice that the class keyword declares a new function, and a constructor was added, which would be invoked when new is called - to create a new object. +
    + +## Instructions +
    +Use class keyword and write a proper constructor to create the Vegetable class. +The Vegetable lets you create a vegetable object, with a property name, to be passed to constructor. +
    + +## Tests +
    + +```yml +- text: Vegetable should be a class with a defined constructor method. + testString: 'assert(typeof Vegetable === "function" && typeof Vegetable.constructor === "function", "Vegetable should be a class with a defined constructor method.");' +- text: class keyword was used. + testString: 'getUserInput => assert(getUserInput("index").match(/class/g),"class keyword was used.");' +- text: Vegetable can be instantiated. + testString: 'assert(() => {const a = new Vegetable("apple"); return typeof a === "object";},"Vegetable can be instantiated.");' +- text: carrot.name should return carrot. + testString: 'assert(carrot.name=="carrot","carrot.name should return carrot.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +function makeClass() { + "use strict"; + /* Alter code below this line */ + + /* Alter code above this line */ + return Vegetable; +} +const Vegetable = makeClass(); +const carrot = new Vegetable('carrot'); +console.log(carrot.name); // => should be 'carrot' +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/es6/Use export to Reuse a Code Block.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/es6/Use export to Reuse a Code Block.md new file mode 100644 index 0000000000..560039dbe5 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/es6/Use export to Reuse a Code Block.md @@ -0,0 +1,66 @@ +--- +id: 587d7b8c367417b2b2512b56 +title: Use export to Reuse a Code Block +challengeType: 1 +--- + +## Description +
    +In the previous challenge, you learned about import and how it can be leveraged to import small amounts of code from large files. In order for this to work, though, we must utilize one of the statements that goes with import, known as export. When we want some code - a function, or a variable - to be usable in another file, we must export it in order to import it into another file. Like import, export is a non-browser feature. +The following is what we refer to as a named export. With this, we can import any code we export into another file with the import syntax you learned in the last lesson. Here's an example: +
    const capitalizeString = (string) => {
      return string.charAt(0).toUpperCase() + string.slice(1);
    }
    export { capitalizeString } //How to export functions.
    export const foo = "bar"; //How to export variables.
    +Alternatively, if you would like to compact all your export statements into one line, you can take this approach: +
    const capitalizeString = (string) => {
      return string.charAt(0).toUpperCase() + string.slice(1);
    }
    const foo = "bar";
    export { capitalizeString, foo }
    +Either approach is perfectly acceptable. +
    + +## Instructions +
    +Below are two variables that I want to make available for other files to use. Utilizing the first way I demonstrated export, export the two variables. +
    + +## Tests +
    + +```yml +- text: foo is exported. + testString: 'getUserInput => assert(getUserInput("index").match(/export\s+const\s+foo\s*=\s*"bar"/g), "foo is exported.");' +- text: bar is exported. + testString: 'getUserInput => assert(getUserInput("index").match(/export\s+const\s+bar\s*=\s*"foo"/g), "bar is exported.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +"use strict"; +const foo = "bar"; +const bar = "foo"; +``` + +
    + +### Before Test +
    + +```js +window.exports = function(){}; +``` + +
    + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/es6/Use getters and setters to Control Access to an Object.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/es6/Use getters and setters to Control Access to an Object.md new file mode 100644 index 0000000000..b35cee56b6 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/es6/Use getters and setters to Control Access to an Object.md @@ -0,0 +1,76 @@ +--- +id: 587d7b8c367417b2b2512b54 +title: Use getters and setters to Control Access to an Object +challengeType: 1 +--- + +## Description +
    +You can obtain values from an object, and set a value of a property within an object. +These are classically called getters and setters. +Getter functions are meant to simply return (get) the value of an object's private variable to the user without the user directly accessing the private variable. +Setter functions are meant to modify (set) the value of an object's private variable based on the value passed into the setter function. This change could involve calculations, or even overwriting the previous value completely. +
    class Book {
      constructor(author) {
        this._author = author;
      }
      // getter
      get writer(){
        return this._author;
      }
      // setter
      set writer(updatedAuthor){
        this._author = updatedAuthor;
      }
    }
    const lol = new Book('anonymous');
    console.log(lol.writer);  // anonymous
    lol.writer = 'wut';
    console.log(lol.writer);  // wut
    +Notice the syntax we are using to invoke the getter and setter - as if they are not even functions. +Getters and setters are important, because they hide internal implementation details. +
    + +## Instructions +
    +Use class keyword to create a Thermostat class. The constructor accepts Fahrenheit temperature. +Now create getter and setter in the class, to obtain the temperature in Celsius scale. +Remember that C = 5/9 * (F - 32) and F = C * 9.0 / 5 + 32, where F is the value of temperature in Fahrenheit scale, and C is the value of the same temperature in Celsius scale +Note +When you implement this, you would be tracking the temperature inside the class in one scale - either Fahrenheit or Celsius. +This is the power of getter or setter - you are creating an API for another user, who would get the correct result, no matter which one you track. +In other words, you are abstracting implementation details from the consumer. +
    + +## Tests +
    + +```yml +- text: Thermostat should be a class with a defined constructor method. + testString: 'assert(typeof Thermostat === "function" && typeof Thermostat.constructor === "function","Thermostat should be a class with a defined constructor method.");' +- text: class keyword was used. + testString: 'getUserInput => assert(getUserInput("index").match(/class/g),"class keyword was used.");' +- text: Thermostat can be instantiated. + testString: 'assert(() => {const t = new Thermostat(32); return typeof t === "object" && t.temperature === 0;}, "Thermostat can be instantiated.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +function makeClass() { + "use strict"; + /* Alter code below this line */ + + /* Alter code above this line */ + return Thermostat; +} +const Thermostat = makeClass(); +const thermos = new Thermostat(76); // setting in Fahrenheit scale +let temp = thermos.temperature; // 24.44 in C +thermos.temperature = 26; +temp = thermos.temperature; // 26 in C +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/es6/Use the Rest Operator with Function Parameters.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/es6/Use the Rest Operator with Function Parameters.md new file mode 100644 index 0000000000..81b87cd094 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/es6/Use the Rest Operator with Function Parameters.md @@ -0,0 +1,67 @@ +--- +id: 587d7b88367417b2b2512b47 +title: Use the Rest Operator with Function Parameters +challengeType: 1 +--- + +## Description +
    +In order to help us create more flexible functions, ES6 introduces the rest operator for function parameters. With the rest operator, you can create functions that take a variable number of arguments. These arguments are stored in an array that can be accessed later from inside the function. +Check out this code: +
    function howMany(...args) {
      return "You have passed " + args.length + " arguments.";
    }
    console.log(howMany(0, 1, 2)); // You have passed 3 arguments
    console.log(howMany("string", null, [1, 2, 3], { })); // You have passed 4 arguments.
    +The rest operator eliminates the need to check the args array and allows us to apply map(), filter() and reduce() on the parameters array. +
    + +## Instructions +
    +Modify the function sum so that it uses the rest operator and it works in the same way with any number of parameters. +
    + +## Tests +
    + +```yml +- text: 'The result of sum(0,1,2) should be 3' + testString: 'assert(sum(0,1,2) === 3, "The result of sum(0,1,2) should be 3");' +- text: 'The result of sum(1,2,3,4) should be 10' + testString: 'assert(sum(1,2,3,4) === 10, "The result of sum(1,2,3,4) should be 10");' +- text: The result of sum(5) should be 5 + testString: 'assert(sum(5) === 5, "The result of sum(5) should be 5");' +- text: The result of sum() should be 0 + testString: 'assert(sum() === 0, "The result of sum() should be 0");' +- text: The sum function uses the ... spread operator on the args parameter. + testString: 'getUserInput => assert(getUserInput("index").match(/function\s+sum\s*\(\s*...args\s*\)\s*{/g), "The sum function uses the ... spread operator on the args parameter.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +const sum = (function() { + "use strict"; + return function sum(x, y, z) { + const args = [ x, y, z ]; + return args.reduce((a, b) => a + b, 0); + }; +})(); +console.log(sum(1, 2, 3)); // 6 +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/es6/Use the Spread Operator to Evaluate Arrays In-Place.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/es6/Use the Spread Operator to Evaluate Arrays In-Place.md new file mode 100644 index 0000000000..da2766364f --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/es6/Use the Spread Operator to Evaluate Arrays In-Place.md @@ -0,0 +1,67 @@ +--- +id: 587d7b89367417b2b2512b48 +title: Use the Spread Operator to Evaluate Arrays In-Place +challengeType: 1 +--- + +## Description +
    +ES6 introduces the spread operator, which allows us to expand arrays and other expressions in places where multiple parameters or elements are expected. +The ES5 code below uses apply() to compute the maximum value in an array: +
    var arr = [6, 89, 3, 45];
    var maximus = Math.max.apply(null, arr); // returns 89
    +We had to use Math.max.apply(null, arr) because Math.max(arr) returns NaN. Math.max() expects comma-separated arguments, but not an array. +The spread operator makes this syntax much better to read and maintain. +
    const arr = [6, 89, 3, 45];
    const maximus = Math.max(...arr); // returns 89
    +...arr returns an unpacked array. In other words, it spreads the array. +However, the spread operator only works in-place, like in an argument to a function or in an array literal. The following code will not work: +
    const spreaded = ...arr; // will throw a syntax error
    +
    + +## Instructions +
    +Copy all contents of arr1 into another array arr2 using the spread operator. +
    + +## Tests +
    + +```yml +- text: arr2 is correct copy of arr1. + testString: 'assert(arr2.every((v, i) => v === arr1[i]), "arr2 is correct copy of arr1.");' +- text: ... spread operator was used to duplicate arr1. + testString: 'getUserInput => assert(getUserInput("index").match(/\[\s*...arr1\s*\]/g),"... spread operator was used to duplicate arr1.");' +- text: arr2 remains unchanged when arr1 is changed. + testString: 'assert((arr1, arr2) => {arr1.push("JUN"); return arr2.length < arr1.length},"arr2 remains unchanged when arr1 is changed.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +const arr1 = ['JAN', 'FEB', 'MAR', 'APR', 'MAY']; +let arr2; +(function() { + "use strict"; + arr2 = []; // change this line +})(); +console.log(arr2); +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/es6/Write Arrow Functions with Parameters.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/es6/Write Arrow Functions with Parameters.md new file mode 100644 index 0000000000..bdf1ba40ba --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/es6/Write Arrow Functions with Parameters.md @@ -0,0 +1,64 @@ +--- +id: 587d7b88367417b2b2512b44 +title: Write Arrow Functions with Parameters +challengeType: 1 +--- + +## Description +
    +Just like a normal function, you can pass arguments into arrow functions. +
    // doubles input value and returns it
    const doubler = (item) => item * 2;
    +You can pass more than one argument into arrow functions as well. +
    + +## Instructions +
    +Rewrite the myConcat function which appends contents of arr2 to arr1 so that the function uses arrow function syntax. +
    + +## Tests +
    + +```yml +- text: User did replace var keyword. + testString: 'getUserInput => assert(!getUserInput("index").match(/var/g), "User did replace var keyword.");' +- text: myConcat should be a constant variable (by using const). + testString: 'getUserInput => assert(getUserInput("index").match(/const\s+myConcat/g), "myConcat should be a constant variable (by using const).");' +- text: myConcat should be a function + testString: 'assert(typeof myConcat === "function", "myConcat should be a function");' +- text: myConcat() returns the correct array + testString: 'assert(() => { const a = myConcat([1], [2]); return a[0] == 1 && a[1] == 2; }, "myConcat() returns the correct array");' +- text: function keyword was not used. + testString: 'getUserInput => assert(!getUserInput("index").match(/function/g), "function keyword was not used.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +var myConcat = function(arr1, arr2) { + "use strict"; + return arr1.concat(arr2); +}; +// test your code +console.log(myConcat([1, 2], [3, 4, 5])); +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/es6/Write Concise Declarative Functions with ES6.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/es6/Write Concise Declarative Functions with ES6.md new file mode 100644 index 0000000000..06dbd71dff --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/es6/Write Concise Declarative Functions with ES6.md @@ -0,0 +1,66 @@ +--- +id: 587d7b8b367417b2b2512b50 +title: Write Concise Declarative Functions with ES6 +challengeType: 1 +--- + +## Description +
    +When defining functions within objects in ES5, we have to use the keyword function as follows: +
    const person = {
      name: "Taylor",
      sayHello: function() {
        return `Hello! My name is ${this.name}.`;
      }
    };
    +With ES6, You can remove the function keyword and colon altogether when defining functions in objects. Here's an example of this syntax: +
    const person = {
      name: "Taylor",
      sayHello() {
        return `Hello! My name is ${this.name}.`;
      }
    };
    +
    + +## Instructions +
    +Refactor the function setGear inside the object bicycle to use the shorthand syntax described above. +
    + +## Tests +
    + +```yml +- text: Traditional function expression was not used. + testString: 'assert(!getUserInput("index").match(/function/),"Traditional function expression was not used.");' +- text: setGear is a declarative function. + testString: 'assert(typeof bicycle.setGear === "function" && getUserInput("index").match(/setGear\s*\(.+\)\s*\{/), "setGear is a declarative function.");' +- text: bicycle.setGear(48) changes the gear value to 48. + testString: 'assert((new bicycle.setGear(48)).gear === 48, "bicycle.setGear(48) changes the gear value to 48.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +// change code below this line +const bicycle = { + gear: 2, + setGear: function(newGear) { + "use strict"; + this.gear = newGear; + } +}; +// change code above this line +bicycle.setGear(3); +console.log(bicycle.gear); +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/es6/Write Concise Object Literal Declarations Using Simple Fields.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/es6/Write Concise Object Literal Declarations Using Simple Fields.md new file mode 100644 index 0000000000..920bbfb482 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/es6/Write Concise Object Literal Declarations Using Simple Fields.md @@ -0,0 +1,67 @@ +--- +id: 587d7b8a367417b2b2512b4f +title: Write Concise Object Literal Declarations Using Simple Fields +challengeType: 1 +--- + +## Description +
    +ES6 adds some nice support for easily defining object literals. +Consider the following code: +
    const getMousePosition = (x, y) => ({
      x: x,
      y: y
    });
    +getMousePosition is a simple function that returns an object containing two fields. +ES6 provides the syntactic sugar to eliminate the redundancy of having to write x: x. You can simply write x once, and it will be converted tox: x (or something equivalent) under the hood. +Here is the same function from above rewritten to use this new syntax: +
    const getMousePosition = (x, y) => ({ x, y });
    +
    + +## Instructions +
    +Use simple fields with object literals to create and return a Person object. +
    + +## Tests +
    + +```yml +- text: 'the output is {name: "Zodiac Hasbro", age: 56, gender: "male"}.' + testString: 'assert(() => {const res={name:"Zodiac Hasbro",age:56,gender:"male"}; const person=createPerson("Zodiac Hasbro", 56, "male"); return Object.keys(person).every(k => person[k] === res[k]);}, "the output is {name: "Zodiac Hasbro", age: 56, gender: "male"}.");' +- text: 'No : were used.' + testString: 'getUserInput => assert(!getUserInput("index").match(/:/g), "No : were used.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +const createPerson = (name, age, gender) => { + "use strict"; + // change code below this line + return { + name: name, + age: age, + gender: gender + }; + // change code above this line +}; +console.log(createPerson("Zodiac Hasbro", 56, "male")); // returns a proper object +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/es6/Write Higher Order Arrow Functions.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/es6/Write Higher Order Arrow Functions.md new file mode 100644 index 0000000000..eedfe108b8 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/es6/Write Higher Order Arrow Functions.md @@ -0,0 +1,75 @@ +--- +id: 587d7b88367417b2b2512b45 +title: Write Higher Order Arrow Functions +challengeType: 1 +--- + +## Description +
    +It's time we see how powerful arrow functions are when processing data. +Arrow functions work really well with higher order functions, such as map(), filter(), and reduce(), that take other functions as arguments for processing collections of data. +Read the following code: +
    FBPosts.filter(function(post) {
      return post.thumbnail !== null && post.shares > 100 && post.likes > 500;
    })
    +We have written this with filter() to at least make it somewhat readable. Now compare it to the following code which uses arrow function syntax instead: +
    FBPosts.filter((post) => post.thumbnail !== null && post.shares > 100 && post.likes > 500)
    +This code is more succinct and accomplishes the same task with fewer lines of code. +
    + +## Instructions +
    +Use arrow function syntax to compute the square of only the positive integers (decimal numbers are not integers) in the array realNumberArray and store the new array in the variable squaredIntegers. +
    + +## Tests +
    + +```yml +- text: squaredIntegers should be a constant variable (by using const). + testString: 'getUserInput => assert(getUserInput("index").match(/const\s+squaredIntegers/g), "squaredIntegers should be a constant variable (by using const).");' +- text: squaredIntegers should be an array + testString: 'assert(Array.isArray(squaredIntegers), "squaredIntegers should be an array");' +- text: 'squaredIntegers should be [16, 1764, 36]' + testString: 'assert.deepStrictEqual(squaredIntegers, [16, 1764, 36], "squaredIntegers should be [16, 1764, 36]");' +- text: function keyword was not used. + testString: 'getUserInput => assert(!getUserInput("index").match(/function/g), "function keyword was not used.");' +- text: loop should not be used + testString: 'getUserInput => assert(!getUserInput("index").match(/(for)|(while)/g), "loop should not be used");' +- text: 'map, filter, or reduce should be used' + testString: 'getUserInput => assert(getUserInput("index").match(/map|filter|reduce/g), "map, filter, or reduce should be used");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +const realNumberArray = [4, 5.6, -9.8, 3.14, 42, 6, 8.34, -2]; +const squareList = (arr) => { + "use strict"; + // change code below this line + const squaredIntegers = arr; + // change code above this line + return squaredIntegers; +}; +// test your code +const squaredIntegers = squareList(realNumberArray); +console.log(squaredIntegers); +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/es6/meta.json b/curriculum/challenges/02-javascript-algorithms-and-data-structures/es6/meta.json new file mode 100644 index 0000000000..4e0bd42c19 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/es6/meta.json @@ -0,0 +1,8 @@ +{ + "name": "ES6", + "dashedName": "es6", + "order": 2, + "time": "5 hours", + "superBlock": "javascript-algorithms-and-data-structures", + "superOrder": 2 +} \ No newline at end of file diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/functional-programming/Add Elements to the End of an Array Using concat Instead of push.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/functional-programming/Add Elements to the End of an Array Using concat Instead of push.md new file mode 100644 index 0000000000..e1f7a1b6d2 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/functional-programming/Add Elements to the End of an Array Using concat Instead of push.md @@ -0,0 +1,68 @@ +--- +id: 587d7da9367417b2b2512b67 +title: Add Elements to the End of an Array Using concat Instead of push +challengeType: 1 +--- + +## Description +
    +Functional programming is all about creating and using non-mutating functions. +The last challenge introduced the concat method as a way to combine arrays into a new one without mutating the original arrays. Compare concat to the push method. Push adds an item to the end of the same array it is called on, which mutates that array. Here's an example: +
    var arr = [1, 2, 3];
    arr.push([4, 5, 6]);
    // arr is changed to [1, 2, 3, [4, 5, 6]]
    // Not the functional programming way
    +Concat offers a way to add new items to the end of an array without any mutating side effects. +
    + +## Instructions +
    +Change the nonMutatingPush function so it uses concat to add newItem to the end of original instead of push. The function should return an array. +
    + +## Tests +
    + +```yml +- text: Your code should use the concat method. + testString: 'assert(code.match(/\.concat/g), "Your code should use the concat method.");' +- text: Your code should not use the push method. + testString: 'assert(!code.match(/\.push/g), "Your code should not use the push method.");' +- text: The first array should not change. + testString: 'assert(JSON.stringify(first) === JSON.stringify([1, 2, 3]), "The first array should not change.");' +- text: The second array should not change. + testString: 'assert(JSON.stringify(second) === JSON.stringify([4, 5]), "The second array should not change.");' +- text: 'nonMutatingPush([1, 2, 3], [4, 5]) should return [1, 2, 3, 4, 5].' + testString: 'assert(JSON.stringify(nonMutatingPush([1, 2, 3], [4, 5])) === JSON.stringify([1, 2, 3, 4, 5]), "nonMutatingPush([1, 2, 3], [4, 5]) should return [1, 2, 3, 4, 5].");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +function nonMutatingPush(original, newItem) { + // Add your code below this line + return original.push(newItem); + + // Add your code above this line +} +var first = [1, 2, 3]; +var second = [4, 5]; +nonMutatingPush(first, second); +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/functional-programming/Apply Functional Programming to Convert Strings to URL Slugs.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/functional-programming/Apply Functional Programming to Convert Strings to URL Slugs.md new file mode 100644 index 0000000000..45ef85557a --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/functional-programming/Apply Functional Programming to Convert Strings to URL Slugs.md @@ -0,0 +1,75 @@ +--- +id: 587d7dab367417b2b2512b6d +title: Apply Functional Programming to Convert Strings to URL Slugs +challengeType: 1 +--- + +## Description +
    +The last several challenges covered a number of useful array and string methods that follow functional programming principles. We've also learned about reduce, which is a powerful method used to reduce problems to simpler forms. From computing averages to sorting, any array operation can be achieved by applying it. Recall that map and filter are special cases of reduce. +Let's combine what we've learned to solve a practical problem. +Many content management sites (CMS) have the titles of a post added to part of the URL for simple bookmarking purposes. For example, if you write a Medium post titled "Stop Using Reduce", it's likely the URL would have some form of the title string in it (".../stop-using-reduce"). You may have already noticed this on the freeCodeCamp site. +
    + +## Instructions +
    +Fill in the urlSlug function so it converts a string title and returns the hyphenated version for the URL. You can use any of the methods covered in this section, and don't use replace. Here are the requirements: +The input is a string with spaces and title-cased words +The output is a string with the spaces between words replaced by a hyphen (-) +The output should be all lower-cased letters +The output should not have any spaces +
    + +## Tests +
    + +```yml +- text: The globalTitle variable should not change. + testString: 'assert(globalTitle === "Winter Is Coming", "The globalTitle variable should not change.");' +- text: Your code should not use the replace method for this challenge. + testString: 'assert(!code.match(/\.replace/g), "Your code should not use the replace method for this challenge.");' +- text: urlSlug("Winter Is Coming") should return "winter-is-coming". + testString: 'assert(urlSlug("Winter Is Coming") === "winter-is-coming", "urlSlug("Winter Is Coming") should return "winter-is-coming".");' +- text: urlSlug(" Winter Is  Coming") should return "winter-is-coming". + testString: 'assert(urlSlug(" Winter Is Coming") === "winter-is-coming", "urlSlug(" Winter Is  Coming") should return "winter-is-coming".");' +- text: urlSlug("A Mind Needs Books Like A Sword Needs A Whetstone") should return "a-mind-needs-books-like-a-sword-needs-a-whetstone". + testString: 'assert(urlSlug("A Mind Needs Books Like A Sword Needs A Whetstone") === "a-mind-needs-books-like-a-sword-needs-a-whetstone", "urlSlug("A Mind Needs Books Like A Sword Needs A Whetstone") should return "a-mind-needs-books-like-a-sword-needs-a-whetstone".");' +- text: urlSlug("Hold The Door") should return "hold-the-door". + testString: 'assert(urlSlug("Hold The Door") === "hold-the-door", "urlSlug("Hold The Door") should return "hold-the-door".");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +// the global variable +var globalTitle = "Winter Is Coming"; + +// Add your code below this line +function urlSlug(title) { + + +} +// Add your code above this line + +var winterComing = urlSlug(globalTitle); // Should be "winter-is-coming" +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/functional-programming/Avoid Mutations and Side Effects Using Functional Programming.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/functional-programming/Avoid Mutations and Side Effects Using Functional Programming.md new file mode 100644 index 0000000000..3b62a9a5f5 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/functional-programming/Avoid Mutations and Side Effects Using Functional Programming.md @@ -0,0 +1,67 @@ +--- +id: 587d7b8e367417b2b2512b5e +title: Avoid Mutations and Side Effects Using Functional Programming +challengeType: 1 +--- + +## Description +
    +If you haven't already figured it out, the issue in the previous challenge was with the splice call in the tabClose() function. Unfortunately, splice changes the original array it is called on, so the second call to it used a modified array, and gave unexpected results. +This is a small example of a much larger pattern - you call a function on a variable, array, or an object, and the function changes the variable or something in the object. +One of the core principle of functional programming is to not change things. Changes lead to bugs. It's easier to prevent bugs knowing that your functions don't change anything, including the function arguments or any global variable. +The previous example didn't have any complicated operations but the splice method changed the original array, and resulted in a bug. +Recall that in functional programming, changing or altering things is called mutation, and the outcome is called a side effect. A function, ideally, should be a pure function, meaning that it does not cause any side effects. +Let's try to master this discipline and not alter any variable or object in our code. +
    + +## Instructions +
    +Fill in the code for the function incrementer so it returns the value of the global variable fixedValue increased by one. +
    + +## Tests +
    + +```yml +- text: Your function incrementer should not change the value of fixedValue. + testString: 'assert(fixedValue === 4, "Your function incrementer should not change the value of fixedValue.");' +- text: Your incrementer function should return a value that is one larger than the fixedValue value. + testString: 'assert(newValue === 5, "Your incrementer function should return a value that is one larger than the fixedValue value.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +// the global variable +var fixedValue = 4; + +function incrementer () { + // Add your code below this line + + + // Add your code above this line +} + +var newValue = incrementer(); // Should equal 5 +console.log(fixedValue); // Should print 4 +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/functional-programming/Combine Two Arrays Using the concat Method.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/functional-programming/Combine Two Arrays Using the concat Method.md new file mode 100644 index 0000000000..df0f327165 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/functional-programming/Combine Two Arrays Using the concat Method.md @@ -0,0 +1,64 @@ +--- +id: 587d7da9367417b2b2512b66 +title: Combine Two Arrays Using the concat Method +challengeType: 1 +--- + +## Description +
    +Concatenation means to join items end to end. JavaScript offers the concat method for both strings and arrays that work in the same way. For arrays, the method is called on one, then another array is provided as the argument to concat, which is added to the end of the first array. It returns a new array and does not mutate either of the original arrays. Here's an example: +
    [1, 2, 3].concat([4, 5, 6]);
    // Returns a new array [1, 2, 3, 4, 5, 6]
    +
    + +## Instructions +
    +Use the concat method in the nonMutatingConcat function to concatenate attach to the end of original. The function should return the concatenated array. +
    + +## Tests +
    + +```yml +- text: Your code should use the concat method. + testString: 'assert(code.match(/\.concat/g), "Your code should use the concat method.");' +- text: The first array should not change. + testString: 'assert(JSON.stringify(first) === JSON.stringify([1, 2, 3]), "The first array should not change.");' +- text: The second array should not change. + testString: 'assert(JSON.stringify(second) === JSON.stringify([4, 5]), "The second array should not change.");' +- text: 'nonMutatingConcat([1, 2, 3], [4, 5]) should return [1, 2, 3, 4, 5].' + testString: 'assert(JSON.stringify(nonMutatingConcat([1, 2, 3], [4, 5])) === JSON.stringify([1, 2, 3, 4, 5]), "nonMutatingConcat([1, 2, 3], [4, 5]) should return [1, 2, 3, 4, 5].");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +function nonMutatingConcat(original, attach) { + // Add your code below this line + + + // Add your code above this line +} +var first = [1, 2, 3]; +var second = [4, 5]; +nonMutatingConcat(first, second); +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/functional-programming/Combine an Array into a String Using the join Method.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/functional-programming/Combine an Array into a String Using the join Method.md new file mode 100644 index 0000000000..071a76f4ee --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/functional-programming/Combine an Array into a String Using the join Method.md @@ -0,0 +1,67 @@ +--- +id: 587d7daa367417b2b2512b6c +title: Combine an Array into a String Using the join Method +challengeType: 1 +--- + +## Description +
    +The join method is used to join the elements of an array together to create a string. It takes an argument for the delimiter that is used to separate the array elements in the string. +Here's an example: +
    var arr = ["Hello", "World"];
    var str = arr.join(" ");
    // Sets str to "Hello World"
    +
    + +## Instructions +
    +Use the join method (among others) inside the sentensify function to make a sentence from the words in the string str. The function should return a string. For example, "I-like-Star-Wars" would be converted to "I like Star Wars". For this challenge, do not use the replace method. +
    + +## Tests +
    + +```yml +- text: Your code should use the join method. + testString: 'assert(code.match(/\.join/g), "Your code should use the join method.");' +- text: Your code should not use the replace method. + testString: 'assert(!code.match(/\.replace/g), "Your code should not use the replace method.");' +- text: sentensify("May-the-force-be-with-you") should return a string. + testString: 'assert(typeof sentensify("May-the-force-be-with-you") === "string", "sentensify("May-the-force-be-with-you") should return a string.");' +- text: sentensify("May-the-force-be-with-you") should return "May the force be with you". + testString: 'assert(sentensify("May-the-force-be-with-you") === "May the force be with you", "sentensify("May-the-force-be-with-you") should return "May the force be with you".");' +- text: sentensify("The.force.is.strong.with.this.one") should return "The force is strong with this one". + testString: 'assert(sentensify("The.force.is.strong.with.this.one") === "The force is strong with this one", "sentensify("The.force.is.strong.with.this.one") should return "The force is strong with this one".");' +- text: 'sentensify("There,has,been,an,awakening") should return "There has been an awakening".' + testString: 'assert(sentensify("There,has,been,an,awakening") === "There has been an awakening", "sentensify("There,has,been,an,awakening") should return "There has been an awakening".");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +function sentensify(str) { + // Add your code below this line + + + // Add your code above this line +} +sentensify("May-the-force-be-with-you"); +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/functional-programming/Implement map on a Prototype.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/functional-programming/Implement map on a Prototype.md new file mode 100644 index 0000000000..19d3aa050c --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/functional-programming/Implement map on a Prototype.md @@ -0,0 +1,68 @@ +--- +id: 587d7b8f367417b2b2512b62 +title: Implement map on a Prototype +challengeType: 1 +--- + +## Description +
    +As you have seen from applying Array.prototype.map(), or simply map() earlier, the map method returns an array of the same length as the one it was called on. It also doesn't alter the original array, as long as its callback function doesn't. +In other words, map is a pure function, and its output depends solely on its inputs. Plus, it takes another function as its argument. +It would teach us a lot about map to try to implement a version of it that behaves exactly like the Array.prototype.map() with a for loop or Array.prototype.forEach(). +Note: A pure function is allowed to alter local variables defined within its scope, although, it's preferable to avoid that as well. +
    + +## Instructions +
    +Write your own Array.prototype.myMap(), which should behave exactly like Array.prototype.map(). You may use a for loop or the forEach method. +
    + +## Tests +
    + +```yml +- text: 'new_s should equal [46, 130, 196, 10].' + testString: 'assert(JSON.stringify(new_s) === JSON.stringify([46, 130, 196, 10]), "new_s should equal [46, 130, 196, 10].");' +- text: Your code should not use the map method. + testString: 'assert(!code.match(/\.map/g), "Your code should not use the map method.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +// the global Array +var s = [23, 65, 98, 5]; + +Array.prototype.myMap = function(callback){ + var newArray = []; + // Add your code below this line + + // Add your code above this line + return newArray; + +}; + +var new_s = s.myMap(function(item){ + return item * 2; +}); +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/functional-programming/Implement the filter Method on a Prototype.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/functional-programming/Implement the filter Method on a Prototype.md new file mode 100644 index 0000000000..5ad6b62d1f --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/functional-programming/Implement the filter Method on a Prototype.md @@ -0,0 +1,66 @@ +--- +id: 587d7b8f367417b2b2512b64 +title: Implement the filter Method on a Prototype +challengeType: 1 +--- + +## Description +
    +It would teach us a lot about the filter method if we try to implement a version of it that behaves exactly like Array.prototype.filter(). It can use either a for loop or Array.prototype.forEach(). +Note: A pure function is allowed to alter local variables defined within its scope, although, it's preferable to avoid that as well. +
    + +## Instructions +
    +Write your own Array.prototype.myFilter(), which should behave exactly like Array.prototype.filter(). You may use a for loop or the Array.prototype.forEach() method. +
    + +## Tests +
    + +```yml +- text: 'new_s should equal [23, 65, 5].' + testString: 'assert(JSON.stringify(new_s) === JSON.stringify([23, 65, 5]), "new_s should equal [23, 65, 5].");' +- text: Your code should not use the filter method. + testString: 'assert(!code.match(/\.filter/g), "Your code should not use the filter method.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +// the global Array +var s = [23, 65, 98, 5]; + +Array.prototype.myFilter = function(callback){ + var newArray = []; + // Add your code below this line + + // Add your code above this line + return newArray; + +}; + +var new_s = s.myFilter(function(item){ + return item % 2 === 1; +}); +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/functional-programming/Introduction to Currying and Partial Application.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/functional-programming/Introduction to Currying and Partial Application.md new file mode 100644 index 0000000000..ed79921469 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/functional-programming/Introduction to Currying and Partial Application.md @@ -0,0 +1,69 @@ +--- +id: 587d7dab367417b2b2512b70 +title: Introduction to Currying and Partial Application +challengeType: 1 +--- + +## Description +
    +The arity of a function is the number of arguments it requires. Currying a function means to convert a function of N arity into N functions of arity 1. +In other words, it restructures a function so it takes one argument, then returns another function that takes the next argument, and so on. +Here's an example: +
    //Un-curried function
    function unCurried(x, y) {
      return x + y;
    }

    //Curried function
    function curried(x) {
      return function(y) {
        return x + y;
      }
    }
    curried(1)(2) // Returns 3
    +This is useful in your program if you can't supply all the arguments to a function at one time. You can save each function call into a variable, which will hold the returned function reference that takes the next argument when it's available. Here's an example using the curried function in the example above: +
    // Call a curried function in parts:
    var funcForY = curried(1);
    console.log(funcForY(2)); // Prints 3
    +Similarly, partial application can be described as applying a few arguments to a function at a time and returning another function that is applied to more arguments. +Here's an example: +
    //Impartial function
    function impartial(x, y, z) {
      return x + y + z;
    }
    var partialFn = impartial.bind(this, 1, 2);
    partialFn(10); // Returns 13
    +
    + +## Instructions +
    +Fill in the body of the add function so it uses currying to add parameters x, y, and z. +
    + +## Tests +
    + +```yml +- text: add(10)(20)(30) should return 60. + testString: 'assert(add(10)(20)(30) === 60, "add(10)(20)(30) should return 60.");' +- text: add(1)(2)(3) should return 6. + testString: 'assert(add(1)(2)(3) === 6, "add(1)(2)(3) should return 6.");' +- text: add(11)(22)(33) should return 66. + testString: 'assert(add(11)(22)(33) === 66, "add(11)(22)(33) should return 66.");' +- text: Your code should include a final statement that returns x + y + z. + testString: 'assert(code.match(/[xyz]\s*?\+\s*?[xyz]\s*?\+\s*?[xyz]/g), "Your code should include a final statement that returns x + y + z.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +function add(x) { + // Add your code below this line + + + // Add your code above this line +} +add(10)(20)(30); +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/functional-programming/Learn About Functional Programming.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/functional-programming/Learn About Functional Programming.md new file mode 100644 index 0000000000..06b38e1c55 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/functional-programming/Learn About Functional Programming.md @@ -0,0 +1,85 @@ +--- +id: 587d7b8d367417b2b2512b5b +title: Learn About Functional Programming +challengeType: 1 +--- + +## Description +
    +Functional programming is a style of programming where solutions are simple, isolated functions, without any side effects outside of the function scope. +INPUT -> PROCESS -> OUTPUT +Functional programming is about: +1) Isolated functions - there is no dependence on the state of the program, which includes global variables that are subject to change +2) Pure functions - the same input always gives the same output +3) Functions with limited side effects - any changes, or mutations, to the state of the program outside the function are carefully controlled +
    + +## Instructions +
    +The members of freeCodeCamp happen to love tea. +In the code editor, the prepareTea and getTea functions are already defined for you. Call the getTea function to get 40 cups of tea for the team, and store them in the tea4TeamFCC variable. +
    + +## Tests +
    + +```yml +- text: The tea4TeamFCC variable should hold 40 cups of tea for the team. + testString: 'assert(tea4TeamFCC.length === 40, "The tea4TeamFCC variable should hold 40 cups of tea for the team.");' +- text: The tea4TeamFCC variable should hold cups of green tea. + testString: 'assert(tea4TeamFCC[0] === "greenTea", "The tea4TeamFCC variable should hold cups of green tea.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +/** + * A long process to prepare tea. + * @return {string} A cup of tea. + **/ +const prepareTea = () => 'greenTea'; + +/** + * Get given number of cups of tea. + * @param {number} numOfCups Number of required cups of tea. + * @return {Array} Given amount of tea cups. + **/ +const getTea = (numOfCups) => { + const teaCups = []; + + for(let cups = 1; cups <= numOfCups; cups += 1) { + const teaCup = prepareTea(); + teaCups.push(teaCup); + } + + return teaCups; +}; + +// Add your code below this line + +const tea4TeamFCC = null; // :( + +// Add your code above this line + +console.log(tea4TeamFCC); +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/functional-programming/Pass Arguments to Avoid External Dependence in a Function.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/functional-programming/Pass Arguments to Avoid External Dependence in a Function.md new file mode 100644 index 0000000000..c01fafc1f8 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/functional-programming/Pass Arguments to Avoid External Dependence in a Function.md @@ -0,0 +1,70 @@ +--- +id: 587d7b8e367417b2b2512b5f +title: Pass Arguments to Avoid External Dependence in a Function +challengeType: 1 +--- + +## Description +
    +The last challenge was a step closer to functional programming principles, but there is still something missing. +We didn't alter the global variable value, but the function incrementer would not work without the global variable fixedValue being there. +Another principle of functional programming is to always declare your dependencies explicitly. This means if a function depends on a variable or object being present, then pass that variable or object directly into the function as an argument. +There are several good consequences from this principle. The function is easier to test, you know exactly what input it takes, and it won't depend on anything else in your program. +This can give you more confidence when you alter, remove, or add new code. You would know what you can or cannot change and you can see where the potential traps are. +Finally, the function would always produce the same output for the same set of inputs, no matter what part of the code executes it. +
    + +## Instructions +
    +Let's update the incrementer function to clearly declare its dependencies. +Write the incrementer function so it takes an argument, and then increases the value by one. +
    + +## Tests +
    + +```yml +- text: Your function incrementer should not change the value of fixedValue. + testString: 'assert(fixedValue === 4, "Your function incrementer should not change the value of fixedValue.");' +- text: Your incrementer function should take a parameter. + testString: 'assert(code.match(/function\s+?incrementer\s*?\(.+?\)/g), "Your incrementer function should take a parameter.");' +- text: Your incrementer function should return a value that is one larger than the fixedValue value. + testString: 'assert(newValue === 5, "Your incrementer function should return a value that is one larger than the fixedValue value.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +// the global variable +var fixedValue = 4; + +// Add your code below this line +function incrementer () { + + + // Add your code above this line +} + +var newValue = incrementer(fixedValue); // Should equal 5 +console.log(fixedValue); // Should print 4 +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/functional-programming/Refactor Global Variables Out of Functions.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/functional-programming/Refactor Global Variables Out of Functions.md new file mode 100644 index 0000000000..232920149f --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/functional-programming/Refactor Global Variables Out of Functions.md @@ -0,0 +1,89 @@ +--- +id: 587d7b8f367417b2b2512b60 +title: Refactor Global Variables Out of Functions +challengeType: 1 +--- + +## Description +
    +So far, we have seen two distinct principles for functional programming: +1) Don't alter a variable or object - create new variables and objects and return them if need be from a function. +2) Declare function arguments - any computation inside a function depends only on the arguments, and not on any global object or variable. +Adding one to a number is not very exciting, but we can apply these principles when working with arrays or more complex objects. +
    + +## Instructions +
    +Refactor (rewrite) the code so the global array bookList is not changed inside either function. The add function should add the given bookName to the end of an array. The remove function should remove the given bookName from an array. Both functions should return an array, and any new parameters should be added before the bookName one. +
    + +## Tests +
    + +```yml +- text: 'bookList should not change and still equal ["The Hound of the Baskervilles", "On The Electrodynamics of Moving Bodies", "Philosophiæ Naturalis Principia Mathematica", "Disquisitiones Arithmeticae"].' + testString: 'assert(JSON.stringify(bookList) === JSON.stringify(["The Hound of the Baskervilles", "On The Electrodynamics of Moving Bodies", "Philosophiæ Naturalis Principia Mathematica", "Disquisitiones Arithmeticae"]), "bookList should not change and still equal ["The Hound of the Baskervilles", "On The Electrodynamics of Moving Bodies", "Philosophiæ Naturalis Principia Mathematica", "Disquisitiones Arithmeticae"].");' +- text: 'newBookList should equal ["The Hound of the Baskervilles", "On The Electrodynamics of Moving Bodies", "Philosophiæ Naturalis Principia Mathematica", "Disquisitiones Arithmeticae", "A Brief History of Time"].' + testString: 'assert(JSON.stringify(newBookList) === JSON.stringify(["The Hound of the Baskervilles", "On The Electrodynamics of Moving Bodies", "Philosophiæ Naturalis Principia Mathematica", "Disquisitiones Arithmeticae", "A Brief History of Time"]), "newBookList should equal ["The Hound of the Baskervilles", "On The Electrodynamics of Moving Bodies", "Philosophiæ Naturalis Principia Mathematica", "Disquisitiones Arithmeticae", "A Brief History of Time"].");' +- text: 'newerBookList should equal ["The Hound of the Baskervilles", "Philosophiæ Naturalis Principia Mathematica", "Disquisitiones Arithmeticae"].' + testString: 'assert(JSON.stringify(newerBookList) === JSON.stringify(["The Hound of the Baskervilles", "Philosophiæ Naturalis Principia Mathematica", "Disquisitiones Arithmeticae"]), "newerBookList should equal ["The Hound of the Baskervilles", "Philosophiæ Naturalis Principia Mathematica", "Disquisitiones Arithmeticae"].");' +- text: 'newestBookList should equal ["The Hound of the Baskervilles", "Philosophiæ Naturalis Principia Mathematica", "Disquisitiones Arithmeticae", "A Brief History of Time"].' + testString: 'assert(JSON.stringify(newestBookList) === JSON.stringify(["The Hound of the Baskervilles", "Philosophiæ Naturalis Principia Mathematica", "Disquisitiones Arithmeticae", "A Brief History of Time"]), "newestBookList should equal ["The Hound of the Baskervilles", "Philosophiæ Naturalis Principia Mathematica", "Disquisitiones Arithmeticae", "A Brief History of Time"].");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +// the global variable +var bookList = ["The Hound of the Baskervilles", "On The Electrodynamics of Moving Bodies", "Philosophiæ Naturalis Principia Mathematica", "Disquisitiones Arithmeticae"]; + +/* This function should add a book to the list and return the list */ +// New parameters should come before the bookName one + +// Add your code below this line +function add (bookName) { + + return bookList.push(bookName); + + // Add your code above this line +} + +/* This function should remove a book from the list and return the list */ +// New parameters should come before the bookName one + +// Add your code below this line +function remove (bookName) { + if (bookList.indexOf(bookName) >= 0) { + + return bookList.splice(0, 1, bookName); + + // Add your code above this line + } +} + +var newBookList = add(bookList, 'A Brief History of Time'); +var newerBookList = remove(bookList, 'On The Electrodynamics of Moving Bodies'); +var newestBookList = remove(add(bookList, 'A Brief History of Time'), 'On The Electrodynamics of Moving Bodies'); + +console.log(bookList); +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/functional-programming/Remove Elements from an Array Using slice Instead of splice.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/functional-programming/Remove Elements from an Array Using slice Instead of splice.md new file mode 100644 index 0000000000..2b0c1824e9 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/functional-programming/Remove Elements from an Array Using slice Instead of splice.md @@ -0,0 +1,65 @@ +--- +id: 9d7123c8c441eeafaeb5bdef +title: Remove Elements from an Array Using slice Instead of splice +challengeType: 1 +--- + +## Description +
    +A common pattern while working with arrays is when you want to remove items and keep the rest of the array. JavaScript offers the splice method for this, which takes arguments for the index of where to start removing items, then the number of items to remove. If the second argument is not provided, the default is to remove items through the end. However, the splice method mutates the original array it is called on. Here's an example: +
    var cities = ["Chicago", "Delhi", "Islamabad", "London", "Berlin"];
    cities.splice(3, 1); // Returns "London" and deletes it from the cities array
    // cities is now ["Chicago", "Delhi", "Islamabad", "Berlin"]
    +As we saw in the last challenge, the slice method does not mutate the original array, but returns a new one which can be saved into a variable. Recall that the slice method takes two arguments for the indices to begin and end the slice (the end is non-inclusive), and returns those items in a new array. Using the slice method instead of splice helps to avoid any array-mutating side effects. +
    + +## Instructions +
    +Rewrite the function nonMutatingSplice by using slice instead of splice. It should limit the provided cities array to a length of 3, and return a new array with only the first three items. +Do not mutate the original array provided to the function. +
    + +## Tests +
    + +```yml +- text: Your code should use the slice method. + testString: 'assert(code.match(/\.slice/g), "Your code should use the slice method.");' +- text: Your code should not use the splice method. + testString: 'assert(!code.match(/\.splice/g), "Your code should not use the splice method.");' +- text: The inputCities array should not change. + testString: 'assert(JSON.stringify(inputCities) === JSON.stringify(["Chicago", "Delhi", "Islamabad", "London", "Berlin"]), "The inputCities array should not change.");' +- text: 'nonMutatingSplice(["Chicago", "Delhi", "Islamabad", "London", "Berlin"]) should return ["Chicago", "Delhi", "Islamabad"].' + testString: 'assert(JSON.stringify(nonMutatingSplice(["Chicago", "Delhi", "Islamabad", "London", "Berlin"])) === JSON.stringify(["Chicago", "Delhi", "Islamabad"]), "nonMutatingSplice(["Chicago", "Delhi", "Islamabad", "London", "Berlin"]) should return ["Chicago", "Delhi", "Islamabad"].");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +function nonMutatingSplice(cities) { + // Add your code below this line + return cities.splice(3); + + // Add your code above this line +} +var inputCities = ["Chicago", "Delhi", "Islamabad", "London", "Berlin"]; +nonMutatingSplice(inputCities); +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/functional-programming/Return Part of an Array Using the slice Method.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/functional-programming/Return Part of an Array Using the slice Method.md new file mode 100644 index 0000000000..aaa2ff75bb --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/functional-programming/Return Part of an Array Using the slice Method.md @@ -0,0 +1,66 @@ +--- +id: 587d7b90367417b2b2512b65 +title: Return Part of an Array Using the slice Method +challengeType: 1 +--- + +## Description +
    +The slice method returns a copy of certain elements of an array. It can take two arguments, the first gives the index of where to begin the slice, the second is the index for where to end the slice (and it's non-inclusive). If the arguments are not provided, the default is to start at the beginning of the array through the end, which is an easy way to make a copy of the entire array. The slice method does not mutate the original array, but returns a new one. +Here's an example: +
    var arr = ["Cat", "Dog", "Tiger", "Zebra"];
    var newArray = arr.slice(1, 3);
    // Sets newArray to ["Dog", "Tiger"]
    +
    + +## Instructions +
    +Use the slice method in the sliceArray function to return part of the anim array given the provided beginSlice and endSlice indices. The function should return an array. +
    + +## Tests +
    + +```yml +- text: Your code should use the slice method. + testString: 'assert(code.match(/\.slice/g), "Your code should use the slice method.");' +- text: The inputAnim variable should not change. + testString: 'assert(JSON.stringify(inputAnim) === JSON.stringify(["Cat", "Dog", "Tiger", "Zebra", "Ant"]), "The inputAnim variable should not change.");' +- text: 'sliceArray(["Cat", "Dog", "Tiger", "Zebra", "Ant"], 1, 3) should return ["Dog", "Tiger"].' + testString: 'assert(JSON.stringify(sliceArray(["Cat", "Dog", "Tiger", "Zebra", "Ant"], 1, 3)) === JSON.stringify(["Dog", "Tiger"]), "sliceArray(["Cat", "Dog", "Tiger", "Zebra", "Ant"], 1, 3) should return ["Dog", "Tiger"].");' +- text: 'sliceArray(["Cat", "Dog", "Tiger", "Zebra", "Ant"], 0, 1) should return ["Cat"].' + testString: 'assert(JSON.stringify(sliceArray(["Cat", "Dog", "Tiger", "Zebra", "Ant"], 0, 1)) === JSON.stringify(["Cat"]), "sliceArray(["Cat", "Dog", "Tiger", "Zebra", "Ant"], 0, 1) should return ["Cat"].");' +- text: 'sliceArray(["Cat", "Dog", "Tiger", "Zebra", "Ant"], 1, 4) should return ["Dog", "Tiger", "Zebra"].' + testString: 'assert(JSON.stringify(sliceArray(["Cat", "Dog", "Tiger", "Zebra", "Ant"], 1, 4)) === JSON.stringify(["Dog", "Tiger", "Zebra"]), "sliceArray(["Cat", "Dog", "Tiger", "Zebra", "Ant"], 1, 4) should return ["Dog", "Tiger", "Zebra"].");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +function sliceArray(anim, beginSlice, endSlice) { + // Add your code below this line + + + // Add your code above this line +} +var inputAnim = ["Cat", "Dog", "Tiger", "Zebra", "Ant"]; +sliceArray(inputAnim, 1, 3); +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/functional-programming/Return a Sorted Array Without Changing the Original Array.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/functional-programming/Return a Sorted Array Without Changing the Original Array.md new file mode 100644 index 0000000000..36d0f10d55 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/functional-programming/Return a Sorted Array Without Changing the Original Array.md @@ -0,0 +1,62 @@ +--- +id: 587d7da9367417b2b2512b6a +title: Return a Sorted Array Without Changing the Original Array +challengeType: 1 +--- + +## Description +
    +A side effect of the sort method is that it changes the order of the elements in the original array. In other words, it mutates the array in place. One way to avoid this is to first concatenate an empty array to the one being sorted (remember that concat returns a new array), then run the sort method. +
    + +## Instructions +
    +Use the sort method in the nonMutatingSort function to sort the elements of an array in ascending order. The function should return a new array, and not mutate the globalArray variable. +
    + +## Tests +
    + +```yml +- text: Your code should use the sort method. + testString: 'assert(code.match(/\.sort/g), "Your code should use the sort method.");' +- text: Your code should use the concat method. + testString: 'assert(code.match(/\.concat/g), "Your code should use the concat method.");' +- text: The globalArray variable should not change. + testString: 'assert(JSON.stringify(globalArray) === JSON.stringify([5, 6, 3, 2, 9]), "The globalArray variable should not change.");' +- text: 'nonMutatingSort(globalArray) should return [2, 3, 5, 6, 9].' + testString: 'assert(JSON.stringify(nonMutatingSort(globalArray)) === JSON.stringify([2, 3, 5, 6, 9]), "nonMutatingSort(globalArray) should return [2, 3, 5, 6, 9].");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +var globalArray = [5, 6, 3, 2, 9]; +function nonMutatingSort(arr) { + // Add your code below this line + + + // Add your code above this line +} +nonMutatingSort(globalArray); +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/functional-programming/Sort an Array Alphabetically using the sort Method.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/functional-programming/Sort an Array Alphabetically using the sort Method.md new file mode 100644 index 0000000000..a322cb6d60 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/functional-programming/Sort an Array Alphabetically using the sort Method.md @@ -0,0 +1,64 @@ +--- +id: 587d7da9367417b2b2512b69 +title: Sort an Array Alphabetically using the sort Method +challengeType: 1 +--- + +## Description +
    +The sort method sorts the elements of an array according to the callback function. +For example: +
    function ascendingOrder(arr) {
      return arr.sort(function(a, b) {
        return a - b;
      });
    }
    ascendingOrder([1, 5, 2, 3, 4]);
    // Returns [1, 2, 3, 4, 5]

    function reverseAlpha(arr) {
      return arr.sort(function(a, b) {
        return a < b;
      });
    }
    reverseAlpha(['l', 'h', 'z', 'b', 's']);
    // Returns ['z', 's', 'l', 'h', 'b']
    +Note: It's encouraged to provide a callback function to specify how to sort the array items. JavaScript's default sorting method is by string Unicode point value, which may return unexpected results. +
    + +## Instructions +
    +Use the sort method in the alphabeticalOrder function to sort the elements of arr in alphabetical order. +
    + +## Tests +
    + +```yml +- text: Your code should use the sort method. + testString: 'assert(code.match(/\.sort/g), "Your code should use the sort method.");' +- text: 'alphabeticalOrder(["a", "d", "c", "a", "z", "g"]) should return ["a", "a", "c", "d", "g", "z"].' + testString: 'assert(JSON.stringify(alphabeticalOrder(["a", "d", "c", "a", "z", "g"])) === JSON.stringify(["a", "a", "c", "d", "g", "z"]), "alphabeticalOrder(["a", "d", "c", "a", "z", "g"]) should return ["a", "a", "c", "d", "g", "z"].");' +- text: 'alphabeticalOrder(["x", "h", "a", "m", "n", "m"]) should return ["a", "h", "m", "m", "n", "x"].' + testString: 'assert(JSON.stringify(alphabeticalOrder(["x", "h", "a", "m", "n", "m"])) === JSON.stringify(["a", "h", "m", "m", "n", "x"]), "alphabeticalOrder(["x", "h", "a", "m", "n", "m"]) should return ["a", "h", "m", "m", "n", "x"].");' +- text: 'alphabeticalOrder(["a", "a", "a", "a", "x", "t"]) should return ["a", "a", "a", "a", "t", "x"].' + testString: 'assert(JSON.stringify(alphabeticalOrder(["a", "a", "a", "a", "x", "t"])) === JSON.stringify(["a", "a", "a", "a", "t", "x"]), "alphabeticalOrder(["a", "a", "a", "a", "x", "t"]) should return ["a", "a", "a", "a", "t", "x"].");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +function alphabeticalOrder(arr) { + // Add your code below this line + + + // Add your code above this line +} +alphabeticalOrder(["a", "d", "c", "a", "z", "g"]); +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/functional-programming/Split a String into an Array Using the split Method.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/functional-programming/Split a String into an Array Using the split Method.md new file mode 100644 index 0000000000..e0ebdcde8b --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/functional-programming/Split a String into an Array Using the split Method.md @@ -0,0 +1,64 @@ +--- +id: 587d7daa367417b2b2512b6b +title: Split a String into an Array Using the split Method +challengeType: 1 +--- + +## Description +
    +The split method splits a string into an array of strings. It takes an argument for the delimiter, which can be a character to use to break up the string or a regular expression. For example, if the delimiter is a space, you get an array of words, and if the delimiter is an empty string, you get an array of each character in the string. +Here are two examples that split one string by spaces, then another by digits using a regular expression: +
    var str = "Hello World";
    var bySpace = str.split(" ");
    // Sets bySpace to ["Hello", "World"]

    var otherString = "How9are7you2today";
    var byDigits = otherString.split(/\d/);
    // Sets byDigits to ["How", "are", "you", "today"]
    +Since strings are immutable, the split method makes it easier to work with them. +
    + +## Instructions +
    +Use the split method inside the splitify function to split str into an array of words. The function should return the array. Note that the words are not always separated by spaces, and the array should not contain punctuation. +
    + +## Tests +
    + +```yml +- text: Your code should use the split method. + testString: 'assert(code.match(/\.split/g), "Your code should use the split method.");' +- text: 'splitify("Hello World,I-am code") should return ["Hello", "World", "I", "am", "code"].' + testString: 'assert(JSON.stringify(splitify("Hello World,I-am code")) === JSON.stringify(["Hello", "World", "I", "am", "code"]), "splitify("Hello World,I-am code") should return ["Hello", "World", "I", "am", "code"].");' +- text: 'splitify("Earth-is-our home") should return ["Earth", "is", "our", "home"].' + testString: 'assert(JSON.stringify(splitify("Earth-is-our home")) === JSON.stringify(["Earth", "is", "our", "home"]), "splitify("Earth-is-our home") should return ["Earth", "is", "our", "home"].");' +- text: 'splitify("This.is.a-sentence") should return ["This", "is", "a", "sentence"].' + testString: 'assert(JSON.stringify(splitify("This.is.a-sentence")) === JSON.stringify(["This", "is", "a", "sentence"]), "splitify("This.is.a-sentence") should return ["This", "is", "a", "sentence"].");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +function splitify(str) { + // Add your code below this line + + + // Add your code above this line +} +splitify("Hello World,I-am code"); +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/functional-programming/Understand Functional Programming Terminology.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/functional-programming/Understand Functional Programming Terminology.md new file mode 100644 index 0000000000..3bc24c3570 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/functional-programming/Understand Functional Programming Terminology.md @@ -0,0 +1,101 @@ +--- +id: 587d7b8e367417b2b2512b5c +title: Understand Functional Programming Terminology +challengeType: 1 +--- + +## Description +
    +The FCC Team had a mood swing and now wants two types of tea: green tea and black tea. General Fact: Client mood swings are pretty common. +With that information, we'll need to revisit the getTea function from last challenge to handle various tea requests. We can modify getTea to accept a function as a parameter to be able to change the type of tea it prepares. This makes getTea more flexible, and gives the programmer more control when client requests change. +But first, let's cover some functional terminology: +Callbacks are the functions that are slipped or passed into another function to decide the invocation of that function. You may have seen them passed to other methods, for example in filter, the callback function tells JavaScript the criteria for how to filter an array. +Functions that can be assigned to a variable, passed into another function, or returned from another function just like any other normal value, are called first class functions. In JavaScript, all functions are first class functions. +The functions that take a function as an argument, or return a function as a return value are called higher order functions. +When the functions are passed in to another function or returned from another function, then those functions which gets passed in or returned can be called a lambda. +
    + +## Instructions +
    +Prepare 27 cups of green tea and 13 cups of black tea and store them in tea4GreenTeamFCC and tea4BlackTeamFCC variables, respectively. Note that the getTea function has been modified so it now takes a function as the first argument. +Note: The data (the number of cups of tea) is supplied as the last argument. We'll discuss this more in later lessons. +
    + +## Tests +
    + +```yml +- text: The tea4GreenTeamFCC variable should hold 27 cups of green tea for the team. + testString: 'assert(tea4GreenTeamFCC.length === 27, "The tea4GreenTeamFCC variable should hold 27 cups of green tea for the team.");' +- text: The tea4GreenTeamFCC variable should hold cups of green tea. + testString: 'assert(tea4GreenTeamFCC[0] === "greenTea", "The tea4GreenTeamFCC variable should hold cups of green tea.");' +- text: The tea4BlackTeamFCC variable should hold 13 cups of black tea. + testString: 'assert(tea4BlackTeamFCC.length === 13, "The tea4BlackTeamFCC variable should hold 13 cups of black tea.");' +- text: The tea4BlackTeamFCC variable should hold cups of black tea. + testString: 'assert(tea4BlackTeamFCC[0] === "blackTea", "The tea4BlackTeamFCC variable should hold cups of black tea.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +/** + * A long process to prepare green tea. + * @return {string} A cup of green tea. + **/ +const prepareGreenTea = () => 'greenTea'; + +/** + * A long process to prepare black tea. + * @return {string} A cup of black tea. + **/ +const prepareBlackTea = () => 'blackTea'; + +/** + * Get given number of cups of tea. + * @param {function():string} prepareTea The type of tea preparing function. + * @param {number} numOfCups Number of required cups of tea. + * @return {Array} Given amount of tea cups. + **/ +const getTea = (prepareTea, numOfCups) => { + const teaCups = []; + + for(let cups = 1; cups <= numOfCups; cups += 1) { + const teaCup = prepareTea(); + teaCups.push(teaCup); + } + + return teaCups; +}; + +// Add your code below this line + +const tea4GreenTeamFCC = null; // :( +const tea4BlackTeamFCC = null; // :( + +// Add your code above this line + +console.log( + tea4GreenTeamFCC, + tea4BlackTeamFCC +); +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/functional-programming/Understand the Hazards of Using Imperative Code.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/functional-programming/Understand the Hazards of Using Imperative Code.md new file mode 100644 index 0000000000..e9cebaf9e1 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/functional-programming/Understand the Hazards of Using Imperative Code.md @@ -0,0 +1,96 @@ +--- +id: 587d7b8e367417b2b2512b5d +title: Understand the Hazards of Using Imperative Code +challengeType: 1 +--- + +## Description +
    +Functional programming is a good habit. It keeps your code easy to manage, and saves you from sneaky bugs. But before we get there, let's look at an imperative approach to programming to highlight where you may have issues. +In English (and many other languages), the imperative tense is used to give commands. Similarly, an imperative style in programming is one that gives the computer a set of statements to perform a task. +Often the statements change the state of the program, like updating global variables. A classic example is writing a for loop that gives exact directions to iterate over the indices of an array. +In contrast, functional programming is a form of declarative programming. You tell the computer what you want done by calling a method or function. +JavaScript offers many predefined methods that handle common tasks so you don't need to write out how the computer should perform them. For example, instead of using the for loop mentioned above, you could call the map method which handles the details of iterating over an array. This helps to avoid semantic errors, like the "Off By One Errors" that were covered in the Debugging section. +Consider the scenario: you are browsing the web in your browser, and want to track the tabs you have opened. Let's try to model this using some simple object-oriented code. +A Window object is made up of tabs, and you usually have more than one Window open. The titles of each open site in each Window object is held in an array. After working in the browser (opening new tabs, merging windows, and closing tabs), you want to print the tabs that are still open. Closed tabs are removed from the array and new tabs (for simplicity) get added to the end of it. +The code editor shows an implementation of this functionality with functions for tabOpen(), tabClose(), and join(). The array tabs is part of the Window object that stores the name of the open pages. +

    Instructions

    +Run the code in the editor. It's using a method that has side effects in the program, causing incorrect output. The final list of open tabs should be ['FB', 'Gitter', 'Reddit', 'Twitter', 'Medium', 'new tab', 'Netflix', 'YouTube', 'Vine', 'GMail', 'Work mail', 'Docs', 'freeCodeCamp', 'new tab'] but the output will be slightly different. +Work through the code and see if you can figure out the problem, then advance to the next challenge to learn more. +

    + +## Instructions +
    + +
    + +## Tests +
    + +```yml +- text: Move ahead to understand the error. + testString: 'assert(true, "Move ahead to understand the error.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +// tabs is an array of titles of each site open within the window +var Window = function(tabs) { + this.tabs = tabs; // we keep a record of the array inside the object +}; + +// When you join two windows into one window +Window.prototype.join = function (otherWindow) { + this.tabs = this.tabs.concat(otherWindow.tabs); + return this; +}; + +// When you open a new tab at the end +Window.prototype.tabOpen = function (tab) { + this.tabs.push('new tab'); // let's open a new tab for now + return this; +}; + +// When you close a tab +Window.prototype.tabClose = function (index) { + var tabsBeforeIndex = this.tabs.splice(0, index); // get the tabs before the tab + var tabsAfterIndex = this.tabs.splice(index); // get the tabs after the tab + + this.tabs = tabsBeforeIndex.concat(tabsAfterIndex); // join them together + return this; + }; + +// Let's create three browser windows +var workWindow = new Window(['GMail', 'Inbox', 'Work mail', 'Docs', 'freeCodeCamp']); // Your mailbox, drive, and other work sites +var socialWindow = new Window(['FB', 'Gitter', 'Reddit', 'Twitter', 'Medium']); // Social sites +var videoWindow = new Window(['Netflix', 'YouTube', 'Vimeo', 'Vine']); // Entertainment sites + +// Now perform the tab opening, closing, and other operations +var finalTabs = socialWindow + .tabOpen() // Open a new tab for cat memes + .join(videoWindow.tabClose(2)) // Close third tab in video window, and join + .join(workWindow.tabClose(1).tabOpen()); + +alert(finalTabs.tabs); +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/functional-programming/Use the every Method to Check that Every Element in an Array Meets a Criteria.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/functional-programming/Use the every Method to Check that Every Element in an Array Meets a Criteria.md new file mode 100644 index 0000000000..fd9cc3462f --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/functional-programming/Use the every Method to Check that Every Element in an Array Meets a Criteria.md @@ -0,0 +1,63 @@ +--- +id: 587d7dab367417b2b2512b6e +title: Use the every Method to Check that Every Element in an Array Meets a Criteria +challengeType: 1 +--- + +## Description +
    +The every method works with arrays to check if every element passes a particular test. It returns a Boolean value - true if all values meet the criteria, false if not. +For example, the following code would check if every element in the numbers array is less than 10: +
    var numbers = [1, 5, 8, 0, 10, 11];
    numbers.every(function(currentValue) {
      return currentValue < 10;
    });
    // Returns false
    +
    + +## Instructions +
    +Use the every method inside the checkPositive function to check if every element in arr is positive. The function should return a Boolean value. +
    + +## Tests +
    + +```yml +- text: Your code should use the every method. + testString: 'assert(code.match(/\.every/g), "Your code should use the every method.");' +- text: 'checkPositive([1, 2, 3, -4, 5]) should return false.' + testString: 'assert(!checkPositive([1, 2, 3, -4, 5]), "checkPositive([1, 2, 3, -4, 5]) should return false.");' +- text: 'checkPositive([1, 2, 3, 4, 5]) should return true.' + testString: 'assert(checkPositive([1, 2, 3, 4, 5]), "checkPositive([1, 2, 3, 4, 5]) should return true.");' +- text: 'checkPositive([1, -2, 3, -4, 5]) should return false.' + testString: 'assert(!checkPositive([1, -2, 3, -4, 5]), "checkPositive([1, -2, 3, -4, 5]) should return false.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +function checkPositive(arr) { + // Add your code below this line + + + // Add your code above this line +} +checkPositive([1, 2, 3, -4, 5]); +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/functional-programming/Use the filter Method to Extract Data from an Array.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/functional-programming/Use the filter Method to Extract Data from an Array.md new file mode 100644 index 0000000000..6aa05119ef --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/functional-programming/Use the filter Method to Extract Data from an Array.md @@ -0,0 +1,176 @@ +--- +id: 587d7b8f367417b2b2512b63 +title: Use the filter Method to Extract Data from an Array +challengeType: 1 +--- + +## Description +
    +Another useful array function is Array.prototype.filter(), or simply filter(). The filter method returns a new array which is at most as long as the original array, but usually has fewer items. +Filter doesn't alter the original array, just like map. It takes a callback function that applies the logic inside the callback on each element of the array. If an element returns true based on the criteria in the callback function, then it is included in the new array. +
    + +## Instructions +
    +The variable watchList holds an array of objects with information on several movies. Use a combination of filter and map to return a new array of objects with only title and rating keys, but where imdbRating is greater than or equal to 8.0. Note that the rating values are saved as strings in the object and you may want to convert them into numbers to perform mathematical operations on them. +
    + +## Tests +
    + +```yml +- text: The watchList variable should not change. + testString: 'assert(watchList[0].Title === "Inception" && watchList[4].Director == "James Cameron", "The watchList variable should not change.");' +- text: Your code should use the filter method. + testString: 'assert(code.match(/\.filter/g), "Your code should use the filter method.");' +- text: Your code should not use a for loop. + testString: 'assert(!code.match(/for\s*?\(.+?\)/g), "Your code should not use a for loop.");' +- text: 'filteredList should equal [{"title": "Inception","rating": "8.8"},{"title": "Interstellar","rating": "8.6"},{"title": "The Dark Knight","rating": "9.0"},{"title": "Batman Begins","rating": "8.3"}].' + testString: 'assert.deepEqual(filteredList, [{"title": "Inception","rating": "8.8"},{"title": "Interstellar","rating": "8.6"},{"title": "The Dark Knight","rating": "9.0"},{"title": "Batman Begins","rating": "8.3"}], "filteredList should equal [{"title": "Inception","rating": "8.8"},{"title": "Interstellar","rating": "8.6"},{"title": "The Dark Knight","rating": "9.0"},{"title": "Batman Begins","rating": "8.3"}].");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +// the global variable +var watchList = [ + { + "Title": "Inception", + "Year": "2010", + "Rated": "PG-13", + "Released": "16 Jul 2010", + "Runtime": "148 min", + "Genre": "Action, Adventure, Crime", + "Director": "Christopher Nolan", + "Writer": "Christopher Nolan", + "Actors": "Leonardo DiCaprio, Joseph Gordon-Levitt, Ellen Page, Tom Hardy", + "Plot": "A thief, who steals corporate secrets through use of dream-sharing technology, is given the inverse task of planting an idea into the mind of a CEO.", + "Language": "English, Japanese, French", + "Country": "USA, UK", + "Awards": "Won 4 Oscars. Another 143 wins & 198 nominations.", + "Poster": "http://ia.media-imdb.com/images/M/MV5BMjAxMzY3NjcxNF5BMl5BanBnXkFtZTcwNTI5OTM0Mw@@._V1_SX300.jpg", + "Metascore": "74", + "imdbRating": "8.8", + "imdbVotes": "1,446,708", + "imdbID": "tt1375666", + "Type": "movie", + "Response": "True" + }, + { + "Title": "Interstellar", + "Year": "2014", + "Rated": "PG-13", + "Released": "07 Nov 2014", + "Runtime": "169 min", + "Genre": "Adventure, Drama, Sci-Fi", + "Director": "Christopher Nolan", + "Writer": "Jonathan Nolan, Christopher Nolan", + "Actors": "Ellen Burstyn, Matthew McConaughey, Mackenzie Foy, John Lithgow", + "Plot": "A team of explorers travel through a wormhole in space in an attempt to ensure humanity's survival.", + "Language": "English", + "Country": "USA, UK", + "Awards": "Won 1 Oscar. Another 39 wins & 132 nominations.", + "Poster": "http://ia.media-imdb.com/images/M/MV5BMjIxNTU4MzY4MF5BMl5BanBnXkFtZTgwMzM4ODI3MjE@._V1_SX300.jpg", + "Metascore": "74", + "imdbRating": "8.6", + "imdbVotes": "910,366", + "imdbID": "tt0816692", + "Type": "movie", + "Response": "True" + }, + { + "Title": "The Dark Knight", + "Year": "2008", + "Rated": "PG-13", + "Released": "18 Jul 2008", + "Runtime": "152 min", + "Genre": "Action, Adventure, Crime", + "Director": "Christopher Nolan", + "Writer": "Jonathan Nolan (screenplay), Christopher Nolan (screenplay), Christopher Nolan (story), David S. Goyer (story), Bob Kane (characters)", + "Actors": "Christian Bale, Heath Ledger, Aaron Eckhart, Michael Caine", + "Plot": "When the menace known as the Joker wreaks havoc and chaos on the people of Gotham, the caped crusader must come to terms with one of the greatest psychological tests of his ability to fight injustice.", + "Language": "English, Mandarin", + "Country": "USA, UK", + "Awards": "Won 2 Oscars. Another 146 wins & 142 nominations.", + "Poster": "http://ia.media-imdb.com/images/M/MV5BMTMxNTMwODM0NF5BMl5BanBnXkFtZTcwODAyMTk2Mw@@._V1_SX300.jpg", + "Metascore": "82", + "imdbRating": "9.0", + "imdbVotes": "1,652,832", + "imdbID": "tt0468569", + "Type": "movie", + "Response": "True" + }, + { + "Title": "Batman Begins", + "Year": "2005", + "Rated": "PG-13", + "Released": "15 Jun 2005", + "Runtime": "140 min", + "Genre": "Action, Adventure", + "Director": "Christopher Nolan", + "Writer": "Bob Kane (characters), David S. Goyer (story), Christopher Nolan (screenplay), David S. Goyer (screenplay)", + "Actors": "Christian Bale, Michael Caine, Liam Neeson, Katie Holmes", + "Plot": "After training with his mentor, Batman begins his fight to free crime-ridden Gotham City from the corruption that Scarecrow and the League of Shadows have cast upon it.", + "Language": "English, Urdu, Mandarin", + "Country": "USA, UK", + "Awards": "Nominated for 1 Oscar. Another 15 wins & 66 nominations.", + "Poster": "http://ia.media-imdb.com/images/M/MV5BNTM3OTc0MzM2OV5BMl5BanBnXkFtZTYwNzUwMTI3._V1_SX300.jpg", + "Metascore": "70", + "imdbRating": "8.3", + "imdbVotes": "972,584", + "imdbID": "tt0372784", + "Type": "movie", + "Response": "True" + }, + { + "Title": "Avatar", + "Year": "2009", + "Rated": "PG-13", + "Released": "18 Dec 2009", + "Runtime": "162 min", + "Genre": "Action, Adventure, Fantasy", + "Director": "James Cameron", + "Writer": "James Cameron", + "Actors": "Sam Worthington, Zoe Saldana, Sigourney Weaver, Stephen Lang", + "Plot": "A paraplegic marine dispatched to the moon Pandora on a unique mission becomes torn between following his orders and protecting the world he feels is his home.", + "Language": "English, Spanish", + "Country": "USA, UK", + "Awards": "Won 3 Oscars. Another 80 wins & 121 nominations.", + "Poster": "http://ia.media-imdb.com/images/M/MV5BMTYwOTEwNjAzMl5BMl5BanBnXkFtZTcwODc5MTUwMw@@._V1_SX300.jpg", + "Metascore": "83", + "imdbRating": "7.9", + "imdbVotes": "876,575", + "imdbID": "tt0499549", + "Type": "movie", + "Response": "True" + } +]; + +// Add your code below this line + +var filteredList; + +// Add your code above this line + +console.log(filteredList); +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/functional-programming/Use the map Method to Extract Data from an Array.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/functional-programming/Use the map Method to Extract Data from an Array.md new file mode 100644 index 0000000000..809aafe32f --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/functional-programming/Use the map Method to Extract Data from an Array.md @@ -0,0 +1,182 @@ +--- +id: 587d7b8f367417b2b2512b61 +title: Use the map Method to Extract Data from an Array +challengeType: 1 +--- + +## Description +
    +So far we have learned to use pure functions to avoid side effects in a program. Also, we have seen the value in having a function only depend on its input arguments. +This is only the beginning. As its name suggests, functional programming is centered around a theory of functions. +It would make sense to be able to pass them as arguments to other functions, and return a function from another function. Functions are considered First Class Objects in JavaScript, which means they can be used like any other object. They can be saved in variables, stored in an object, or passed as function arguments. +Let's start with some simple array functions, which are methods on the array object prototype. In this exercise we are looking at Array.prototype.map(), or more simply map. +Remember that the map method is a way to iterate over each item in an array. It creates a new array (without changing the original one) after applying a callback function to every element. +
    + +## Instructions +
    +The watchList array holds objects with information on several movies. Use map to pull the title and rating from watchList and save the new array in the rating variable. The code in the editor currently uses a for loop to do this, replace the loop functionality with your map expression. +
    + +## Tests +
    + +```yml +- text: The watchList variable should not change. + testString: 'assert(watchList[0].Title === "Inception" && watchList[4].Director == "James Cameron", "The watchList variable should not change.");' +- text: Your code should not use a for loop. + testString: 'assert(!code.match(/for\s*?\(.+?\)/g), "Your code should not use a for loop.");' +- text: Your code should use the map method. + testString: 'assert(code.match(/\.map/g), "Your code should use the map method.");' +- text: 'rating should equal [{"title":"Inception","rating":"8.8"},{"title":"Interstellar","rating":"8.6"},{"title":"The Dark Knight","rating":"9.0"},{"title":"Batman Begins","rating":"8.3"},{"title":"Avatar","rating":"7.9"}].' + testString: 'assert(JSON.stringify(rating) === JSON.stringify([{"title":"Inception","rating":"8.8"},{"title":"Interstellar","rating":"8.6"},{"title":"The Dark Knight","rating":"9.0"},{"title":"Batman Begins","rating":"8.3"},{"title":"Avatar","rating":"7.9"}]), "rating should equal [{"title":"Inception","rating":"8.8"},{"title":"Interstellar","rating":"8.6"},{"title":"The Dark Knight","rating":"9.0"},{"title":"Batman Begins","rating":"8.3"},{"title":"Avatar","rating":"7.9"}].");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +// the global variable +var watchList = [ + { + "Title": "Inception", + "Year": "2010", + "Rated": "PG-13", + "Released": "16 Jul 2010", + "Runtime": "148 min", + "Genre": "Action, Adventure, Crime", + "Director": "Christopher Nolan", + "Writer": "Christopher Nolan", + "Actors": "Leonardo DiCaprio, Joseph Gordon-Levitt, Ellen Page, Tom Hardy", + "Plot": "A thief, who steals corporate secrets through use of dream-sharing technology, is given the inverse task of planting an idea into the mind of a CEO.", + "Language": "English, Japanese, French", + "Country": "USA, UK", + "Awards": "Won 4 Oscars. Another 143 wins & 198 nominations.", + "Poster": "http://ia.media-imdb.com/images/M/MV5BMjAxMzY3NjcxNF5BMl5BanBnXkFtZTcwNTI5OTM0Mw@@._V1_SX300.jpg", + "Metascore": "74", + "imdbRating": "8.8", + "imdbVotes": "1,446,708", + "imdbID": "tt1375666", + "Type": "movie", + "Response": "True" + }, + { + "Title": "Interstellar", + "Year": "2014", + "Rated": "PG-13", + "Released": "07 Nov 2014", + "Runtime": "169 min", + "Genre": "Adventure, Drama, Sci-Fi", + "Director": "Christopher Nolan", + "Writer": "Jonathan Nolan, Christopher Nolan", + "Actors": "Ellen Burstyn, Matthew McConaughey, Mackenzie Foy, John Lithgow", + "Plot": "A team of explorers travel through a wormhole in space in an attempt to ensure humanity's survival.", + "Language": "English", + "Country": "USA, UK", + "Awards": "Won 1 Oscar. Another 39 wins & 132 nominations.", + "Poster": "http://ia.media-imdb.com/images/M/MV5BMjIxNTU4MzY4MF5BMl5BanBnXkFtZTgwMzM4ODI3MjE@._V1_SX300.jpg", + "Metascore": "74", + "imdbRating": "8.6", + "imdbVotes": "910,366", + "imdbID": "tt0816692", + "Type": "movie", + "Response": "True" + }, + { + "Title": "The Dark Knight", + "Year": "2008", + "Rated": "PG-13", + "Released": "18 Jul 2008", + "Runtime": "152 min", + "Genre": "Action, Adventure, Crime", + "Director": "Christopher Nolan", + "Writer": "Jonathan Nolan (screenplay), Christopher Nolan (screenplay), Christopher Nolan (story), David S. Goyer (story), Bob Kane (characters)", + "Actors": "Christian Bale, Heath Ledger, Aaron Eckhart, Michael Caine", + "Plot": "When the menace known as the Joker wreaks havoc and chaos on the people of Gotham, the caped crusader must come to terms with one of the greatest psychological tests of his ability to fight injustice.", + "Language": "English, Mandarin", + "Country": "USA, UK", + "Awards": "Won 2 Oscars. Another 146 wins & 142 nominations.", + "Poster": "http://ia.media-imdb.com/images/M/MV5BMTMxNTMwODM0NF5BMl5BanBnXkFtZTcwODAyMTk2Mw@@._V1_SX300.jpg", + "Metascore": "82", + "imdbRating": "9.0", + "imdbVotes": "1,652,832", + "imdbID": "tt0468569", + "Type": "movie", + "Response": "True" + }, + { + "Title": "Batman Begins", + "Year": "2005", + "Rated": "PG-13", + "Released": "15 Jun 2005", + "Runtime": "140 min", + "Genre": "Action, Adventure", + "Director": "Christopher Nolan", + "Writer": "Bob Kane (characters), David S. Goyer (story), Christopher Nolan (screenplay), David S. Goyer (screenplay)", + "Actors": "Christian Bale, Michael Caine, Liam Neeson, Katie Holmes", + "Plot": "After training with his mentor, Batman begins his fight to free crime-ridden Gotham City from the corruption that Scarecrow and the League of Shadows have cast upon it.", + "Language": "English, Urdu, Mandarin", + "Country": "USA, UK", + "Awards": "Nominated for 1 Oscar. Another 15 wins & 66 nominations.", + "Poster": "http://ia.media-imdb.com/images/M/MV5BNTM3OTc0MzM2OV5BMl5BanBnXkFtZTYwNzUwMTI3._V1_SX300.jpg", + "Metascore": "70", + "imdbRating": "8.3", + "imdbVotes": "972,584", + "imdbID": "tt0372784", + "Type": "movie", + "Response": "True" + }, + { + "Title": "Avatar", + "Year": "2009", + "Rated": "PG-13", + "Released": "18 Dec 2009", + "Runtime": "162 min", + "Genre": "Action, Adventure, Fantasy", + "Director": "James Cameron", + "Writer": "James Cameron", + "Actors": "Sam Worthington, Zoe Saldana, Sigourney Weaver, Stephen Lang", + "Plot": "A paraplegic marine dispatched to the moon Pandora on a unique mission becomes torn between following his orders and protecting the world he feels is his home.", + "Language": "English, Spanish", + "Country": "USA, UK", + "Awards": "Won 3 Oscars. Another 80 wins & 121 nominations.", + "Poster": "http://ia.media-imdb.com/images/M/MV5BMTYwOTEwNjAzMl5BMl5BanBnXkFtZTcwODc5MTUwMw@@._V1_SX300.jpg", + "Metascore": "83", + "imdbRating": "7.9", + "imdbVotes": "876,575", + "imdbID": "tt0499549", + "Type": "movie", + "Response": "True" + } +]; + +// Add your code below this line + +var rating = []; +for(var i=0; i < watchList.length; i++){ + rating.push({title: watchList[i]["Title"], rating: watchList[i]["imdbRating"]}); +} + +// Add your code above this line + +console.log(rating); +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/functional-programming/Use the reduce Method to Analyze Data.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/functional-programming/Use the reduce Method to Analyze Data.md new file mode 100644 index 0000000000..0033b06c98 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/functional-programming/Use the reduce Method to Analyze Data.md @@ -0,0 +1,178 @@ +--- +id: 587d7da9367417b2b2512b68 +title: Use the reduce Method to Analyze Data +challengeType: 1 +--- + +## Description +
    +Array.prototype.reduce(), or simply reduce(), is the most general of all array operations in JavaScript. You can solve almost any array processing problem using the reduce method. +This is not the case with the filter and map methods since they do not allow interaction between two different elements of the array. For example, if you want to compare elements of the array, or add them together, filter or map could not process that. +The reduce method allows for more general forms of array processing, and it's possible to show that both filter and map can be derived as a special application of reduce. +However, before we get there, let's practice using reduce first. +
    + +## Instructions +
    +The variable watchList holds an array of objects with information on several movies. Use reduce to find the average IMDB rating of the movies directed by Christopher Nolan. Recall from prior challenges how to filter data and map over it to pull what you need. You may need to create other variables, but save the final average into the variable averageRating. Note that the rating values are saved as strings in the object and need to be converted into numbers before they are used in any mathematical operations. +
    + +## Tests +
    + +```yml +- text: The watchList variable should not change. + testString: 'assert(watchList[0].Title === "Inception" && watchList[4].Director == "James Cameron", "The watchList variable should not change.");' +- text: Your code should use the reduce method. + testString: 'assert(code.match(/\.reduce/g), "Your code should use the reduce method.");' +- text: The averageRating should equal 8.675. + testString: 'assert(averageRating == 8.675, "The averageRating should equal 8.675.");' +- text: Your code should not use a for loop. + testString: 'assert(!code.match(/for\s*?\(.*\)/g), "Your code should not use a for loop.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +// the global variable +var watchList = [ + { + "Title": "Inception", + "Year": "2010", + "Rated": "PG-13", + "Released": "16 Jul 2010", + "Runtime": "148 min", + "Genre": "Action, Adventure, Crime", + "Director": "Christopher Nolan", + "Writer": "Christopher Nolan", + "Actors": "Leonardo DiCaprio, Joseph Gordon-Levitt, Ellen Page, Tom Hardy", + "Plot": "A thief, who steals corporate secrets through use of dream-sharing technology, is given the inverse task of planting an idea into the mind of a CEO.", + "Language": "English, Japanese, French", + "Country": "USA, UK", + "Awards": "Won 4 Oscars. Another 143 wins & 198 nominations.", + "Poster": "http://ia.media-imdb.com/images/M/MV5BMjAxMzY3NjcxNF5BMl5BanBnXkFtZTcwNTI5OTM0Mw@@._V1_SX300.jpg", + "Metascore": "74", + "imdbRating": "8.8", + "imdbVotes": "1,446,708", + "imdbID": "tt1375666", + "Type": "movie", + "Response": "True" + }, + { + "Title": "Interstellar", + "Year": "2014", + "Rated": "PG-13", + "Released": "07 Nov 2014", + "Runtime": "169 min", + "Genre": "Adventure, Drama, Sci-Fi", + "Director": "Christopher Nolan", + "Writer": "Jonathan Nolan, Christopher Nolan", + "Actors": "Ellen Burstyn, Matthew McConaughey, Mackenzie Foy, John Lithgow", + "Plot": "A team of explorers travel through a wormhole in space in an attempt to ensure humanity's survival.", + "Language": "English", + "Country": "USA, UK", + "Awards": "Won 1 Oscar. Another 39 wins & 132 nominations.", + "Poster": "http://ia.media-imdb.com/images/M/MV5BMjIxNTU4MzY4MF5BMl5BanBnXkFtZTgwMzM4ODI3MjE@._V1_SX300.jpg", + "Metascore": "74", + "imdbRating": "8.6", + "imdbVotes": "910,366", + "imdbID": "tt0816692", + "Type": "movie", + "Response": "True" + }, + { + "Title": "The Dark Knight", + "Year": "2008", + "Rated": "PG-13", + "Released": "18 Jul 2008", + "Runtime": "152 min", + "Genre": "Action, Adventure, Crime", + "Director": "Christopher Nolan", + "Writer": "Jonathan Nolan (screenplay), Christopher Nolan (screenplay), Christopher Nolan (story), David S. Goyer (story), Bob Kane (characters)", + "Actors": "Christian Bale, Heath Ledger, Aaron Eckhart, Michael Caine", + "Plot": "When the menace known as the Joker wreaks havoc and chaos on the people of Gotham, the caped crusader must come to terms with one of the greatest psychological tests of his ability to fight injustice.", + "Language": "English, Mandarin", + "Country": "USA, UK", + "Awards": "Won 2 Oscars. Another 146 wins & 142 nominations.", + "Poster": "http://ia.media-imdb.com/images/M/MV5BMTMxNTMwODM0NF5BMl5BanBnXkFtZTcwODAyMTk2Mw@@._V1_SX300.jpg", + "Metascore": "82", + "imdbRating": "9.0", + "imdbVotes": "1,652,832", + "imdbID": "tt0468569", + "Type": "movie", + "Response": "True" + }, + { + "Title": "Batman Begins", + "Year": "2005", + "Rated": "PG-13", + "Released": "15 Jun 2005", + "Runtime": "140 min", + "Genre": "Action, Adventure", + "Director": "Christopher Nolan", + "Writer": "Bob Kane (characters), David S. Goyer (story), Christopher Nolan (screenplay), David S. Goyer (screenplay)", + "Actors": "Christian Bale, Michael Caine, Liam Neeson, Katie Holmes", + "Plot": "After training with his mentor, Batman begins his fight to free crime-ridden Gotham City from the corruption that Scarecrow and the League of Shadows have cast upon it.", + "Language": "English, Urdu, Mandarin", + "Country": "USA, UK", + "Awards": "Nominated for 1 Oscar. Another 15 wins & 66 nominations.", + "Poster": "http://ia.media-imdb.com/images/M/MV5BNTM3OTc0MzM2OV5BMl5BanBnXkFtZTYwNzUwMTI3._V1_SX300.jpg", + "Metascore": "70", + "imdbRating": "8.3", + "imdbVotes": "972,584", + "imdbID": "tt0372784", + "Type": "movie", + "Response": "True" + }, + { + "Title": "Avatar", + "Year": "2009", + "Rated": "PG-13", + "Released": "18 Dec 2009", + "Runtime": "162 min", + "Genre": "Action, Adventure, Fantasy", + "Director": "James Cameron", + "Writer": "James Cameron", + "Actors": "Sam Worthington, Zoe Saldana, Sigourney Weaver, Stephen Lang", + "Plot": "A paraplegic marine dispatched to the moon Pandora on a unique mission becomes torn between following his orders and protecting the world he feels is his home.", + "Language": "English, Spanish", + "Country": "USA, UK", + "Awards": "Won 3 Oscars. Another 80 wins & 121 nominations.", + "Poster": "http://ia.media-imdb.com/images/M/MV5BMTYwOTEwNjAzMl5BMl5BanBnXkFtZTcwODc5MTUwMw@@._V1_SX300.jpg", + "Metascore": "83", + "imdbRating": "7.9", + "imdbVotes": "876,575", + "imdbID": "tt0499549", + "Type": "movie", + "Response": "True" + } +]; + +// Add your code below this line + +var averageRating; + +// Add your code above this line + +console.log(averageRating); +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/functional-programming/Use the some Method to Check that Any Elements in an Array Meet a Criteria.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/functional-programming/Use the some Method to Check that Any Elements in an Array Meet a Criteria.md new file mode 100644 index 0000000000..c2d6e49af6 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/functional-programming/Use the some Method to Check that Any Elements in an Array Meet a Criteria.md @@ -0,0 +1,63 @@ +--- +id: 587d7dab367417b2b2512b6f +title: Use the some Method to Check that Any Elements in an Array Meet a Criteria +challengeType: 1 +--- + +## Description +
    +The some method works with arrays to check if any element passes a particular test. It returns a Boolean value - true if any of the values meet the criteria, false if not. +For example, the following code would check if any element in the numbers array is less than 10: +
    var numbers = [10, 50, 8, 220, 110, 11];
    numbers.some(function(currentValue) {
      return currentValue < 10;
    });
    // Returns true
    +
    + +## Instructions +
    +Use the some method inside the checkPositive function to check if any element in arr is positive. The function should return a Boolean value. +
    + +## Tests +
    + +```yml +- text: Your code should use the some method. + testString: 'assert(code.match(/\.some/g), "Your code should use the some method.");' +- text: 'checkPositive([1, 2, 3, -4, 5]) should return true.' + testString: 'assert(checkPositive([1, 2, 3, -4, 5]), "checkPositive([1, 2, 3, -4, 5]) should return true.");' +- text: 'checkPositive([1, 2, 3, 4, 5]) should return true.' + testString: 'assert(checkPositive([1, 2, 3, 4, 5]), "checkPositive([1, 2, 3, 4, 5]) should return true.");' +- text: 'checkPositive([-1, -2, -3, -4, -5]) should return false.' + testString: 'assert(!checkPositive([-1, -2, -3, -4, -5]), "checkPositive([-1, -2, -3, -4, -5]) should return false.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +function checkPositive(arr) { + // Add your code below this line + + + // Add your code above this line +} +checkPositive([1, 2, 3, -4, 5]); +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/functional-programming/meta.json b/curriculum/challenges/02-javascript-algorithms-and-data-structures/functional-programming/meta.json new file mode 100644 index 0000000000..a06851a33a --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/functional-programming/meta.json @@ -0,0 +1,8 @@ +{ + "name": "Functional Programming", + "dashedName": "functional-programming", + "order": 8, + "time": "5 hours", + "superBlock": "javascript-algorithms-and-data-structures", + "superOrder": 2 +} \ No newline at end of file diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/Arguments Optional.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/Arguments Optional.md new file mode 100644 index 0000000000..0d50245585 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/Arguments Optional.md @@ -0,0 +1,83 @@ +--- +id: a97fd23d9b809dac9921074f +title: Arguments Optional +isRequired: true +challengeType: 5 +guideUrl: 'https://guide.freecodecamp.org/certificates/arguments-optional' +--- + +## Description +
    +Create a function that sums two arguments together. If only one argument is provided, then return a function that expects one argument and returns the sum. +For example, addTogether(2, 3) should return 5, and addTogether(2) should return a function. +Calling this returned function with a single argument will then return the sum: +var sumTwoAnd = addTogether(2); +sumTwoAnd(3) returns 5. +If either argument isn't a valid number, return undefined. +Remember to use Read-Search-Ask if you get stuck. Try to pair program. Write your own code. +
    + +## Instructions +
    + +
    + +## Tests +
    + +```yml +- text: 'addTogether(2, 3) should return 5.' + testString: 'assert.deepEqual(addTogether(2, 3), 5, "addTogether(2, 3) should return 5.");' +- text: addTogether(2)(3) should return 5. + testString: 'assert.deepEqual(addTogether(2)(3), 5, "addTogether(2)(3) should return 5.");' +- text: 'addTogether("http://bit.ly/IqT6zt") should return undefined.' + testString: 'assert.isUndefined(addTogether("http://bit.ly/IqT6zt"), "addTogether("http://bit.ly/IqT6zt") should return undefined.");' +- text: 'addTogether(2, "3") should return undefined.' + testString: 'assert.isUndefined(addTogether(2, "3"), "addTogether(2, "3") should return undefined.");' +- text: 'addTogether(2)([3]) should return undefined.' + testString: 'assert.isUndefined(addTogether(2)([3]), "addTogether(2)([3]) should return undefined.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +function addTogether() { + return false; +} + +addTogether(2,3); +``` + +
    + + + +
    + +## Solution +
    + + +```js +function addTogether() { + var a = arguments[0]; + if (toString.call(a) !== '[object Number]') return; + if (arguments.length === 1) { + return function(b) { + if (toString.call(b) !== '[object Number]') return; + return a + b; + }; + } + var b = arguments[1]; + if (toString.call(b) !== '[object Number]') return; + return a + arguments[1]; +} +``` + +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/Binary Agents.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/Binary Agents.md new file mode 100644 index 0000000000..5b12f67ca9 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/Binary Agents.md @@ -0,0 +1,62 @@ +--- +id: a8d97bd4c764e91f9d2bda01 +title: Binary Agents +isRequired: true +challengeType: 5 +--- + +## Description +
    +Return an English translated sentence of the passed binary string. +The binary string will be space separated. +Remember to use Read-Search-Ask if you get stuck. Try to pair program. Write your own code. +
    + +## Instructions +
    + +
    + +## Tests +
    + +```yml +- text: 'binaryAgent("01000001 01110010 01100101 01101110 00100111 01110100 00100000 01100010 01101111 01101110 01100110 01101001 01110010 01100101 01110011 00100000 01100110 01110101 01101110 00100001 00111111") should return "Aren't bonfires fun!?"' + testString: 'assert.deepEqual(binaryAgent("01000001 01110010 01100101 01101110 00100111 01110100 00100000 01100010 01101111 01101110 01100110 01101001 01110010 01100101 01110011 00100000 01100110 01110101 01101110 00100001 00111111"), "Aren"t bonfires fun!?", "binaryAgent("01000001 01110010 01100101 01101110 00100111 01110100 00100000 01100010 01101111 01101110 01100110 01101001 01110010 01100101 01110011 00100000 01100110 01110101 01101110 00100001 00111111") should return "Aren't bonfires fun!?"");' +- text: binaryAgent("01001001 00100000 01101100 01101111 01110110 01100101 00100000 01000110 01110010 01100101 01100101 01000011 01101111 01100100 01100101 01000011 01100001 01101101 01110000 00100001") should return "I love FreeCodeCamp!" + testString: 'assert.deepEqual(binaryAgent("01001001 00100000 01101100 01101111 01110110 01100101 00100000 01000110 01110010 01100101 01100101 01000011 01101111 01100100 01100101 01000011 01100001 01101101 01110000 00100001"), "I love FreeCodeCamp!", "binaryAgent("01001001 00100000 01101100 01101111 01110110 01100101 00100000 01000110 01110010 01100101 01100101 01000011 01101111 01100100 01100101 01000011 01100001 01101101 01110000 00100001") should return "I love FreeCodeCamp!"");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +function binaryAgent(str) { + return str; +} + +binaryAgent("01000001 01110010 01100101 01101110 00100111 01110100 00100000 01100010 01101111 01101110 01100110 01101001 01110010 01100101 01110011 00100000 01100110 01110101 01101110 00100001 00111111"); +``` + +
    + + + +
    + +## Solution +
    + + +```js +function binaryAgent(str) { + return str.split(' ').map(function(s) { return parseInt(s, 2); }).map(function(b) { return String.fromCharCode(b);}).join("); +} +``` + +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/Convert HTML Entities.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/Convert HTML Entities.md new file mode 100644 index 0000000000..407e597f40 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/Convert HTML Entities.md @@ -0,0 +1,80 @@ +--- +id: a6b0bb188d873cb2c8729495 +title: Convert HTML Entities +isRequired: true +challengeType: 5 +--- + +## Description +
    +Convert the characters &, <, >, " (double quote), and ' (apostrophe), in a string to their corresponding HTML entities. +Remember to use Read-Search-Ask if you get stuck. Try to pair program. Write your own code. +
    + +## Instructions +
    + +
    + +## Tests +
    + +```yml +- text: 'convertHTML("Dolce & Gabbana") should return Dolce &​amp; Gabbana.' + testString: 'assert.match(convertHTML("Dolce & Gabbana"), /Dolce & Gabbana/, "convertHTML("Dolce & Gabbana") should return Dolce &​amp; Gabbana.");' +- text: 'convertHTML("Hamburgers < Pizza < Tacos") should return Hamburgers &​lt; Pizza &​lt; Tacos.' + testString: 'assert.match(convertHTML("Hamburgers < Pizza < Tacos"), /Hamburgers < Pizza < Tacos/, "convertHTML("Hamburgers < Pizza < Tacos") should return Hamburgers &​lt; Pizza &​lt; Tacos.");' +- text: 'convertHTML("Sixty > twelve") should return Sixty &​gt; twelve.' + testString: 'assert.match(convertHTML("Sixty > twelve"), /Sixty > twelve/, "convertHTML("Sixty > twelve") should return Sixty &​gt; twelve.");' +- text: 'convertHTML('Stuff in "quotation marks"') should return Stuff in &​quot;quotation marks&​quot;.' + testString: 'assert.match(convertHTML("Stuff in "quotation marks""), /Stuff in "quotation marks"/, "convertHTML('Stuff in "quotation marks"') should return Stuff in &​quot;quotation marks&​quot;.");' +- text: 'convertHTML("Schindler's List") should return Schindler&​apos;s List.' + testString: 'assert.match(convertHTML("Schindler"s List"), /Schindler's List/, "convertHTML("Schindler's List") should return Schindler&​apos;s List.");' +- text: 'convertHTML("<>") should return &​lt;&​gt;.' + testString: 'assert.match(convertHTML("<>"), /<>/, "convertHTML("<>") should return &​lt;&​gt;.");' +- text: convertHTML("abc") should return abc. + testString: 'assert.strictEqual(convertHTML("abc"), "abc", "convertHTML("abc") should return abc.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +function convertHTML(str) { + // :) + return str; +} + +convertHTML("Dolce & Gabbana"); +``` + +
    + + + +
    + +## Solution +
    + + +```js +var MAP = { '&': '&', + '<': '<', + '>': '>', + '"': '"', + "'": '''}; + +function convertHTML(str) { + return str.replace(/[&<>"']/g, function(c) { + return MAP[c]; + }); +} +``` + +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/DNA Pairing.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/DNA Pairing.md new file mode 100644 index 0000000000..35775917b4 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/DNA Pairing.md @@ -0,0 +1,73 @@ +--- +id: afd15382cdfb22c9efe8b7de +title: DNA Pairing +isRequired: true +challengeType: 5 +--- + +## Description +
    +The DNA strand is missing the pairing element. Take each character, get its pair, and return the results as a 2d array. +Base pairs are a pair of AT and CG. Match the missing element to the provided character. +Return the provided character as the first element in each array. +For example, for the input GCG, return [["G", "C"], ["C","G"],["G", "C"]] +The character and its pair are paired up in an array, and all the arrays are grouped into one encapsulating array. +Remember to use Read-Search-Ask if you get stuck. Try to pair program. Write your own code. +
    + +## Instructions +
    + +
    + +## Tests +
    + +```yml +- text: 'pairElement("ATCGA") should return [["A","T"],["T","A"],["C","G"],["G","C"],["A","T"]].' + testString: 'assert.deepEqual(pairElement("ATCGA"),[["A","T"],["T","A"],["C","G"],["G","C"],["A","T"]], "pairElement("ATCGA") should return [["A","T"],["T","A"],["C","G"],["G","C"],["A","T"]].");' +- text: 'pairElement("TTGAG") should return [["T","A"],["T","A"],["G","C"],["A","T"],["G","C"]].' + testString: 'assert.deepEqual(pairElement("TTGAG"),[["T","A"],["T","A"],["G","C"],["A","T"],["G","C"]], "pairElement("TTGAG") should return [["T","A"],["T","A"],["G","C"],["A","T"],["G","C"]].");' +- text: 'pairElement("CTCTA") should return [["C","G"],["T","A"],["C","G"],["T","A"],["A","T"]].' + testString: 'assert.deepEqual(pairElement("CTCTA"),[["C","G"],["T","A"],["C","G"],["T","A"],["A","T"]], "pairElement("CTCTA") should return [["C","G"],["T","A"],["C","G"],["T","A"],["A","T"]].");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +function pairElement(str) { + return str; +} + +pairElement("GCG"); +``` + +
    + + + +
    + +## Solution +
    + + +```js +var lookup = Object.create(null); +lookup.A = 'T'; +lookup.T = 'A'; +lookup.C = 'G'; +lookup.G = 'C'; + +function pairElement(str) { + return str.split(").map(function(p) {return [p, lookup[p]];}); +} +``` + +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/Diff Two Arrays.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/Diff Two Arrays.md new file mode 100644 index 0000000000..3a6b42a459 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/Diff Two Arrays.md @@ -0,0 +1,108 @@ +--- +id: a5de63ebea8dbee56860f4f2 +title: Diff Two Arrays +isRequired: true +challengeType: 5 +--- + +## Description +
    +Compare two arrays and return a new array with any items only found in one of the two given arrays, but not both. In other words, return the symmetric difference of the two arrays. +Remember to use Read-Search-Ask if you get stuck. Try to pair program. Write your own code. +Note
    You can return the array with its elements in any order. +
    + +## Instructions +
    + +
    + +## Tests +
    + +```yml +- text: 'diffArray([1, 2, 3, 5], [1, 2, 3, 4, 5]) should return an array.' + testString: 'assert(typeof diffArray([1, 2, 3, 5], [1, 2, 3, 4, 5]) === "object", "diffArray([1, 2, 3, 5], [1, 2, 3, 4, 5]) should return an array.");' +- text: '["diorite", "andesite", "grass", "dirt", "pink wool", "dead shrub"], ["diorite", "andesite", "grass", "dirt", "dead shrub"] should return ["pink wool"].' + testString: 'assert.sameMembers(diffArray(["diorite", "andesite", "grass", "dirt", "pink wool", "dead shrub"], ["diorite", "andesite", "grass", "dirt", "dead shrub"]), ["pink wool"], "["diorite", "andesite", "grass", "dirt", "pink wool", "dead shrub"], ["diorite", "andesite", "grass", "dirt", "dead shrub"] should return ["pink wool"].");' +- text: '["diorite", "andesite", "grass", "dirt", "pink wool", "dead shrub"], ["diorite", "andesite", "grass", "dirt", "dead shrub"] should return an array with one item.' + testString: 'assert(diffArray(["diorite", "andesite", "grass", "dirt", "pink wool", "dead shrub"], ["diorite", "andesite", "grass", "dirt", "dead shrub"]).length === 1, "["diorite", "andesite", "grass", "dirt", "pink wool", "dead shrub"], ["diorite", "andesite", "grass", "dirt", "dead shrub"] should return an array with one item.");' +- text: '["andesite", "grass", "dirt", "pink wool", "dead shrub"], ["diorite", "andesite", "grass", "dirt", "dead shrub"] should return ["diorite", "pink wool"].' + testString: 'assert.sameMembers(diffArray(["andesite", "grass", "dirt", "pink wool", "dead shrub"], ["diorite", "andesite", "grass", "dirt", "dead shrub"]), ["diorite", "pink wool"], "["andesite", "grass", "dirt", "pink wool", "dead shrub"], ["diorite", "andesite", "grass", "dirt", "dead shrub"] should return ["diorite", "pink wool"].");' +- text: '["andesite", "grass", "dirt", "pink wool", "dead shrub"], ["diorite", "andesite", "grass", "dirt", "dead shrub"] should return an array with two items.' + testString: 'assert(diffArray(["andesite", "grass", "dirt", "pink wool", "dead shrub"], ["diorite", "andesite", "grass", "dirt", "dead shrub"]).length === 2, "["andesite", "grass", "dirt", "pink wool", "dead shrub"], ["diorite", "andesite", "grass", "dirt", "dead shrub"] should return an array with two items.");' +- text: '["andesite", "grass", "dirt", "dead shrub"], ["andesite", "grass", "dirt", "dead shrub"] should return [].' + testString: 'assert.sameMembers(diffArray(["andesite", "grass", "dirt", "dead shrub"], ["andesite", "grass", "dirt", "dead shrub"]), [], "["andesite", "grass", "dirt", "dead shrub"], ["andesite", "grass", "dirt", "dead shrub"] should return [].");' +- text: '["andesite", "grass", "dirt", "dead shrub"], ["andesite", "grass", "dirt", "dead shrub"] should return an empty array.' + testString: 'assert(diffArray(["andesite", "grass", "dirt", "dead shrub"], ["andesite", "grass", "dirt", "dead shrub"]).length === 0, "["andesite", "grass", "dirt", "dead shrub"], ["andesite", "grass", "dirt", "dead shrub"] should return an empty array.");' +- text: '[1, 2, 3, 5], [1, 2, 3, 4, 5] should return [4].' + testString: 'assert.sameMembers(diffArray([1, 2, 3, 5], [1, 2, 3, 4, 5]), [4], "[1, 2, 3, 5], [1, 2, 3, 4, 5] should return [4].");' +- text: '[1, 2, 3, 5], [1, 2, 3, 4, 5] should return an array with one item.' + testString: 'assert(diffArray([1, 2, 3, 5], [1, 2, 3, 4, 5]).length === 1, "[1, 2, 3, 5], [1, 2, 3, 4, 5] should return an array with one item.");' +- text: '[1, "calf", 3, "piglet"], [1, "calf", 3, 4] should return ["piglet", 4].' + testString: 'assert.sameMembers(diffArray([1, "calf", 3, "piglet"], [1, "calf", 3, 4]), ["piglet", 4], "[1, "calf", 3, "piglet"], [1, "calf", 3, 4] should return ["piglet", 4].");' +- text: '[1, "calf", 3, "piglet"], [1, "calf", 3, 4] should return an array with two items.' + testString: 'assert(diffArray([1, "calf", 3, "piglet"], [1, "calf", 3, 4]).length === 2, "[1, "calf", 3, "piglet"], [1, "calf", 3, 4] should return an array with two items.");' +- text: '[], ["snuffleupagus", "cookie monster", "elmo"] should return ["snuffleupagus", "cookie monster", "elmo"].' + testString: 'assert.sameMembers(diffArray([], ["snuffleupagus", "cookie monster", "elmo"]), ["snuffleupagus", "cookie monster", "elmo"], "[], ["snuffleupagus", "cookie monster", "elmo"] should return ["snuffleupagus", "cookie monster", "elmo"].");' +- text: '[], ["snuffleupagus", "cookie monster", "elmo"] should return an array with three items.' + testString: 'assert(diffArray([], ["snuffleupagus", "cookie monster", "elmo"]).length === 3, "[], ["snuffleupagus", "cookie monster", "elmo"] should return an array with three items.");' +- text: '[1, "calf", 3, "piglet"], [7, "filly"] should return [1, "calf", 3, "piglet", 7, "filly"].' + testString: 'assert.sameMembers(diffArray([1, "calf", 3, "piglet"], [7, "filly"]), [1, "calf", 3, "piglet", 7, "filly"], "[1, "calf", 3, "piglet"], [7, "filly"] should return [1, "calf", 3, "piglet", 7, "filly"].");' +- text: '[1, "calf", 3, "piglet"], [7, "filly"] should return an array with six items.' + testString: 'assert(diffArray([1, "calf", 3, "piglet"], [7, "filly"]).length === 6, "[1, "calf", 3, "piglet"], [7, "filly"] should return an array with six items.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +function diffArray(arr1, arr2) { + var newArr = []; + // Same, same; but different. + return newArr; +} + +diffArray([1, 2, 3, 5], [1, 2, 3, 4, 5]); +``` + +
    + + + +
    + +## Solution +
    + + +```js +function diffArray(arr1, arr2) { + var newArr = []; + var h1 = Object.create(null); + arr1.forEach(function(e) { + h1[e] = e; + }); + + var h2 = Object.create(null); + arr2.forEach(function(e) { + h2[e] = e; + }); + + Object.keys(h1).forEach(function(e) { + if (!(e in h2)) newArr.push(h1[e]); + }); + Object.keys(h2).forEach(function(e) { + if (!(e in h1)) newArr.push(h2[e]); + }); + // Same, same; but different. + return newArr; +} +``` + +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/Drop it.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/Drop it.md new file mode 100644 index 0000000000..798af0d6f1 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/Drop it.md @@ -0,0 +1,75 @@ +--- +id: a5deed1811a43193f9f1c841 +title: Drop it +isRequired: true +challengeType: 5 +--- + +## Description +
    +Given the array arr, iterate through and remove each element starting from the first element (the 0 index) until the function func returns true when the iterated element is passed through it. +Then return the rest of the array once the condition is satisfied, otherwise, arr should be returned as an empty array. +Remember to use Read-Search-Ask if you get stuck. Try to pair program. Write your own code. +
    + +## Instructions +
    + +
    + +## Tests +
    + +```yml +- text: 'dropElements([1, 2, 3, 4], function(n) {return n >= 3;}) should return [3, 4].' + testString: 'assert.deepEqual(dropElements([1, 2, 3, 4], function(n) {return n >= 3;}), [3, 4], "dropElements([1, 2, 3, 4], function(n) {return n >= 3;}) should return [3, 4].");' +- text: 'dropElements([0, 1, 0, 1], function(n) {return n === 1;}) should return [1, 0, 1].' + testString: 'assert.deepEqual(dropElements([0, 1, 0, 1], function(n) {return n === 1;}), [1, 0, 1], "dropElements([0, 1, 0, 1], function(n) {return n === 1;}) should return [1, 0, 1].");' +- text: 'dropElements([1, 2, 3], function(n) {return n > 0;}) should return [1, 2, 3].' + testString: 'assert.deepEqual(dropElements([1, 2, 3], function(n) {return n > 0;}), [1, 2, 3], "dropElements([1, 2, 3], function(n) {return n > 0;}) should return [1, 2, 3].");' +- text: 'dropElements([1, 2, 3, 4], function(n) {return n > 5;}) should return [].' + testString: 'assert.deepEqual(dropElements([1, 2, 3, 4], function(n) {return n > 5;}), [], "dropElements([1, 2, 3, 4], function(n) {return n > 5;}) should return [].");' +- text: 'dropElements([1, 2, 3, 7, 4], function(n) {return n > 3;}) should return [7, 4].' + testString: 'assert.deepEqual(dropElements([1, 2, 3, 7, 4], function(n) {return n > 3;}), [7, 4], "dropElements([1, 2, 3, 7, 4], function(n) {return n > 3;}) should return [7, 4].");' +- text: 'dropElements([1, 2, 3, 9, 2], function(n) {return n > 2;}) should return [3, 9, 2].' + testString: 'assert.deepEqual(dropElements([1, 2, 3, 9, 2], function(n) {return n > 2;}), [3, 9, 2], "dropElements([1, 2, 3, 9, 2], function(n) {return n > 2;}) should return [3, 9, 2].");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +function dropElements(arr, func) { + // Drop them elements. + return arr; +} + +dropElements([1, 2, 3], function(n) {return n < 3; }); +``` + +
    + + + +
    + +## Solution +
    + + +```js +function dropElements(arr, func) { + // Drop them elements. + while (arr.length && !func(arr[0])) { + arr.shift(); + } + return arr; +} +``` + +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/Everything Be True.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/Everything Be True.md new file mode 100644 index 0000000000..9ccfff741e --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/Everything Be True.md @@ -0,0 +1,80 @@ +--- +id: a10d2431ad0c6a099a4b8b52 +title: Everything Be True +isRequired: true +challengeType: 5 +--- + +## Description +
    +Check if the predicate (second argument) is truthy on all elements of a collection (first argument). +In other words, you are given an array collection of objects. The predicate pre will be an object property and you need to return true if its value is truthy. Otherwise, return false. +In JavaScript, truthy values are values that translate to true when evaluated in a Boolean context. +Remember, you can access object properties through either dot notation or [] notation. +Remember to use Read-Search-Ask if you get stuck. Try to pair program. Write your own code. +
    + +## Instructions +
    + +
    + +## Tests +
    + +```yml +- text: 'truthCheck([{"user": "Tinky-Winky", "sex": "male"}, {"user": "Dipsy", "sex": "male"}, {"user": "Laa-Laa", "sex": "female"}, {"user": "Po", "sex": "female"}], "sex") should return true.' + testString: 'assert.strictEqual(truthCheck([{"user": "Tinky-Winky", "sex": "male"}, {"user": "Dipsy", "sex": "male"}, {"user": "Laa-Laa", "sex": "female"}, {"user": "Po", "sex": "female"}], "sex"), true, "truthCheck([{"user": "Tinky-Winky", "sex": "male"}, {"user": "Dipsy", "sex": "male"}, {"user": "Laa-Laa", "sex": "female"}, {"user": "Po", "sex": "female"}], "sex") should return true.");' +- text: 'truthCheck([{"user": "Tinky-Winky", "sex": "male"}, {"user": "Dipsy"}, {"user": "Laa-Laa", "sex": "female"}, {"user": "Po", "sex": "female"}], "sex") should return false.' + testString: 'assert.strictEqual(truthCheck([{"user": "Tinky-Winky", "sex": "male"}, {"user": "Dipsy"}, {"user": "Laa-Laa", "sex": "female"}, {"user": "Po", "sex": "female"}], "sex"), false, "truthCheck([{"user": "Tinky-Winky", "sex": "male"}, {"user": "Dipsy"}, {"user": "Laa-Laa", "sex": "female"}, {"user": "Po", "sex": "female"}], "sex") should return false.");' +- text: 'truthCheck([{"user": "Tinky-Winky", "sex": "male", "age": 0}, {"user": "Dipsy", "sex": "male", "age": 3}, {"user": "Laa-Laa", "sex": "female", "age": 5}, {"user": "Po", "sex": "female", "age": 4}], "age") should return false.' + testString: 'assert.strictEqual(truthCheck([{"user": "Tinky-Winky", "sex": "male", "age": 2}, {"user": "Dipsy", "sex": "male", "age": 0}, {"user": "Laa-Laa", "sex": "female", "age": 5}, {"user": "Po", "sex": "female", "age": 4}], "age"), false, "truthCheck([{"user": "Tinky-Winky", "sex": "male", "age": 0}, {"user": "Dipsy", "sex": "male", "age": 3}, {"user": "Laa-Laa", "sex": "female", "age": 5}, {"user": "Po", "sex": "female", "age": 4}], "age") should return false.");' +- text: 'truthCheck([{"name": "Pete", "onBoat": true}, {"name": "Repeat", "onBoat": true}, {"name": "FastFoward", "onBoat": null}], "onBoat") should return false' + testString: 'assert.strictEqual(truthCheck([{"name": "Pete", "onBoat": true}, {"name": "Repeat", "onBoat": true}, {"name": "FastFoward", "onBoat": null}], "onBoat"), false, "truthCheck([{"name": "Pete", "onBoat": true}, {"name": "Repeat", "onBoat": true}, {"name": "FastFoward", "onBoat": null}], "onBoat") should return false");' +- text: 'truthCheck([{"name": "Pete", "onBoat": true}, {"name": "Repeat", "onBoat": true, "alias": "Repete"}, {"name": "FastFoward", "onBoat": true}], "onBoat") should return true' + testString: 'assert.strictEqual(truthCheck([{"name": "Pete", "onBoat": true}, {"name": "Repeat", "onBoat": true, "alias": "Repete"}, {"name": "FastFoward", "onBoat": true}], "onBoat"), true, "truthCheck([{"name": "Pete", "onBoat": true}, {"name": "Repeat", "onBoat": true, "alias": "Repete"}, {"name": "FastFoward", "onBoat": true}], "onBoat") should return true");' +- text: 'truthCheck([{"single": "yes"}], "single") should return true' + testString: 'assert.strictEqual(truthCheck([{"single": "yes"}], "single"), true, "truthCheck([{"single": "yes"}], "single") should return true");' +- text: 'truthCheck([{"single": ""}, {"single": "double"}], "single") should return false' + testString: 'assert.strictEqual(truthCheck([{"single": ""}, {"single": "double"}], "single"), false, "truthCheck([{"single": ""}, {"single": "double"}], "single") should return false");' +- text: 'truthCheck([{"single": "double"}, {"single": undefined}], "single") should return false' + testString: 'assert.strictEqual(truthCheck([{"single": "double"}, {"single": undefined}], "single"), false, "truthCheck([{"single": "double"}, {"single": undefined}], "single") should return false");' +- text: 'truthCheck([{"single": "double"}, {"single": NaN}], "single") should return false' + testString: 'assert.strictEqual(truthCheck([{"single": "double"}, {"single": NaN}], "single"), false, "truthCheck([{"single": "double"}, {"single": NaN}], "single") should return false");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +function truthCheck(collection, pre) { + // Is everyone being true? + return pre; +} + +truthCheck([{"user": "Tinky-Winky", "sex": "male"}, {"user": "Dipsy", "sex": "male"}, {"user": "Laa-Laa", "sex": "female"}, {"user": "Po", "sex": "female"}], "sex"); +``` + +
    + + + +
    + +## Solution +
    + + +```js +function truthCheck(collection, pre) { + // Does everyone have one of these? + return collection.every(function(e) { return e[pre]; }); +} +``` + +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/Make a Person.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/Make a Person.md new file mode 100644 index 0000000000..4023ac59f7 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/Make a Person.md @@ -0,0 +1,130 @@ +--- +id: a2f1d72d9b908d0bd72bb9f6 +title: Make a Person +challengeType: 5 +--- + +## Description +
    +Fill in the object constructor with the following methods below: +
    getFirstName() +getLastName() +getFullName() +setFirstName(first) +setLastName(last) +setFullName(firstAndLast)
    +Run the tests to see the expected output for each method. +The methods that take an argument must accept only one argument and it has to be a string. +These methods must be the only available means of interacting with the object. +Remember to use Read-Search-Ask if you get stuck. Try to pair program. Write your own code. +
    + +## Instructions +
    + +
    + +## Tests +
    + +```yml +- text: Object.keys(bob).length should return 6. + testString: 'assert.deepEqual(Object.keys(bob).length, 6, "Object.keys(bob).length should return 6.");' +- text: bob instanceof Person should return true. + testString: 'assert.deepEqual(bob instanceof Person, true, "bob instanceof Person should return true.");' +- text: bob.firstName should return undefined. + testString: 'assert.deepEqual(bob.firstName, undefined, "bob.firstName should return undefined.");' +- text: bob.lastName should return undefined. + testString: 'assert.deepEqual(bob.lastName, undefined, "bob.lastName should return undefined.");' +- text: bob.getFirstName() should return "Bob". + testString: 'assert.deepEqual(bob.getFirstName(), "Bob", "bob.getFirstName() should return "Bob".");' +- text: bob.getLastName() should return "Ross". + testString: 'assert.deepEqual(bob.getLastName(), "Ross", "bob.getLastName() should return "Ross".");' +- text: bob.getFullName() should return "Bob Ross". + testString: 'assert.deepEqual(bob.getFullName(), "Bob Ross", "bob.getFullName() should return "Bob Ross".");' +- text: bob.getFullName() should return "Haskell Ross" after bob.setFirstName("Haskell"). + testString: 'assert.strictEqual((function () { bob.setFirstName("Haskell"); return bob.getFullName(); })(), "Haskell Ross", "bob.getFullName() should return "Haskell Ross" after bob.setFirstName("Haskell").");' +- text: bob.getFullName() should return "Haskell Curry" after bob.setLastName("Curry"). + testString: 'assert.strictEqual((function () { var _bob=new Person("Haskell Ross"); _bob.setLastName("Curry"); return _bob.getFullName(); })(), "Haskell Curry", "bob.getFullName() should return "Haskell Curry" after bob.setLastName("Curry").");' +- text: bob.getFullName() should return "Haskell Curry" after bob.setFullName("Haskell Curry"). + testString: 'assert.strictEqual((function () { bob.setFullName("Haskell Curry"); return bob.getFullName(); })(), "Haskell Curry", "bob.getFullName() should return "Haskell Curry" after bob.setFullName("Haskell Curry").");' +- text: bob.getFirstName() should return "Haskell" after bob.setFullName("Haskell Curry"). + testString: 'assert.strictEqual((function () { bob.setFullName("Haskell Curry"); return bob.getFirstName(); })(), "Haskell", "bob.getFirstName() should return "Haskell" after bob.setFullName("Haskell Curry").");' +- text: bob.getLastName() should return "Curry" after bob.setFullName("Haskell Curry"). + testString: 'assert.strictEqual((function () { bob.setFullName("Haskell Curry"); return bob.getLastName(); })(), "Curry", "bob.getLastName() should return "Curry" after bob.setFullName("Haskell Curry").");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +var Person = function(firstAndLast) { + // Complete the method below and implement the others similarly + this.getFullName = function() { + return ""; + }; + return firstAndLast; +}; + +var bob = new Person('Bob Ross'); +bob.getFullName(); +``` + +
    + + + +
    + +## Solution +
    + + +```js +var Person = function(firstAndLast) { + + var firstName, lastName; + + function updateName(str) { + firstName = str.split(" ")[0]; + lastName = str.split(" ")[1]; + } + + updateName(firstAndLast); + + this.getFirstName = function(){ + return firstName; + }; + + this.getLastName = function(){ + return lastName; + }; + + this.getFullName = function(){ + return firstName + " " + lastName; + }; + + this.setFirstName = function(str){ + firstName = str; + }; + + + this.setLastName = function(str){ + lastName = str; + }; + + this.setFullName = function(str){ + updateName(str); + }; +}; + +var bob = new Person('Bob Ross'); +bob.getFullName(); +``` + +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/Map the Debris.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/Map the Debris.md new file mode 100644 index 0000000000..0bf60c7fa4 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/Map the Debris.md @@ -0,0 +1,77 @@ +--- +id: af4afb223120f7348cdfc9fd +title: Map the Debris +challengeType: 5 +--- + +## Description +
    +Return a new array that transforms the elements' average altitude into their orbital periods (in seconds). +The array will contain objects in the format {name: 'name', avgAlt: avgAlt}. +You can read about orbital periods on Wikipedia. +The values should be rounded to the nearest whole number. The body being orbited is Earth. +The radius of the earth is 6367.4447 kilometers, and the GM value of earth is 398600.4418 km3s-2. +Remember to use Read-Search-Ask if you get stuck. Try to pair program. Write your own code. +
    + +## Instructions +
    + +
    + +## Tests +
    + +```yml +- text: 'orbitalPeriod([{name : "sputnik", avgAlt : 35873.5553}]) should return [{name: "sputnik", orbitalPeriod: 86400}].' + testString: 'assert.deepEqual(orbitalPeriod([{name : "sputnik", avgAlt : 35873.5553}]), [{name: "sputnik", orbitalPeriod: 86400}], "orbitalPeriod([{name : "sputnik", avgAlt : 35873.5553}]) should return [{name: "sputnik", orbitalPeriod: 86400}].");' +- text: 'orbitalPeriod([{name: "iss", avgAlt: 413.6}, {name: "hubble", avgAlt: 556.7}, {name: "moon", avgAlt: 378632.553}]) should return [{name : "iss", orbitalPeriod: 5557}, {name: "hubble", orbitalPeriod: 5734}, {name: "moon", orbitalPeriod: 2377399}].' + testString: 'assert.deepEqual(orbitalPeriod([{name: "iss", avgAlt: 413.6}, {name: "hubble", avgAlt: 556.7}, {name: "moon", avgAlt: 378632.553}]), [{name : "iss", orbitalPeriod: 5557}, {name: "hubble", orbitalPeriod: 5734}, {name: "moon", orbitalPeriod: 2377399}], "orbitalPeriod([{name: "iss", avgAlt: 413.6}, {name: "hubble", avgAlt: 556.7}, {name: "moon", avgAlt: 378632.553}]) should return [{name : "iss", orbitalPeriod: 5557}, {name: "hubble", orbitalPeriod: 5734}, {name: "moon", orbitalPeriod: 2377399}].");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +function orbitalPeriod(arr) { + var GM = 398600.4418; + var earthRadius = 6367.4447; + return arr; +} + +orbitalPeriod([{name : "sputnik", avgAlt : 35873.5553}]); +``` + +
    + + + +
    + +## Solution +
    + + +```js +function orbitalPeriod(arr) { + var GM = 398600.4418; + var earthRadius = 6367.4447; + var TAU = 2 * Math.PI; + return arr.map(function(obj) { + return { + name: obj.name, + orbitalPeriod: Math.round(TAU * Math.sqrt(Math.pow(obj.avgAlt+earthRadius, 3)/GM)) + }; + }); +} + +orbitalPeriod([{name : "sputkin", avgAlt : 35873.5553}]); + +``` + +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/Missing letters.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/Missing letters.md new file mode 100644 index 0000000000..21e0dcd5ac --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/Missing letters.md @@ -0,0 +1,75 @@ +--- +id: af7588ade1100bde429baf20 +title: Missing letters +isRequired: true +challengeType: 5 +--- + +## Description +
    +Find the missing letter in the passed letter range and return it. +If all letters are present in the range, return undefined. +Remember to use Read-Search-Ask if you get stuck. Try to pair program. Write your own code. +
    + +## Instructions +
    + +
    + +## Tests +
    + +```yml +- text: fearNotLetter("abce") should return "d". + testString: 'assert.deepEqual(fearNotLetter("abce"), "d", "fearNotLetter("abce") should return "d".");' +- text: fearNotLetter("abcdefghjklmno") should return "i". + testString: 'assert.deepEqual(fearNotLetter("abcdefghjklmno"), "i", "fearNotLetter("abcdefghjklmno") should return "i".");' +- text: fearNotLetter("stvwx") should return "u". + testString: 'assert.deepEqual(fearNotLetter("stvwx"), "u", "fearNotLetter("stvwx") should return "u".");' +- text: fearNotLetter("bcdf") should return "e". + testString: 'assert.deepEqual(fearNotLetter("bcdf"), "e", "fearNotLetter("bcdf") should return "e".");' +- text: fearNotLetter("abcdefghijklmnopqrstuvwxyz") should return undefined. + testString: 'assert.isUndefined(fearNotLetter("abcdefghijklmnopqrstuvwxyz"), "fearNotLetter("abcdefghijklmnopqrstuvwxyz") should return undefined.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +function fearNotLetter(str) { + return str; +} + +fearNotLetter("abce"); +``` + +
    + + + +
    + +## Solution +
    + + +```js +function fearNotLetter (str) { + for (var i = str.charCodeAt(0); i <= str.charCodeAt(str.length - 1); i++) { + var letter = String.fromCharCode(i); + if (str.indexOf(letter) === -1) { + return letter; + } + } + + return undefined; +} +``` + +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/Pig Latin.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/Pig Latin.md new file mode 100644 index 0000000000..42d55be3ef --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/Pig Latin.md @@ -0,0 +1,84 @@ +--- +id: aa7697ea2477d1316795783b +title: Pig Latin +isRequired: true +challengeType: 5 +--- + +## Description +
    +Translate the provided string to pig latin. +Pig Latin takes the first consonant (or consonant cluster) of an English word, moves it to the end of the word and suffixes an "ay". +If a word begins with a vowel you just add "way" to the end. +Input strings are guaranteed to be English words in all lowercase. +Remember to use Read-Search-Ask if you get stuck. Try to pair program. Write your own code. +
    + +## Instructions +
    + +
    + +## Tests +
    + +```yml +- text: translatePigLatin("california") should return "aliforniacay". + testString: 'assert.deepEqual(translatePigLatin("california"), "aliforniacay", "translatePigLatin("california") should return "aliforniacay".");' +- text: translatePigLatin("paragraphs") should return "aragraphspay". + testString: 'assert.deepEqual(translatePigLatin("paragraphs"), "aragraphspay", "translatePigLatin("paragraphs") should return "aragraphspay".");' +- text: translatePigLatin("glove") should return "oveglay". + testString: 'assert.deepEqual(translatePigLatin("glove"), "oveglay", "translatePigLatin("glove") should return "oveglay".");' +- text: translatePigLatin("algorithm") should return "algorithmway". + testString: 'assert.deepEqual(translatePigLatin("algorithm"), "algorithmway", "translatePigLatin("algorithm") should return "algorithmway".");' +- text: translatePigLatin("eight") should return "eightway". + testString: 'assert.deepEqual(translatePigLatin("eight"), "eightway", "translatePigLatin("eight") should return "eightway".");' +- text: Should handle words where the first vowel comes in the end of the word. + testString: 'assert.deepEqual(translatePigLatin("schwartz"), "artzschway", "Should handle words where the first vowel comes in the end of the word.");' +- text: Should handle words without vowels. + testString: 'assert.deepEqual(translatePigLatin("rhythm"), "rhythmay", "Should handle words without vowels.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +function translatePigLatin(str) { + return str; +} + +translatePigLatin("consonant"); +``` + +
    + + + +
    + +## Solution +
    + + +```js +function translatePigLatin(str) { + if (isVowel(str.charAt(0))) return str + "way"; + var front = []; + str = str.split("); + while (str.length && !isVowel(str[0])) { + front.push(str.shift()); + } + return [].concat(str, front).join(") + 'ay'; +} + +function isVowel(c) { + return ['a', 'e', 'i', 'o', 'u'].indexOf(c.toLowerCase()) !== -1; +} +``` + +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/Search and Replace.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/Search and Replace.md new file mode 100644 index 0000000000..3afaa50a8f --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/Search and Replace.md @@ -0,0 +1,76 @@ +--- +id: a0b5010f579e69b815e7c5d6 +title: Search and Replace +isRequired: true +challengeType: 5 +--- + +## Description +
    +Perform a search and replace on the sentence using the arguments provided and return the new sentence. +First argument is the sentence to perform the search and replace on. +Second argument is the word that you will be replacing (before). +Third argument is what you will be replacing the second argument with (after). +Note
    Preserve the case of the first character in the original word when you are replacing it. For example if you mean to replace the word "Book" with the word "dog", it should be replaced as "Dog" +Remember to use Read-Search-Ask if you get stuck. Try to pair program. Write your own code. +
    + +## Instructions +
    + +
    + +## Tests +
    + +```yml +- text: 'myReplace("Let us go to the store", "store", "mall") should return "Let us go to the mall".' + testString: 'assert.deepEqual(myReplace("Let us go to the store", "store", "mall"), "Let us go to the mall", "myReplace("Let us go to the store", "store", "mall") should return "Let us go to the mall".");' +- text: 'myReplace("He is Sleeping on the couch", "Sleeping", "sitting") should return "He is Sitting on the couch".' + testString: 'assert.deepEqual(myReplace("He is Sleeping on the couch", "Sleeping", "sitting"), "He is Sitting on the couch", "myReplace("He is Sleeping on the couch", "Sleeping", "sitting") should return "He is Sitting on the couch".");' +- text: 'myReplace("This has a spellngi error", "spellngi", "spelling") should return "This has a spelling error".' + testString: 'assert.deepEqual(myReplace("This has a spellngi error", "spellngi", "spelling"), "This has a spelling error", "myReplace("This has a spellngi error", "spellngi", "spelling") should return "This has a spelling error".");' +- text: 'myReplace("His name is Tom", "Tom", "john") should return "His name is John".' + testString: 'assert.deepEqual(myReplace("His name is Tom", "Tom", "john"), "His name is John", "myReplace("His name is Tom", "Tom", "john") should return "His name is John".");' +- text: 'myReplace("Let us get back to more Coding", "Coding", "algorithms") should return "Let us get back to more Algorithms".' + testString: 'assert.deepEqual(myReplace("Let us get back to more Coding", "Coding", "algorithms"), "Let us get back to more Algorithms", "myReplace("Let us get back to more Coding", "Coding", "algorithms") should return "Let us get back to more Algorithms".");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +function myReplace(str, before, after) { + return str; +} + +myReplace("A quick brown fox jumped over the lazy dog", "jumped", "leaped"); +``` + +
    + + + +
    + +## Solution +
    + + +```js +function myReplace(str, before, after) { + if (before.charAt(0) === before.charAt(0).toUpperCase()) { + after = after.charAt(0).toUpperCase() + after.substring(1); + } else { + after = after.charAt(0).toLowerCase() + after.substring(1); + } + return str.replace(before, after); +} +``` + +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/Seek and Destroy.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/Seek and Destroy.md new file mode 100644 index 0000000000..488b16c156 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/Seek and Destroy.md @@ -0,0 +1,79 @@ +--- +id: a39963a4c10bc8b4d4f06d7e +title: Seek and Destroy +isRequired: true +challengeType: 5 +--- + +## Description +
    +You will be provided with an initial array (the first argument in the destroyer function), followed by one or more arguments. Remove all elements from the initial array that are of the same value as these arguments. +Note
    You have to use the arguments object. +Remember to use Read-Search-Ask if you get stuck. Write your own code. +
    + +## Instructions +
    + +
    + +## Tests +
    + +```yml +- text: 'destroyer([1, 2, 3, 1, 2, 3], 2, 3) should return [1, 1].' + testString: 'assert.deepEqual(destroyer([1, 2, 3, 1, 2, 3], 2, 3), [1, 1], "destroyer([1, 2, 3, 1, 2, 3], 2, 3) should return [1, 1].");' +- text: 'destroyer([1, 2, 3, 5, 1, 2, 3], 2, 3) should return [1, 5, 1].' + testString: 'assert.deepEqual(destroyer([1, 2, 3, 5, 1, 2, 3], 2, 3), [1, 5, 1], "destroyer([1, 2, 3, 5, 1, 2, 3], 2, 3) should return [1, 5, 1].");' +- text: 'destroyer([3, 5, 1, 2, 2], 2, 3, 5) should return [1].' + testString: 'assert.deepEqual(destroyer([3, 5, 1, 2, 2], 2, 3, 5), [1], "destroyer([3, 5, 1, 2, 2], 2, 3, 5) should return [1].");' +- text: 'destroyer([2, 3, 2, 3], 2, 3) should return [].' + testString: 'assert.deepEqual(destroyer([2, 3, 2, 3], 2, 3), [], "destroyer([2, 3, 2, 3], 2, 3) should return [].");' +- text: 'destroyer(["tree", "hamburger", 53], "tree", 53) should return ["hamburger"].' + testString: 'assert.deepEqual(destroyer(["tree", "hamburger", 53], "tree", 53), ["hamburger"], "destroyer(["tree", "hamburger", 53], "tree", 53) should return ["hamburger"].");' +- text: 'destroyer(["possum", "trollo", 12, "safari", "hotdog", 92, 65, "grandma", "bugati", "trojan", "yacht"], "yacht", "possum", "trollo", "safari", "hotdog", "grandma", "bugati", "trojan") should return [12,92,65].' + testString: 'assert.deepEqual(destroyer(["possum", "trollo", 12, "safari", "hotdog", 92, 65, "grandma", "bugati", "trojan", "yacht"], "yacht", "possum", "trollo", "safari", "hotdog", "grandma", "bugati", "trojan"), [12,92,65], "destroyer(["possum", "trollo", 12, "safari", "hotdog", 92, 65, "grandma", "bugati", "trojan", "yacht"], "yacht", "possum", "trollo", "safari", "hotdog", "grandma", "bugati", "trojan") should return [12,92,65].");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +function destroyer(arr) { + // Remove all the values + return arr; +} + +destroyer([1, 2, 3, 1, 2, 3], 2, 3); +``` + +
    + + + +
    + +## Solution +
    + + +```js +function destroyer(arr) { + var hash = Object.create(null); + [].slice.call(arguments, 1).forEach(function(e) { + hash[e] = true; + }); + // Remove all the values + return arr.filter(function(e) { return !(e in hash);}); +} + +destroyer([1, 2, 3, 1, 2, 3], 2, 3); + +``` + +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/Smallest Common Multiple.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/Smallest Common Multiple.md new file mode 100644 index 0000000000..4a21b43f6d --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/Smallest Common Multiple.md @@ -0,0 +1,88 @@ +--- +id: ae9defd7acaf69703ab432ea +title: Smallest Common Multiple +isRequired: true +challengeType: 5 +--- + +## Description +
    +Find the smallest common multiple of the provided parameters that can be evenly divided by both, as well as by all sequential numbers in the range between these parameters. +The range will be an array of two numbers that will not necessarily be in numerical order. +For example, if given 1 and 3, find the smallest common multiple of both 1 and 3 that is also evenly divisible by all numbers between 1 and 3. The answer here would be 6. +Remember to use Read-Search-Ask if you get stuck. Try to pair program. Write your own code. +
    + +## Instructions +
    + +
    + +## Tests +
    + +```yml +- text: 'smallestCommons([1, 5]) should return a number.' + testString: 'assert.deepEqual(typeof smallestCommons([1, 5]), "number", "smallestCommons([1, 5]) should return a number.");' +- text: 'smallestCommons([1, 5]) should return 60.' + testString: 'assert.deepEqual(smallestCommons([1, 5]), 60, "smallestCommons([1, 5]) should return 60.");' +- text: 'smallestCommons([5, 1]) should return 60.' + testString: 'assert.deepEqual(smallestCommons([5, 1]), 60, "smallestCommons([5, 1]) should return 60.");' +- text: 'smallestCommons([2, 10]) should return 2520.' + testString: 'assert.deepEqual(smallestCommons([2, 10]), 2520, "smallestCommons([2, 10]) should return 2520.");' +- text: 'smallestCommons([1, 13]) should return 360360.' + testString: 'assert.deepEqual(smallestCommons([1, 13]), 360360, "smallestCommons([1, 13]) should return 360360.");' +- text: 'smallestCommons([23, 18]) should return 6056820.' + testString: 'assert.deepEqual(smallestCommons([23, 18]), 6056820, "smallestCommons([23, 18]) should return 6056820.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +function smallestCommons(arr) { + return arr; +} + + +smallestCommons([1,5]); +``` + +
    + + + +
    + +## Solution +
    + + +```js +function gcd(a, b) { + while (b !== 0) { + a = [b, b = a % b][0]; + } + return a; +} + +function lcm(a, b) { + return (a * b) / gcd(a, b); +} + +function smallestCommons(arr) { + arr.sort(function(a,b) {return a-b;}); + var rng = []; + for (var i = arr[0]; i <= arr[1]; i++) { + rng.push(i); + } + return rng.reduce(lcm); +} +``` + +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/Sorted Union.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/Sorted Union.md new file mode 100644 index 0000000000..546a8482ba --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/Sorted Union.md @@ -0,0 +1,70 @@ +--- +id: a105e963526e7de52b219be9 +title: Sorted Union +isRequired: true +challengeType: 5 +--- + +## Description +
    +Write a function that takes two or more arrays and returns a new array of unique values in the order of the original provided arrays. +In other words, all values present from all arrays should be included in their original order, but with no duplicates in the final array. +The unique numbers should be sorted by their original order, but the final array should not be sorted in numerical order. +Check the assertion tests for examples. +Remember to use Read-Search-Ask if you get stuck. Try to pair program. Write your own code. +
    + +## Instructions +
    + +
    + +## Tests +
    + +```yml +- text: 'uniteUnique([1, 3, 2], [5, 2, 1, 4], [2, 1]) should return [1, 3, 2, 5, 4].' + testString: 'assert.deepEqual(uniteUnique([1, 3, 2], [5, 2, 1, 4], [2, 1]), [1, 3, 2, 5, 4], "uniteUnique([1, 3, 2], [5, 2, 1, 4], [2, 1]) should return [1, 3, 2, 5, 4].");' +- text: 'uniteUnique([1, 3, 2], [1, [5]], [2, [4]]) should return [1, 3, 2, [5], [4]].' + testString: 'assert.deepEqual(uniteUnique([1, 3, 2], [1, [5]], [2, [4]]), [1, 3, 2, [5], [4]], "uniteUnique([1, 3, 2], [1, [5]], [2, [4]]) should return [1, 3, 2, [5], [4]].");' +- text: 'uniteUnique([1, 2, 3], [5, 2, 1]) should return [1, 2, 3, 5].' + testString: 'assert.deepEqual(uniteUnique([1, 2, 3], [5, 2, 1]), [1, 2, 3, 5], "uniteUnique([1, 2, 3], [5, 2, 1]) should return [1, 2, 3, 5].");' +- text: 'uniteUnique([1, 2, 3], [5, 2, 1, 4], [2, 1], [6, 7, 8]) should return [1, 2, 3, 5, 4, 6, 7, 8].' + testString: 'assert.deepEqual(uniteUnique([1, 2, 3], [5, 2, 1, 4], [2, 1], [6, 7, 8]), [1, 2, 3, 5, 4, 6, 7, 8], "uniteUnique([1, 2, 3], [5, 2, 1, 4], [2, 1], [6, 7, 8]) should return [1, 2, 3, 5, 4, 6, 7, 8].");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +function uniteUnique(arr) { + return arr; +} + +uniteUnique([1, 3, 2], [5, 2, 1, 4], [2, 1]); +``` + +
    + + + +
    + +## Solution +
    + + +```js +function uniteUnique(arr) { + return [].slice.call(arguments).reduce(function(a, b) { + return [].concat(a, b.filter(function(e) {return a.indexOf(e) === -1;})); + }, []); +} +``` + +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/Spinal Tap Case.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/Spinal Tap Case.md new file mode 100644 index 0000000000..ce299db105 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/Spinal Tap Case.md @@ -0,0 +1,72 @@ +--- +id: a103376db3ba46b2d50db289 +title: Spinal Tap Case +isRequired: true +challengeType: 5 +--- + +## Description +
    +Convert a string to spinal case. Spinal case is all-lowercase-words-joined-by-dashes. +Remember to use Read-Search-Ask if you get stuck. Try to pair program. Write your own code. +
    + +## Instructions +
    + +
    + +## Tests +
    + +```yml +- text: spinalCase("This Is Spinal Tap") should return "this-is-spinal-tap". + testString: 'assert.deepEqual(spinalCase("This Is Spinal Tap"), "this-is-spinal-tap", "spinalCase("This Is Spinal Tap") should return "this-is-spinal-tap".");' +- text: spinalCase("thisIsSpinalTap") should return "this-is-spinal-tap". + testString: 'assert.strictEqual(spinalCase("thisIsSpinalTap"), "this-is-spinal-tap", "spinalCase("thisIsSpinalTap") should return "this-is-spinal-tap".");' +- text: spinalCase("The_Andy_Griffith_Show") should return "the-andy-griffith-show". + testString: 'assert.strictEqual(spinalCase("The_Andy_Griffith_Show"), "the-andy-griffith-show", "spinalCase("The_Andy_Griffith_Show") should return "the-andy-griffith-show".");' +- text: spinalCase("Teletubbies say Eh-oh") should return "teletubbies-say-eh-oh". + testString: 'assert.strictEqual(spinalCase("Teletubbies say Eh-oh"), "teletubbies-say-eh-oh", "spinalCase("Teletubbies say Eh-oh") should return "teletubbies-say-eh-oh".");' +- text: spinalCase("AllThe-small Things") should return "all-the-small-things". + testString: 'assert.strictEqual(spinalCase("AllThe-small Things"), "all-the-small-things", "spinalCase("AllThe-small Things") should return "all-the-small-things".");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +function spinalCase(str) { + // "It's such a fine line between stupid, and clever." + // --David St. Hubbins + return str; +} + +spinalCase('This Is Spinal Tap'); +``` + +
    + + + +
    + +## Solution +
    + + +```js +function spinalCase(str) { + // "It's such a fine line between stupid, and clever." + // --David St. Hubbins + str = str.replace(/([a-z](?=[A-Z]))/g, '$1 '); + return str.toLowerCase().replace(/\ |\_/g, '-'); +} +``` + +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/Steamroller.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/Steamroller.md new file mode 100644 index 0000000000..9bc91f67e8 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/Steamroller.md @@ -0,0 +1,75 @@ +--- +id: ab306dbdcc907c7ddfc30830 +title: Steamroller +isRequired: true +challengeType: 5 +--- + +## Description +
    +Flatten a nested array. You must account for varying levels of nesting. +Remember to use Read-Search-Ask if you get stuck. Try to pair program. Write your own code. +
    + +## Instructions +
    + +
    + +## Tests +
    + +```yml +- text: 'steamrollArray([[["a"]], [["b"]]]) should return ["a", "b"].' + testString: 'assert.deepEqual(steamrollArray([[["a"]], [["b"]]]), ["a", "b"], "steamrollArray([[["a"]], [["b"]]]) should return ["a", "b"].");' +- text: 'steamrollArray([1, [2], [3, [[4]]]]) should return [1, 2, 3, 4].' + testString: 'assert.deepEqual(steamrollArray([1, [2], [3, [[4]]]]), [1, 2, 3, 4], "steamrollArray([1, [2], [3, [[4]]]]) should return [1, 2, 3, 4].");' +- text: 'steamrollArray([1, [], [3, [[4]]]]) should return [1, 3, 4].' + testString: 'assert.deepEqual(steamrollArray([1, [], [3, [[4]]]]), [1, 3, 4], "steamrollArray([1, [], [3, [[4]]]]) should return [1, 3, 4].");' +- text: 'steamrollArray([1, {}, [3, [[4]]]]) should return [1, {}, 3, 4].' + testString: 'assert.deepEqual(steamrollArray([1, {}, [3, [[4]]]]), [1, {}, 3, 4], "steamrollArray([1, {}, [3, [[4]]]]) should return [1, {}, 3, 4].");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +function steamrollArray(arr) { + // I'm a steamroller, baby + return arr; +} + +steamrollArray([1, [2], [3, [[4]]]]); +``` + +
    + + + +
    + +## Solution +
    + + +```js +function steamrollArray(arr) { + if (!Array.isArray(arr)) { + return [arr]; + } + var out = []; + arr.forEach(function(e) { + steamrollArray(e).forEach(function(v) { + out.push(v); + }); + }); + return out; +} +``` + +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/Sum All Numbers in a Range.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/Sum All Numbers in a Range.md new file mode 100644 index 0000000000..68346178b4 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/Sum All Numbers in a Range.md @@ -0,0 +1,73 @@ +--- +id: a3566b1109230028080c9345 +title: Sum All Numbers in a Range +isRequired: true +challengeType: 5 +--- + +## Description +
    +We'll pass you an array of two numbers. Return the sum of those two numbers plus the sum of all the numbers between them. +The lowest number will not always come first. +Remember to use Read-Search-Ask if you get stuck. Try to pair program. Write your own code. +
    + +## Instructions +
    + +
    + +## Tests +
    + +```yml +- text: 'sumAll([1, 4]) should return a number.' + testString: 'assert(typeof sumAll([1, 4]) === "number", "sumAll([1, 4]) should return a number.");' +- text: 'sumAll([1, 4]) should return 10.' + testString: 'assert.deepEqual(sumAll([1, 4]), 10, "sumAll([1, 4]) should return 10.");' +- text: 'sumAll([4, 1]) should return 10.' + testString: 'assert.deepEqual(sumAll([4, 1]), 10, "sumAll([4, 1]) should return 10.");' +- text: 'sumAll([5, 10]) should return 45.' + testString: 'assert.deepEqual(sumAll([5, 10]), 45, "sumAll([5, 10]) should return 45.");' +- text: 'sumAll([10, 5]) should return 45.' + testString: 'assert.deepEqual(sumAll([10, 5]), 45, "sumAll([10, 5]) should return 45.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +function sumAll(arr) { + return 1; +} + +sumAll([1, 4]); +``` + +
    + + + +
    + +## Solution +
    + + +```js +function sumAll(arr) { + var sum = 0; + arr.sort(function(a,b) {return a-b;}); + for (var i = arr[0]; i <= arr[1]; i++) { + sum += i; + } + return sum; +} +``` + +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/Sum All Odd Fibonacci Numbers.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/Sum All Odd Fibonacci Numbers.md new file mode 100644 index 0000000000..2091c07d78 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/Sum All Odd Fibonacci Numbers.md @@ -0,0 +1,80 @@ +--- +id: a5229172f011153519423690 +title: Sum All Odd Fibonacci Numbers +isRequired: true +challengeType: 5 +--- + +## Description +
    +Given a positive integer num, return the sum of all odd Fibonacci numbers that are less than or equal to num. +The first two numbers in the Fibonacci sequence are 1 and 1. Every additional number in the sequence is the sum of the two previous numbers. The first six numbers of the Fibonacci sequence are 1, 1, 2, 3, 5 and 8. +For example, sumFibs(10) should return 10 because all odd Fibonacci numbers less than or equal to 10 are 1, 1, 3, and 5. +Remember to use Read-Search-Ask if you get stuck. Try to pair program. Write your own code. +
    + +## Instructions +
    + +
    + +## Tests +
    + +```yml +- text: sumFibs(1) should return a number. + testString: 'assert(typeof sumFibs(1) === "number", "sumFibs(1) should return a number.");' +- text: sumFibs(1000) should return 1785. + testString: 'assert(sumFibs(1000) === 1785, "sumFibs(1000) should return 1785.");' +- text: sumFibs(4000000) should return 4613732. + testString: 'assert(sumFibs(4000000) === 4613732, "sumFibs(4000000) should return 4613732.");' +- text: sumFibs(4) should return 5. + testString: 'assert(sumFibs(4) === 5, "sumFibs(4) should return 5.");' +- text: sumFibs(75024) should return 60696. + testString: 'assert(sumFibs(75024) === 60696, "sumFibs(75024) should return 60696.");' +- text: sumFibs(75025) should return 135721. + testString: 'assert(sumFibs(75025) === 135721, "sumFibs(75025) should return 135721.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +function sumFibs(num) { + return num; +} + +sumFibs(4); +``` + +
    + + + +
    + +## Solution +
    + + +```js +function sumFibs(num) { + var a = 1; + var b = 1; + var s = 0; + while (a <= num) { + if (a % 2 !== 0) { + s += a; + } + a = [b, b=b+a][0]; + } + return s; +} +``` + +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/Sum All Primes.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/Sum All Primes.md new file mode 100644 index 0000000000..6a4c18b753 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/Sum All Primes.md @@ -0,0 +1,87 @@ +--- +id: a3bfc1673c0526e06d3ac698 +title: Sum All Primes +isRequired: true +challengeType: 5 +--- + +## Description +
    +Sum all the prime numbers up to and including the provided number. +A prime number is defined as a number greater than one and having only two divisors, one and itself. For example, 2 is a prime number because it's only divisible by one and two. +The provided number may not be a prime. +Remember to use Read-Search-Ask if you get stuck. Try to pair program. Write your own code. +
    + +## Instructions +
    + +
    + +## Tests +
    + +```yml +- text: sumPrimes(10) should return a number. + testString: 'assert.deepEqual(typeof sumPrimes(10), "number", "sumPrimes(10) should return a number.");' +- text: sumPrimes(10) should return 17. + testString: 'assert.deepEqual(sumPrimes(10), 17, "sumPrimes(10) should return 17.");' +- text: sumPrimes(977) should return 73156. + testString: 'assert.deepEqual(sumPrimes(977), 73156, "sumPrimes(977) should return 73156.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +function sumPrimes(num) { + return num; +} + +sumPrimes(10); +``` + +
    + + + +
    + +## Solution +
    + + +```js +function eratosthenesArray(n) { + var primes = []; + if (n > 2) { + var half = n>>1; + var sieve = Array(half); + for (var i = 1, limit = Math.sqrt(n)>>1; i <= limit; i++) { + if (!sieve[i]) { + for (var step = 2*i+1, j = (step*step)>>1; j < half; j+=step) { + sieve[j] = true; + } + } + } + primes.push(2); + for (var p = 1; p < half; p++) { + if (!sieve[p]) primes.push(2*p+1); + } + } + return primes; +} + +function sumPrimes(num) { + return eratosthenesArray(num+1).reduce(function(a,b) {return a+b;}, 0); +} + +sumPrimes(10); +``` + +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/Wherefore art thou.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/Wherefore art thou.md new file mode 100644 index 0000000000..2be8e888c5 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/Wherefore art thou.md @@ -0,0 +1,83 @@ +--- +id: a8e512fbe388ac2f9198f0fa +title: Wherefore art thou +isRequired: true +challengeType: 5 +--- + +## Description +
    +Make a function that looks through an array of objects (first argument) and returns an array of all objects that have matching name and value pairs (second argument). Each name and value pair of the source object has to be present in the object from the collection if it is to be included in the returned array. +For example, if the first argument is [{ first: "Romeo", last: "Montague" }, { first: "Mercutio", last: null }, { first: "Tybalt", last: "Capulet" }], and the second argument is { last: "Capulet" }, then you must return the third object from the array (the first argument), because it contains the name and its value, that was passed on as the second argument. +Remember to use Read-Search-Ask if you get stuck. Write your own code. +
    + +## Instructions +
    + +
    + +## Tests +
    + +```yml +- text: 'whatIsInAName([{ first: "Romeo", last: "Montague" }, { first: "Mercutio", last: null }, { first: "Tybalt", last: "Capulet" }], { last: "Capulet" }) should return [{ first: "Tybalt", last: "Capulet" }].' + testString: 'assert.deepEqual(whatIsInAName([{ first: "Romeo", last: "Montague" }, { first: "Mercutio", last: null }, { first: "Tybalt", last: "Capulet" }], { last: "Capulet" }), [{ first: "Tybalt", last: "Capulet" }], "whatIsInAName([{ first: "Romeo", last: "Montague" }, { first: "Mercutio", last: null }, { first: "Tybalt", last: "Capulet" }], { last: "Capulet" }) should return [{ first: "Tybalt", last: "Capulet" }].");' +- text: 'whatIsInAName([{ "apple": 1 }, { "apple": 1 }, { "apple": 1, "bat": 2 }], { "apple": 1 }) should return [{ "apple": 1 }, { "apple": 1 }, { "apple": 1, "bat": 2 }].' + testString: 'assert.deepEqual(whatIsInAName([{ "apple": 1 }, { "apple": 1 }, { "apple": 1, "bat": 2 }], { "apple": 1 }), [{ "apple": 1 }, { "apple": 1 }, { "apple": 1, "bat": 2 }], "whatIsInAName([{ "apple": 1 }, { "apple": 1 }, { "apple": 1, "bat": 2 }], { "apple": 1 }) should return [{ "apple": 1 }, { "apple": 1 }, { "apple": 1, "bat": 2 }].");' +- text: 'whatIsInAName([{ "apple": 1, "bat": 2 }, { "bat": 2 }, { "apple": 1, "bat": 2, "cookie": 2 }], { "apple": 1, "bat": 2 }) should return [{ "apple": 1, "bat": 2 }, { "apple": 1, "bat": 2, "cookie": 2 }].' + testString: 'assert.deepEqual(whatIsInAName([{ "apple": 1, "bat": 2 }, { "bat": 2 }, { "apple": 1, "bat": 2, "cookie": 2 }], { "apple": 1, "bat": 2 }), [{ "apple": 1, "bat": 2 }, { "apple": 1, "bat": 2, "cookie": 2 }], "whatIsInAName([{ "apple": 1, "bat": 2 }, { "bat": 2 }, { "apple": 1, "bat": 2, "cookie": 2 }], { "apple": 1, "bat": 2 }) should return [{ "apple": 1, "bat": 2 }, { "apple": 1, "bat": 2, "cookie": 2 }].");' +- text: 'whatIsInAName([{ "apple": 1, "bat": 2 }, { "apple": 1 }, { "apple": 1, "bat": 2, "cookie": 2 }], { "apple": 1, "cookie": 2 }) should return [{ "apple": 1, "bat": 2, "cookie": 2 }].' + testString: 'assert.deepEqual(whatIsInAName([{ "apple": 1, "bat": 2 }, { "apple": 1 }, { "apple": 1, "bat": 2, "cookie": 2 }], { "apple": 1, "cookie": 2 }), [{ "apple": 1, "bat": 2, "cookie": 2 }], "whatIsInAName([{ "apple": 1, "bat": 2 }, { "apple": 1 }, { "apple": 1, "bat": 2, "cookie": 2 }], { "apple": 1, "cookie": 2 }) should return [{ "apple": 1, "bat": 2, "cookie": 2 }].");' +- text: 'whatIsInAName([{ "apple": 1, "bat": 2 }, { "apple": 1 }, { "apple": 1, "bat": 2, "cookie": 2 }, { "bat":2 }], { "apple": 1, "bat": 2 }) should return [{ "apple": 1, "bat": 2 }, { "apple": 1, "bat": 2, "cookie":2 }].' + testString: 'assert.deepEqual(whatIsInAName([{ "apple": 1, "bat": 2 }, { "apple": 1 }, { "apple": 1, "bat": 2, "cookie": 2 }, {"bat":2}], { "apple": 1, "bat": 2 }), [{ "apple": 1, "bat": 2 }, { "apple": 1, "bat": 2, "cookie":2 }], "whatIsInAName([{ "apple": 1, "bat": 2 }, { "apple": 1 }, { "apple": 1, "bat": 2, "cookie": 2 }, { "bat":2 }], { "apple": 1, "bat": 2 }) should return [{ "apple": 1, "bat": 2 }, { "apple": 1, "bat": 2, "cookie":2 }].");' +- text: 'whatIsInAName([{"a": 1, "b": 2, "c": 3}], {"a": 1, "b": 9999, "c": 3}) should return []' + testString: 'assert.deepEqual(whatIsInAName([{ "a": 1, "b": 2, "c": 3 }], { "a": 1, "b": 9999, "c": 3 }), [], "whatIsInAName([{"a": 1, "b": 2, "c": 3}], {"a": 1, "b": 9999, "c": 3}) should return []");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +function whatIsInAName(collection, source) { + // What's in a name? + var arr = []; + // Only change code below this line + + + // Only change code above this line + return arr; +} + +whatIsInAName([{ first: "Romeo", last: "Montague" }, { first: "Mercutio", last: null }, { first: "Tybalt", last: "Capulet" }], { last: "Capulet" }); +``` + +
    + + + +
    + +## Solution +
    + + +```js +function whatIsInAName(collection, source) { + var arr = []; + var keys = Object.keys(source); + collection.forEach(function(e) { + if(keys.every(function(key) {return e[key] === source[key];})) { + arr.push(e); + } + }); + return arr; +} +``` + +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/meta.json b/curriculum/challenges/02-javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/meta.json new file mode 100644 index 0000000000..673339c35f --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/meta.json @@ -0,0 +1,8 @@ +{ + "name": "Intermediate Algorithm Scripting", + "dashedName": "intermediate-algorithm-scripting", + "order": 9, + "time": "50 hours", + "superBlock": "javascript-algorithms-and-data-structures", + "superOrder": 2 +} \ No newline at end of file diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/javascript-algorithms-and-data-structures-projects/Caesars Cipher.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/javascript-algorithms-and-data-structures-projects/Caesars Cipher.md new file mode 100644 index 0000000000..04d94dea0b --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/javascript-algorithms-and-data-structures-projects/Caesars Cipher.md @@ -0,0 +1,92 @@ +--- +id: 56533eb9ac21ba0edf2244e2 +title: Caesars Cipher +challengeType: 5 +isRequired: true +--- + +## Description +
    +One of the simplest and most widely known ciphers is a Caesar cipher, also known as a shift cipher. In a shift cipher the meanings of the letters are shifted by some set amount. +A common modern use is the ROT13 cipher, where the values of the letters are shifted by 13 places. Thus 'A' ↔ 'N', 'B' ↔ 'O' and so on. +Write a function which takes a ROT13 encoded string as input and returns a decoded string. +All letters will be uppercase. Do not transform any non-alphabetic character (i.e. spaces, punctuation), but do pass them on. +Remember to use Read-Search-Ask if you get stuck. Try to pair program. Write your own code. +
    + +## Instructions +
    + +
    + +## Tests +
    + +```yml +- text: rot13("SERR PBQR PNZC") should decode to FREE CODE CAMP + testString: 'assert(rot13("SERR PBQR PNZC") === "FREE CODE CAMP", "rot13("SERR PBQR PNZC") should decode to FREE CODE CAMP");' +- text: rot13("SERR CVMMN!") should decode to FREE PIZZA! + testString: 'assert(rot13("SERR CVMMN!") === "FREE PIZZA!", "rot13("SERR CVMMN!") should decode to FREE PIZZA!");' +- text: rot13("SERR YBIR?") should decode to FREE LOVE? + testString: 'assert(rot13("SERR YBIR?") === "FREE LOVE?", "rot13("SERR YBIR?") should decode to FREE LOVE?");' +- text: rot13("GUR DHVPX OEBJA SBK WHZCF BIRE GUR YNML QBT.") should decode to THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG. + testString: 'assert(rot13("GUR DHVPX OEBJA SBK WHZCF BIRE GUR YNML QBT.") === "THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG.", "rot13("GUR DHVPX OEBJA SBK WHZCF BIRE GUR YNML QBT.") should decode to THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +function rot13(str) { // LBH QVQ VG! + + return str; +} + +// Change the inputs below to test +rot13("SERR PBQR PNZC"); +``` + +
    + + + +
    + +## Solution +
    + + +```js +var lookup = { + 'A': 'N','B': 'O','C': 'P','D': 'Q', + 'E': 'R','F': 'S','G': 'T','H': 'U', + 'I': 'V','J': 'W','K': 'X','L': 'Y', + 'M': 'Z','N': 'A','O': 'B','P': 'C', + 'Q': 'D','R': 'E','S': 'F','T': 'G', + 'U': 'H','V': 'I','W': 'J','X': 'K', + 'Y': 'L','Z': 'M' +}; + +function rot13(encodedStr) { + var codeArr = encodedStr.split(""); // String to Array + var decodedArr = []; // Your Result goes here + // Only change code below this line + + decodedArr = codeArr.map(function(letter) { + if(lookup.hasOwnProperty(letter)) { + letter = lookup[letter]; + } + return letter; + }); + + // Only change code above this line + return decodedArr.join(""); // Array to String +} +``` + +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/javascript-algorithms-and-data-structures-projects/Cash Register.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/javascript-algorithms-and-data-structures-projects/Cash Register.md new file mode 100644 index 0000000000..b13614baf7 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/javascript-algorithms-and-data-structures-projects/Cash Register.md @@ -0,0 +1,135 @@ +--- +id: aa2e6f85cab2ab736c9a9b24 +title: Cash Register +isRequired: true +challengeType: 5 +--- + +## Description +
    +Design a cash register drawer function checkCashRegister() that accepts purchase price as the first argument (price), payment as the second argument (cash), and cash-in-drawer (cid) as the third argument. +cid is a 2D array listing available currency. +The checkCashRegister() function should always return an object with a status key and a change key. +Return {status: "INSUFFICIENT_FUNDS", change: []} if cash-in-drawer is less than the change due, or if you cannot return the exact change. +Return {status: "CLOSED", change: [...]} with cash-in-drawer as the value for the key change if it is equal to the change due. +Otherwise, return {status: "OPEN", change: [...]}, with the change due in coins and bills, sorted in highest to lowest order, as the value of the change key. +Remember to use Read-Search-Ask if you get stuck. Try to pair program. Write your own code. +
    Currency UnitAmount
    Penny$0.01 (PENNY)
    Nickel$0.05 (NICKEL)
    Dime$0.1 (DIME)
    Quarter$0.25 (QUARTER)
    Dollar$1 (DOLLAR)
    Five Dollars$5 (FIVE)
    Ten Dollars$10 (TEN)
    Twenty Dollars$20 (TWENTY)
    One-hundred Dollars$100 (ONE HUNDRED)
    +
    + +## Instructions +
    + +
    + +## Tests +
    + +```yml +- text: 'checkCashRegister(19.5, 20, [["PENNY", 1.01], ["NICKEL", 2.05], ["DIME", 3.1], ["QUARTER", 4.25], ["ONE", 90], ["FIVE", 55], ["TEN", 20], ["TWENTY", 60], ["ONE HUNDRED", 100]]) should return an object.' + testString: 'assert.deepEqual(Object.prototype.toString.call(checkCashRegister(19.5, 20, [["PENNY", 1.01], ["NICKEL", 2.05], ["DIME", 3.1], ["QUARTER", 4.25], ["ONE", 90], ["FIVE", 55], ["TEN", 20], ["TWENTY", 60], ["ONE HUNDRED", 100]])), "[object Object]", "checkCashRegister(19.5, 20, [["PENNY", 1.01], ["NICKEL", 2.05], ["DIME", 3.1], ["QUARTER", 4.25], ["ONE", 90], ["FIVE", 55], ["TEN", 20], ["TWENTY", 60], ["ONE HUNDRED", 100]]) should return an object.");' +- text: 'checkCashRegister(19.5, 20, [["PENNY", 1.01], ["NICKEL", 2.05], ["DIME", 3.1], ["QUARTER", 4.25], ["ONE", 90], ["FIVE", 55], ["TEN", 20], ["TWENTY", 60], ["ONE HUNDRED", 100]]) should return {status: "OPEN", change: [["QUARTER", 0.5]]}.' + testString: 'assert.deepEqual(checkCashRegister(19.5, 20, [["PENNY", 1.01], ["NICKEL", 2.05], ["DIME", 3.1], ["QUARTER", 4.25], ["ONE", 90], ["FIVE", 55], ["TEN", 20], ["TWENTY", 60], ["ONE HUNDRED", 100]]), {status: "OPEN", change: [["QUARTER", 0.5]]}, "checkCashRegister(19.5, 20, [["PENNY", 1.01], ["NICKEL", 2.05], ["DIME", 3.1], ["QUARTER", 4.25], ["ONE", 90], ["FIVE", 55], ["TEN", 20], ["TWENTY", 60], ["ONE HUNDRED", 100]]) should return {status: "OPEN", change: [["QUARTER", 0.5]]}.");' +- text: 'checkCashRegister(3.26, 100, [["PENNY", 1.01], ["NICKEL", 2.05], ["DIME", 3.1], ["QUARTER", 4.25], ["ONE", 90], ["FIVE", 55], ["TEN", 20], ["TWENTY", 60], ["ONE HUNDRED", 100]]) should return {status: "OPEN", change: [["TWENTY", 60], ["TEN", 20], ["FIVE", 15], ["ONE", 1], ["QUARTER", 0.5], ["DIME", 0.2], ["PENNY", 0.04]]}.' + testString: 'assert.deepEqual(checkCashRegister(3.26, 100, [["PENNY", 1.01], ["NICKEL", 2.05], ["DIME", 3.1], ["QUARTER", 4.25], ["ONE", 90], ["FIVE", 55], ["TEN", 20], ["TWENTY", 60], ["ONE HUNDRED", 100]]), {status: "OPEN", change: [["TWENTY", 60], ["TEN", 20], ["FIVE", 15], ["ONE", 1], ["QUARTER", 0.5], ["DIME", 0.2], ["PENNY", 0.04]]}, "checkCashRegister(3.26, 100, [["PENNY", 1.01], ["NICKEL", 2.05], ["DIME", 3.1], ["QUARTER", 4.25], ["ONE", 90], ["FIVE", 55], ["TEN", 20], ["TWENTY", 60], ["ONE HUNDRED", 100]]) should return {status: "OPEN", change: [["TWENTY", 60], ["TEN", 20], ["FIVE", 15], ["ONE", 1], ["QUARTER", 0.5], ["DIME", 0.2], ["PENNY", 0.04]]}.");' +- text: 'checkCashRegister(19.5, 20, [["PENNY", 0.01], ["NICKEL", 0], ["DIME", 0], ["QUARTER", 0], ["ONE", 0], ["FIVE", 0], ["TEN", 0], ["TWENTY", 0], ["ONE HUNDRED", 0]]) should return {status: "INSUFFICIENT_FUNDS", change: []}.' + testString: 'assert.deepEqual(checkCashRegister(19.5, 20, [["PENNY", 0.01], ["NICKEL", 0], ["DIME", 0], ["QUARTER", 0], ["ONE", 0], ["FIVE", 0], ["TEN", 0], ["TWENTY", 0], ["ONE HUNDRED", 0]]), {status: "INSUFFICIENT_FUNDS", change: []}, "checkCashRegister(19.5, 20, [["PENNY", 0.01], ["NICKEL", 0], ["DIME", 0], ["QUARTER", 0], ["ONE", 0], ["FIVE", 0], ["TEN", 0], ["TWENTY", 0], ["ONE HUNDRED", 0]]) should return {status: "INSUFFICIENT_FUNDS", change: []}.");' +- text: 'checkCashRegister(19.5, 20, [["PENNY", 0.01], ["NICKEL", 0], ["DIME", 0], ["QUARTER", 0], ["ONE", 1], ["FIVE", 0], ["TEN", 0], ["TWENTY", 0], ["ONE HUNDRED", 0]]) should return {status: "INSUFFICIENT_FUNDS", change: []}.' + testString: 'assert.deepEqual(checkCashRegister(19.5, 20, [["PENNY", 0.01], ["NICKEL", 0], ["DIME", 0], ["QUARTER", 0], ["ONE", 1], ["FIVE", 0], ["TEN", 0], ["TWENTY", 0], ["ONE HUNDRED", 0]]), {status: "INSUFFICIENT_FUNDS", change: []}, "checkCashRegister(19.5, 20, [["PENNY", 0.01], ["NICKEL", 0], ["DIME", 0], ["QUARTER", 0], ["ONE", 1], ["FIVE", 0], ["TEN", 0], ["TWENTY", 0], ["ONE HUNDRED", 0]]) should return {status: "INSUFFICIENT_FUNDS", change: []}.");' +- text: 'checkCashRegister(19.5, 20, [["PENNY", 0.5], ["NICKEL", 0], ["DIME", 0], ["QUARTER", 0], ["ONE", 0], ["FIVE", 0], ["TEN", 0], ["TWENTY", 0], ["ONE HUNDRED", 0]]) should return {status: "CLOSED", change: [["PENNY", 0.5], ["NICKEL", 0], ["DIME", 0], ["QUARTER", 0], ["ONE", 0], ["FIVE", 0], ["TEN", 0], ["TWENTY", 0], ["ONE HUNDRED", 0]]}.' + testString: 'assert.deepEqual(checkCashRegister(19.5, 20, [["PENNY", 0.5], ["NICKEL", 0], ["DIME", 0], ["QUARTER", 0], ["ONE", 0], ["FIVE", 0], ["TEN", 0], ["TWENTY", 0], ["ONE HUNDRED", 0]]), {status: "CLOSED", change: [["PENNY", 0.5], ["NICKEL", 0], ["DIME", 0], ["QUARTER", 0], ["ONE", 0], ["FIVE", 0], ["TEN", 0], ["TWENTY", 0], ["ONE HUNDRED", 0]]}, "checkCashRegister(19.5, 20, [["PENNY", 0.5], ["NICKEL", 0], ["DIME", 0], ["QUARTER", 0], ["ONE", 0], ["FIVE", 0], ["TEN", 0], ["TWENTY", 0], ["ONE HUNDRED", 0]]) should return {status: "CLOSED", change: [["PENNY", 0.5], ["NICKEL", 0], ["DIME", 0], ["QUARTER", 0], ["ONE", 0], ["FIVE", 0], ["TEN", 0], ["TWENTY", 0], ["ONE HUNDRED", 0]]}.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +function checkCashRegister(price, cash, cid) { + var change; + // Here is your change, ma'am. + return change; +} + +// Example cash-in-drawer array: +// [["PENNY", 1.01], +// ["NICKEL", 2.05], +// ["DIME", 3.1], +// ["QUARTER", 4.25], +// ["ONE", 90], +// ["FIVE", 55], +// ["TEN", 20], +// ["TWENTY", 60], +// ["ONE HUNDRED", 100]] + +checkCashRegister(19.5, 20, [["PENNY", 1.01], ["NICKEL", 2.05], ["DIME", 3.1], ["QUARTER", 4.25], ["ONE", 90], ["FIVE", 55], ["TEN", 20], ["TWENTY", 60], ["ONE HUNDRED", 100]]); +``` + +
    + + + +
    + +## Solution +
    + + +```js +var denom = [ + { name: 'ONE HUNDRED', val: 100}, + { name: 'TWENTY', val: 20}, + { name: 'TEN', val: 10}, + { name: 'FIVE', val: 5}, + { name: 'ONE', val: 1}, + { name: 'QUARTER', val: 0.25}, + { name: 'DIME', val: 0.1}, + { name: 'NICKEL', val: 0.05}, + { name: 'PENNY', val: 0.01} +]; + +function checkCashRegister(price, cash, cid) { + var output = {status: null, change: []}; + var change = cash - price; + var register = cid.reduce(function(acc, curr) { + acc.total += curr[1]; + acc[curr[0]] = curr[1]; + return acc; + }, {total: 0}); + if(register.total === change) { + output.status = 'CLOSED'; + output.change = cid; + return output; + } + if(register.total < change) { + output.status = 'INSUFFICIENT_FUNDS'; + return output; + } + var change_arr = denom.reduce(function(acc, curr) { + var value = 0; + while(register[curr.name] > 0 && change >= curr.val) { + change -= curr.val; + register[curr.name] -= curr.val; + value += curr.val; + change = Math.round(change * 100) / 100; + } + if(value > 0) { + acc.push([ curr.name, value ]); + } + return acc; + }, []); + if(change_arr.length < 1 || change > 0) { + output.status = 'INSUFFICIENT_FUNDS'; + return output; + } + output.status = 'OPEN'; + output.change = change_arr; + return output; +} +``` + +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/javascript-algorithms-and-data-structures-projects/Palindrome Checker.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/javascript-algorithms-and-data-structures-projects/Palindrome Checker.md new file mode 100644 index 0000000000..ee7324ccbb --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/javascript-algorithms-and-data-structures-projects/Palindrome Checker.md @@ -0,0 +1,96 @@ +--- +id: aaa48de84e1ecc7c742e1124 +title: Palindrome Checker +isRequired: true +challengeType: 5 +--- + +## Description +
    +Return true if the given string is a palindrome. Otherwise, return false. +A palindrome is a word or sentence that's spelled the same way both forward and backward, ignoring punctuation, case, and spacing. +Note
    You'll need to remove all non-alphanumeric characters (punctuation, spaces and symbols) and turn everything into the same case (lower or upper case) in order to check for palindromes. +We'll pass strings with varying formats, such as "racecar", "RaceCar", and "race CAR" among others. +We'll also pass strings with special symbols, such as "2A3*3a2", "2A3 3a2", and "2_A3*3#A2". +Remember to use Read-Search-Ask if you get stuck. Write your own code. +
    + +## Instructions +
    + +
    + +## Tests +
    + +```yml +- text: palindrome("eye") should return a boolean. + testString: 'assert(typeof palindrome("eye") === "boolean", "palindrome("eye") should return a boolean.");' +- text: palindrome("eye") should return true. + testString: 'assert(palindrome("eye") === true, "palindrome("eye") should return true.");' +- text: palindrome("_eye") should return true. + testString: 'assert(palindrome("_eye") === true, "palindrome("_eye") should return true.");' +- text: palindrome("race car") should return true. + testString: 'assert(palindrome("race car") === true, "palindrome("race car") should return true.");' +- text: palindrome("not a palindrome") should return false. + testString: 'assert(palindrome("not a palindrome") === false, "palindrome("not a palindrome") should return false.");' +- text: 'palindrome("A man, a plan, a canal. Panama") should return true.' + testString: 'assert(palindrome("A man, a plan, a canal. Panama") === true, "palindrome("A man, a plan, a canal. Panama") should return true.");' +- text: palindrome("never odd or even") should return true. + testString: 'assert(palindrome("never odd or even") === true, "palindrome("never odd or even") should return true.");' +- text: palindrome("nope") should return false. + testString: 'assert(palindrome("nope") === false, "palindrome("nope") should return false.");' +- text: palindrome("almostomla") should return false. + testString: 'assert(palindrome("almostomla") === false, "palindrome("almostomla") should return false.");' +- text: 'palindrome("My age is 0, 0 si ega ym.") should return true.' + testString: 'assert(palindrome("My age is 0, 0 si ega ym.") === true, "palindrome("My age is 0, 0 si ega ym.") should return true.");' +- text: palindrome("1 eye for of 1 eye.") should return false. + testString: 'assert(palindrome("1 eye for of 1 eye.") === false, "palindrome("1 eye for of 1 eye.") should return false.");' +- text: 'palindrome("0_0 (: /-\ :) 0-0") should return true.' + testString: 'assert(palindrome("0_0 (: /-\ :) 0-0") === true, "palindrome("0_0 (: /-\ :) 0-0") should return true.");' +- text: palindrome("five|\_/|four") should return false. + testString: 'assert(palindrome("five|\_/|four") === false, "palindrome("five|\_/|four") should return false.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +function palindrome(str) { + // Good luck! + return true; +} + + + +palindrome("eye"); +``` + +
    + + + +
    + +## Solution +
    + + +```js +function palindrome(str) { + var string = str.toLowerCase().split(/[^A-Za-z0-9]/gi).join("); + var aux = string.split("); + if (aux.join(") === aux.reverse().join(")){ + return true; + } + + return false; +} +``` + +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/javascript-algorithms-and-data-structures-projects/Roman Numeral Converter.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/javascript-algorithms-and-data-structures-projects/Roman Numeral Converter.md new file mode 100644 index 0000000000..54bedaa92d --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/javascript-algorithms-and-data-structures-projects/Roman Numeral Converter.md @@ -0,0 +1,118 @@ +--- +id: a7f4d8f2483413a6ce226cac +title: Roman Numeral Converter +isRequired: true +challengeType: 5 +--- + +## Description +
    +Convert the given number into a roman numeral. +All roman numerals answers should be provided in upper-case. +Remember to use Read-Search-Ask if you get stuck. Try to pair program. Write your own code. +
    + +## Instructions +
    + +
    + +## Tests +
    + +```yml +- text: convertToRoman(2) should return "II". + testString: 'assert.deepEqual(convertToRoman(2), "II", "convertToRoman(2) should return "II".");' +- text: convertToRoman(3) should return "III". + testString: 'assert.deepEqual(convertToRoman(3), "III", "convertToRoman(3) should return "III".");' +- text: convertToRoman(4) should return "IV". + testString: 'assert.deepEqual(convertToRoman(4), "IV", "convertToRoman(4) should return "IV".");' +- text: convertToRoman(5) should return "V". + testString: 'assert.deepEqual(convertToRoman(5), "V", "convertToRoman(5) should return "V".");' +- text: convertToRoman(9) should return "IX". + testString: 'assert.deepEqual(convertToRoman(9), "IX", "convertToRoman(9) should return "IX".");' +- text: convertToRoman(12) should return "XII". + testString: 'assert.deepEqual(convertToRoman(12), "XII", "convertToRoman(12) should return "XII".");' +- text: convertToRoman(16) should return "XVI". + testString: 'assert.deepEqual(convertToRoman(16), "XVI", "convertToRoman(16) should return "XVI".");' +- text: convertToRoman(29) should return "XXIX". + testString: 'assert.deepEqual(convertToRoman(29), "XXIX", "convertToRoman(29) should return "XXIX".");' +- text: convertToRoman(44) should return "XLIV". + testString: 'assert.deepEqual(convertToRoman(44), "XLIV", "convertToRoman(44) should return "XLIV".");' +- text: convertToRoman(45) should return "XLV" + testString: 'assert.deepEqual(convertToRoman(45), "XLV", "convertToRoman(45) should return "XLV"");' +- text: convertToRoman(68) should return "LXVIII" + testString: 'assert.deepEqual(convertToRoman(68), "LXVIII", "convertToRoman(68) should return "LXVIII"");' +- text: convertToRoman(83) should return "LXXXIII" + testString: 'assert.deepEqual(convertToRoman(83), "LXXXIII", "convertToRoman(83) should return "LXXXIII"");' +- text: convertToRoman(97) should return "XCVII" + testString: 'assert.deepEqual(convertToRoman(97), "XCVII", "convertToRoman(97) should return "XCVII"");' +- text: convertToRoman(99) should return "XCIX" + testString: 'assert.deepEqual(convertToRoman(99), "XCIX", "convertToRoman(99) should return "XCIX"");' +- text: convertToRoman(400) should return "CD" + testString: 'assert.deepEqual(convertToRoman(400), "CD", "convertToRoman(400) should return "CD"");' +- text: convertToRoman(500) should return "D" + testString: 'assert.deepEqual(convertToRoman(500), "D", "convertToRoman(500) should return "D"");' +- text: convertToRoman(501) should return "DI" + testString: 'assert.deepEqual(convertToRoman(501), "DI", "convertToRoman(501) should return "DI"");' +- text: convertToRoman(649) should return "DCXLIX" + testString: 'assert.deepEqual(convertToRoman(649), "DCXLIX", "convertToRoman(649) should return "DCXLIX"");' +- text: convertToRoman(798) should return "DCCXCVIII" + testString: 'assert.deepEqual(convertToRoman(798), "DCCXCVIII", "convertToRoman(798) should return "DCCXCVIII"");' +- text: convertToRoman(891) should return "DCCCXCI" + testString: 'assert.deepEqual(convertToRoman(891), "DCCCXCI", "convertToRoman(891) should return "DCCCXCI"");' +- text: convertToRoman(1000) should return "M" + testString: 'assert.deepEqual(convertToRoman(1000), "M", "convertToRoman(1000) should return "M"");' +- text: convertToRoman(1004) should return "MIV" + testString: 'assert.deepEqual(convertToRoman(1004), "MIV", "convertToRoman(1004) should return "MIV"");' +- text: convertToRoman(1006) should return "MVI" + testString: 'assert.deepEqual(convertToRoman(1006), "MVI", "convertToRoman(1006) should return "MVI"");' +- text: convertToRoman(1023) should return "MXXIII" + testString: 'assert.deepEqual(convertToRoman(1023), "MXXIII", "convertToRoman(1023) should return "MXXIII"");' +- text: convertToRoman(2014) should return "MMXIV" + testString: 'assert.deepEqual(convertToRoman(2014), "MMXIV", "convertToRoman(2014) should return "MMXIV"");' +- text: convertToRoman(3999) should return "MMMCMXCIX" + testString: 'assert.deepEqual(convertToRoman(3999), "MMMCMXCIX", "convertToRoman(3999) should return "MMMCMXCIX"");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +function convertToRoman(num) { + return num; +} + +convertToRoman(36); +``` + +
    + + + +
    + +## Solution +
    + + +```js +function convertToRoman(num) { + var ref = [['M', 1000], ['CM', 900], ['D', 500], ['CD', 400], ['C', 100], ['XC', 90], ['L', 50], ['XL', 40], ['X', 10], ['IX', 9], ['V', 5], ['IV', 4], ['I', 1]]; + var res = []; + ref.forEach(function(p) { + while (num >= p[1]) { + res.push(p[0]); + num -= p[1]; + } + }); + return res.join("); +} +``` + +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/javascript-algorithms-and-data-structures-projects/Telephone Number Validator.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/javascript-algorithms-and-data-structures-projects/Telephone Number Validator.md new file mode 100644 index 0000000000..7dde0d36c5 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/javascript-algorithms-and-data-structures-projects/Telephone Number Validator.md @@ -0,0 +1,119 @@ +--- +id: aff0395860f5d3034dc0bfc9 +title: Telephone Number Validator +challengeType: 5 +isRequired: true +--- + +## Description +
    +Return true if the passed string looks like a valid US phone number. +The user may fill out the form field any way they choose as long as it has the format of a valid US number. The following are examples of valid formats for US numbers (refer to the tests below for other variants): +
    555-555-5555
    (555)555-5555
    (555) 555-5555
    555 555 5555
    5555555555
    1 555 555 5555
    +For this challenge you will be presented with a string such as 800-692-7753 or 8oo-six427676;laskdjf. Your job is to validate or reject the US phone number based on any combination of the formats provided above. The area code is required. If the country code is provided, you must confirm that the country code is 1. Return true if the string is a valid US phone number; otherwise return false. +Remember to use Read-Search-Ask if you get stuck. Try to pair program. Write your own code. +
    + +## Instructions +
    + +
    + +## Tests +
    + +```yml +- text: telephoneCheck("555-555-5555") should return a boolean. + testString: 'assert(typeof telephoneCheck("555-555-5555") === "boolean", "telephoneCheck("555-555-5555") should return a boolean.");' +- text: telephoneCheck("1 555-555-5555") should return true. + testString: 'assert(telephoneCheck("1 555-555-5555") === true, "telephoneCheck("1 555-555-5555") should return true.");' +- text: telephoneCheck("1 (555) 555-5555") should return true. + testString: 'assert(telephoneCheck("1 (555) 555-5555") === true, "telephoneCheck("1 (555) 555-5555") should return true.");' +- text: telephoneCheck("5555555555") should return true. + testString: 'assert(telephoneCheck("5555555555") === true, "telephoneCheck("5555555555") should return true.");' +- text: telephoneCheck("555-555-5555") should return true. + testString: 'assert(telephoneCheck("555-555-5555") === true, "telephoneCheck("555-555-5555") should return true.");' +- text: telephoneCheck("(555)555-5555") should return true. + testString: 'assert(telephoneCheck("(555)555-5555") === true, "telephoneCheck("(555)555-5555") should return true.");' +- text: telephoneCheck("1(555)555-5555") should return true. + testString: 'assert(telephoneCheck("1(555)555-5555") === true, "telephoneCheck("1(555)555-5555") should return true.");' +- text: telephoneCheck("555-5555") should return false. + testString: 'assert(telephoneCheck("555-5555") === false, "telephoneCheck("555-5555") should return false.");' +- text: telephoneCheck("5555555") should return false. + testString: 'assert(telephoneCheck("5555555") === false, "telephoneCheck("5555555") should return false.");' +- text: telephoneCheck("1 555)555-5555") should return false. + testString: 'assert(telephoneCheck("1 555)555-5555") === false, "telephoneCheck("1 555)555-5555") should return false.");' +- text: telephoneCheck("1 555 555 5555") should return true. + testString: 'assert(telephoneCheck("1 555 555 5555") === true, "telephoneCheck("1 555 555 5555") should return true.");' +- text: telephoneCheck("1 456 789 4444") should return true. + testString: 'assert(telephoneCheck("1 456 789 4444") === true, "telephoneCheck("1 456 789 4444") should return true.");' +- text: 'telephoneCheck("123**&!!asdf#") should return false.' + testString: 'assert(telephoneCheck("123**&!!asdf#") === false, "telephoneCheck("123**&!!asdf#") should return false.");' +- text: telephoneCheck("55555555") should return false. + testString: 'assert(telephoneCheck("55555555") === false, "telephoneCheck("55555555") should return false.");' +- text: telephoneCheck("(6054756961)") should return false + testString: 'assert(telephoneCheck("(6054756961)") === false, "telephoneCheck("(6054756961)") should return false");' +- text: telephoneCheck("2 (757) 622-7382") should return false. + testString: 'assert(telephoneCheck("2 (757) 622-7382") === false, "telephoneCheck("2 (757) 622-7382") should return false.");' +- text: telephoneCheck("0 (757) 622-7382") should return false. + testString: 'assert(telephoneCheck("0 (757) 622-7382") === false, "telephoneCheck("0 (757) 622-7382") should return false.");' +- text: telephoneCheck("-1 (757) 622-7382") should return false + testString: 'assert(telephoneCheck("-1 (757) 622-7382") === false, "telephoneCheck("-1 (757) 622-7382") should return false");' +- text: telephoneCheck("2 757 622-7382") should return false. + testString: 'assert(telephoneCheck("2 757 622-7382") === false, "telephoneCheck("2 757 622-7382") should return false.");' +- text: telephoneCheck("10 (757) 622-7382") should return false. + testString: 'assert(telephoneCheck("10 (757) 622-7382") === false, "telephoneCheck("10 (757) 622-7382") should return false.");' +- text: telephoneCheck("27576227382") should return false. + testString: 'assert(telephoneCheck("27576227382") === false, "telephoneCheck("27576227382") should return false.");' +- text: telephoneCheck("(275)76227382") should return false. + testString: 'assert(telephoneCheck("(275)76227382") === false, "telephoneCheck("(275)76227382") should return false.");' +- text: telephoneCheck("2(757)6227382") should return false. + testString: 'assert(telephoneCheck("2(757)6227382") === false, "telephoneCheck("2(757)6227382") should return false.");' +- text: telephoneCheck("2(757)622-7382") should return false. + testString: 'assert(telephoneCheck("2(757)622-7382") === false, "telephoneCheck("2(757)622-7382") should return false.");' +- text: telephoneCheck("555)-555-5555") should return false. + testString: 'assert(telephoneCheck("555)-555-5555") === false, "telephoneCheck("555)-555-5555") should return false.");' +- text: telephoneCheck("(555-555-5555") should return false. + testString: 'assert(telephoneCheck("(555-555-5555") === false, "telephoneCheck("(555-555-5555") should return false.");' +- text: telephoneCheck("(555)5(55?)-5555") should return false. + testString: 'assert(telephoneCheck("(555)5(55?)-5555") === false, "telephoneCheck("(555)5(55?)-5555") should return false.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +function telephoneCheck(str) { + // Good luck! + return true; +} + +telephoneCheck("555-555-5555"); +``` + +
    + + + +
    + +## Solution +
    + + +```js +var re = /^([+]?1[\s]?)?((?:[(](?:[2-9]1[02-9]|[2-9][02-8][0-9])[)][\s]?)|(?:(?:[2-9]1[02-9]|[2-9][02-8][0-9])[\s.-]?)){1}([2-9]1[02-9]|[2-9][02-9]1|[2-9][02-9]{2}[\s.-]?){1}([0-9]{4}){1}$/; + +function telephoneCheck(str) { + return re.test(str); +} + +telephoneCheck("555-555-5555"); +``` + +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/javascript-algorithms-and-data-structures-projects/meta.json b/curriculum/challenges/02-javascript-algorithms-and-data-structures/javascript-algorithms-and-data-structures-projects/meta.json new file mode 100644 index 0000000000..3b55b50263 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/javascript-algorithms-and-data-structures-projects/meta.json @@ -0,0 +1,8 @@ +{ + "name": "JavaScript Algorithms and Data Structures Projects", + "dashedName": "javascript-algorithms-and-data-structures-projects", + "order": 10, + "time": "50 hours", + "superBlock": "javascript-algorithms-and-data-structures", + "superOrder": 2 +} \ No newline at end of file diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/object-oriented-programming/Add Methods After Inheritance.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/object-oriented-programming/Add Methods After Inheritance.md new file mode 100644 index 0000000000..194fad5ad6 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/object-oriented-programming/Add Methods After Inheritance.md @@ -0,0 +1,92 @@ +--- +id: 587d7db1367417b2b2512b87 +title: Add Methods After Inheritance +challengeType: 1 +--- + +## Description +
    +A constructor function that inherits its prototype object from a supertype constructor function can still have its own methods in addition to inherited methods. +For example, Bird is a constructor that inherits its prototype from Animal: +
    function Animal() { }
    Animal.prototype.eat = function() {
      console.log("nom nom nom");
    };
    function Bird() { }
    Bird.prototype = Object.create(Animal.prototype);
    Bird.prototype.constructor = Bird;
    +In addition to what is inherited from Animal, you want to add behavior that is unique to Bird objects. Here, Bird will get a fly() function. Functions are added to Bird's prototype the same way as any constructor function: +
    Bird.prototype.fly = function() {
      console.log("I'm flying!");
    };
    +Now instances of Bird will have both eat() and fly() methods: +
    let duck = new Bird();
    duck.eat(); // prints "nom nom nom"
    duck.fly(); // prints "I'm flying!"
    +
    + +## Instructions +
    +Add all necessary code so the Dog object inherits from Animal and the Dog's prototype constructor is set to Dog. Then add a bark() method to the Dog object so that beagle can both eat() and bark(). The bark() method should print "Woof!" to the console. +
    + +## Tests +
    + +```yml +- text: Animal should not respond to the bark() method. + testString: 'assert(typeof Animal.prototype.bark == "undefined", "Animal should not respond to the bark() method.");' +- text: Dog should inherit the eat() method from Animal. + testString: 'assert(typeof Dog.prototype.eat == "function", "Dog should inherit the eat() method from Animal.");' +- text: Dog should have the bark() method as an own property. + testString: 'assert(Dog.prototype.hasOwnProperty("bark"), "Dog should have the bark() method as an own property.");' +- text: beagle should be an instanceof Animal. + testString: 'assert(beagle instanceof Animal, "beagle should be an instanceof Animal.");' +- text: The constructor for beagle should be set to Dog. + testString: 'assert(beagle.constructor === Dog, "The constructor for beagle should be set to Dog.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +function Animal() { } +Animal.prototype.eat = function() { console.log("nom nom nom"); }; + +function Dog() { } + +// Add your code below this line + + + + +// Add your code above this line + +let beagle = new Dog(); + +beagle.eat(); // Should print "nom nom nom" +beagle.bark(); // Should print "Woof!" +``` + +
    + + + +
    + +## Solution +
    + + +```js +function Animal() { } +Animal.prototype.eat = function() { console.log("nom nom nom"); }; + +function Dog() { } +Dog.prototype = Object.create(Animal.prototype); +Dog.prototype.constructor = Dog; +Dog.prototype.bark = function () { + console.log('Woof!'); +}; +let beagle = new Dog(); + +beagle.eat(); +beagle.bark(); +``` + +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/object-oriented-programming/Change the Prototype to a New Object.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/object-oriented-programming/Change the Prototype to a New Object.md new file mode 100644 index 0000000000..714ee5f384 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/object-oriented-programming/Change the Prototype to a New Object.md @@ -0,0 +1,80 @@ +--- +id: 587d7daf367417b2b2512b7f +title: Change the Prototype to a New Object +challengeType: 1 +--- + +## Description +
    +Up until now you have been adding properties to the prototype individually: +
    Bird.prototype.numLegs = 2;
    +This becomes tedious after more than a few properties. +
    Bird.prototype.eat = function() {
      console.log("nom nom nom");
    }

    Bird.prototype.describe = function() {
      console.log("My name is " + this.name);
    }
    +A more efficient way is to set the prototype to a new object that already contains the properties. This way, the properties are added all at once: +
    Bird.prototype = {
      numLegs: 2,
      eat: function() {
        console.log("nom nom nom");
      },
      describe: function() {
        console.log("My name is " + this.name);
      }
    };
    +
    + +## Instructions +
    +Add the property numLegs and the two methods eat() and describe() to the prototype of Dog by setting the prototype to a new object. +
    + +## Tests +
    + +```yml +- text: Dog.prototype should be set to a new object. + testString: 'assert((/Dog\.prototype\s*?=\s*?{/).test(code), "Dog.prototype should be set to a new object.");' +- text: Dog.prototype should have the property numLegs. + testString: 'assert(Dog.prototype.numLegs !== undefined, "Dog.prototype should have the property numLegs.");' +- text: Dog.prototype should have the method eat(). + testString: 'assert(typeof Dog.prototype.eat === "function", "Dog.prototype should have the method eat()."); ' +- text: Dog.prototype should have the method describe(). + testString: 'assert(typeof Dog.prototype.describe === "function", "Dog.prototype should have the method describe()."); ' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +function Dog(name) { + this.name = name; +} + +Dog.prototype = { + // Add your code below this line + +}; +``` + +
    + + + +
    + +## Solution +
    + + +```js +function Dog(name) { + this.name = name; +} +Dog.prototype = { +numLegs: 4, + eat () { + console.log('nom nom nom'); + }, + describe () { + console.log('My name is ' + this.name); + } +}; +``` + +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/object-oriented-programming/Create a Basic JavaScript Object.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/object-oriented-programming/Create a Basic JavaScript Object.md new file mode 100644 index 0000000000..ce26fcbe2e --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/object-oriented-programming/Create a Basic JavaScript Object.md @@ -0,0 +1,65 @@ +--- +id: 587d7dac367417b2b2512b73 +title: Create a Basic JavaScript Object +challengeType: 1 +--- + +## Description +
    +Think about things people see everyday, like cars, shops, and birds. These are all objects: tangible things people can observe and interact with. +What are some qualities of these objects? A car has wheels. Shops sell items. Birds have wings. +These qualities, or properties, define what makes up an object. Note that similar objects share the same properties, but may have different values for those properties. For example, all cars have wheels, but not all cars have the same number of wheels. +Objects in JavaScript are used to model real-world objects, giving them properties and behavior just like their real-world counterparts. Here's an example using these concepts to create a duck object: +
    let duck = {
      name: "Aflac",
      numLegs: 2
    };
    +This duck object has two property/value pairs: a name of "Aflac" and a numLegs of 2. +
    + +## Instructions +
    +Create a dog object with name and numLegs properties, and set them to a string and a number, respectively. +
    + +## Tests +
    + +```yml +- text: dog should be an object. + testString: 'assert(typeof(dog) === "object", "dog should be an object.");' +- text: dog should have a name property set to a string. + testString: 'assert(typeof(dog.name) === "string", "dog should have a name property set to a string.");' +- text: dog should have a numLegs property set to a number. + testString: 'assert(typeof(dog.numLegs) === "number", "dog should have a numLegs property set to a number.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +let dog = { + +}; +``` + +
    + + + +
    + +## Solution +
    + + +```js +let dog = { + name: ", + numLegs: 4 +}; +``` + +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/object-oriented-programming/Create a Method on an Object.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/object-oriented-programming/Create a Method on an Object.md new file mode 100644 index 0000000000..c30e4ee70e --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/object-oriented-programming/Create a Method on an Object.md @@ -0,0 +1,71 @@ +--- +id: 587d7dad367417b2b2512b75 +title: Create a Method on an Object +challengeType: 1 +--- + +## Description +
    +Objects can have a special type of property, called a method. +Methods are properties that are functions. This adds different behavior to an object. Here is the duck example with a method: +
    let duck = {
      name: "Aflac",
      numLegs: 2,
      sayName: function() {return "The name of this duck is " + duck.name + ".";}
    };
    duck.sayName();
    // Returns "The name of this duck is Aflac."
    +The example adds the sayName method, which is a function that returns a sentence giving the name of the duck. +Notice that the method accessed the name property in the return statement using duck.name. The next challenge will cover another way to do this. +
    + +## Instructions +
    +Using the dog object, give it a method called sayLegs. The method should return the sentence "This dog has 4 legs." +
    + +## Tests +
    + +```yml +- text: dog.sayLegs() should be a function. + testString: 'assert(typeof(dog.sayLegs) === "function", "dog.sayLegs() should be a function.");' +- text: dog.sayLegs() should return the given string - note that punctuation and spacing matter. + testString: 'assert(dog.sayLegs() === "This dog has 4 legs.", "dog.sayLegs() should return the given string - note that punctuation and spacing matter.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +let dog = { + name: "Spot", + numLegs: 4, + +}; + +dog.sayLegs(); +``` + +
    + + + +
    + +## Solution +
    + + +```js +let dog = { + name: "Spot", + numLegs: 4, + sayLegs () { + return 'This dog has ' + this.numLegs + ' legs.'; + } +}; + +dog.sayLegs(); +``` + +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/object-oriented-programming/Define a Constructor Function.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/object-oriented-programming/Define a Constructor Function.md new file mode 100644 index 0000000000..08cbfeb11d --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/object-oriented-programming/Define a Constructor Function.md @@ -0,0 +1,64 @@ +--- +id: 587d7dad367417b2b2512b77 +title: Define a Constructor Function +challengeType: 1 +--- + +## Description +
    +Constructors are functions that create new objects. They define properties and behaviors that will belong to the new object. Think of them as a blueprint for the creation of new objects. +Here is an example of a constructor: +
    function Bird() {
      this.name = "Albert";
      this.color = "blue";
      this.numLegs = 2;
    }
    +This constructor defines a Bird object with properties name, color, and numLegs set to Albert, blue, and 2, respectively. +Constructors follow a few conventions: +
    • Constructors are defined with a capitalized name to distinguish them from other functions that are not constructors.
    • Constructors use the keyword this to set properties of the object they will create. Inside the constructor, this refers to the new object it will create.
    • Constructors define properties and behaviors instead of returning a value as other functions might.
    +
    + +## Instructions +
    +Create a constructor, Dog, with properties name, color, and numLegs that are set to a string, a string, and a number, respectively. +
    + +## Tests +
    + +```yml +- text: Dog should have a name property set to a string. + testString: 'assert(typeof (new Dog()).name === "string", "Dog should have a name property set to a string.");' +- text: Dog should have a color property set to a string. + testString: 'assert(typeof (new Dog()).color === "string", "Dog should have a color property set to a string.");' +- text: Dog should have a numLegs property set to a number. + testString: 'assert(typeof (new Dog()).numLegs === "number", "Dog should have a numLegs property set to a number.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js + +``` + +
    + + + +
    + +## Solution +
    + + +```js +function Dog (name, color, numLegs) { + this.name = 'name'; + this.color = 'color'; + this.numLegs = 4; +} +``` + +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/object-oriented-programming/Extend Constructors to Receive Arguments.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/object-oriented-programming/Extend Constructors to Receive Arguments.md new file mode 100644 index 0000000000..66775f11bd --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/object-oriented-programming/Extend Constructors to Receive Arguments.md @@ -0,0 +1,77 @@ +--- +id: 587d7dae367417b2b2512b79 +title: Extend Constructors to Receive Arguments +challengeType: 1 +--- + +## Description +
    +The Bird and Dog constructors from last challenge worked well. However, notice that all Birds that are created with the Bird constructor are automatically named Albert, are blue in color, and have two legs. What if you want birds with different values for name and color? It's possible to change the properties of each bird manually but that would be a lot of work: +
    let swan = new Bird();
    swan.name = "Carlos";
    swan.color = "white";
    +Suppose you were writing a program to keep track of hundreds or even thousands of different birds in an aviary. It would take a lot of time to create all the birds, then change the properties to different values for every one. +To more easily create different Bird objects, you can design your Bird constructor to accept parameters: +
    function Bird(name, color) {
      this.name = name;
      this.color = color;
      this.numLegs = 2;
    }
    +Then pass in the values as arguments to define each unique bird into the Bird constructor: +let cardinal = new Bird("Bruce", "red"); +This gives a new instance of Bird with name and color properties set to Bruce and red, respectively. The numLegs property is still set to 2. +The cardinal has these properties: +
    cardinal.name // => Bruce
    cardinal.color // => red
    cardinal.numLegs // => 2
    +The constructor is more flexible. It's now possible to define the properties for each Bird at the time it is created, which is one way that JavaScript constructors are so useful. They group objects together based on shared characteristics and behavior and define a blueprint that automates their creation. +
    + +## Instructions +
    +Create another Dog constructor. This time, set it up to take the parameters name and color, and have the property numLegs fixed at 4. Then create a new Dog saved in a variable terrier. Pass it two strings as arguments for the name and color properties. +
    + +## Tests +
    + +```yml +- text: Dog should receive an argument for name. + testString: 'assert((new Dog("Clifford")).name === "Clifford", "Dog should receive an argument for name.");' +- text: Dog should receive an argument for color. + testString: 'assert((new Dog("Clifford", "yellow")).color === "yellow", "Dog should receive an argument for color.");' +- text: Dog should have property numLegs set to 4. + testString: 'assert((new Dog("Clifford")).numLegs === 4, "Dog should have property numLegs set to 4.");' +- text: terrier should be created using the Dog constructor. + testString: 'assert(terrier instanceof Dog, "terrier should be created using the Dog constructor.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +function Dog() { + +} + + +``` + +
    + + + +
    + +## Solution +
    + + +```js +function Dog (name, color) { + this.numLegs = 4; + this.name = name; + this.color = color; +} + +const terrier = new Dog(); +``` + +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/object-oriented-programming/Inherit Behaviors from a Supertype.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/object-oriented-programming/Inherit Behaviors from a Supertype.md new file mode 100644 index 0000000000..811bcffd9a --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/object-oriented-programming/Inherit Behaviors from a Supertype.md @@ -0,0 +1,93 @@ +--- +id: 587d7db0367417b2b2512b84 +title: Inherit Behaviors from a Supertype +challengeType: 1 +--- + +## Description +
    +In the previous challenge, you created a supertype called Animal that defined behaviors shared by all animals: +
    function Animal() { }
    Animal.prototype.eat = function() {
      console.log("nom nom nom");
    };
    +This and the next challenge will cover how to reuse Animal's methods inside Bird and Dog without defining them again. It uses a technique called inheritance. +This challenge covers the first step: make an instance of the supertype (or parent). +You already know one way to create an instance of Animal using the new operator: +
    let animal = new Animal();
    +There are some disadvantages when using this syntax for inheritance, which are too complex for the scope of this challenge. Instead, here's an alternative approach without those disadvantages: +
    let animal = Object.create(Animal.prototype);
    +Object.create(obj) creates a new object, and sets obj as the new object's prototype. Recall that the prototype is like the "recipe" for creating an object. By setting the prototype of animal to be Animal's prototype, you are effectively giving the animal instance the same "recipe" as any other instance of Animal. +
    animal.eat(); // prints "nom nom nom"
    animal instanceof Animal; // => true
    +
    + +## Instructions +
    +Use Object.create to make two instances of Animal named duck and beagle. +
    + +## Tests +
    + +```yml +- text: The duck variable should be defined. + testString: 'assert(typeof duck !== "undefined", "The duck variable should be defined.");' +- text: The beagle variable should be defined. + testString: 'assert(typeof beagle !== "undefined", "The beagle variable should be defined.");' +- text: duck should have a prototype of Animal. + testString: 'assert(duck instanceof Animal, "duck should have a prototype of Animal.");' +- text: beagle should have a prototype of Animal. + testString: 'assert(beagle instanceof Animal, "beagle should have a prototype of Animal.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +function Animal() { } + +Animal.prototype = { + constructor: Animal, + eat: function() { + console.log("nom nom nom"); + } +}; + +// Add your code below this line + +let duck; // Change this line +let beagle; // Change this line + +duck.eat(); // Should print "nom nom nom" +beagle.eat(); // Should print "nom nom nom" +``` + +
    + + + +
    + +## Solution +
    + + +```js +function Animal() { } + +Animal.prototype = { + constructor: Animal, + eat: function() { + console.log("nom nom nom"); + } +}; +let duck = Object.create(Animal.prototype); +let beagle = Object.create(Animal.prototype); + +duck.eat(); +beagle.eat(); +``` + +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/object-oriented-programming/Iterate Over All Properties.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/object-oriented-programming/Iterate Over All Properties.md new file mode 100644 index 0000000000..b44f2f26c2 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/object-oriented-programming/Iterate Over All Properties.md @@ -0,0 +1,88 @@ +--- +id: 587d7daf367417b2b2512b7d +title: Iterate Over All Properties +challengeType: 1 +--- + +## Description +
    +You have now seen two kinds of properties: own properties and prototype properties. Own properties are defined directly on the object instance itself. And prototype properties are defined on the prototype. +
    function Bird(name) {
      this.name = name; //own property
    }

    Bird.prototype.numLegs = 2; // prototype property

    let duck = new Bird("Donald");
    +Here is how you add duck’s own properties to the array ownProps and prototype properties to the array prototypeProps: +
    let ownProps = [];
    let prototypeProps = [];

    for (let property in duck) {
      if(duck.hasOwnProperty(property)) {
        ownProps.push(property);
      } else {
        prototypeProps.push(property);
      }
    }

    console.log(ownProps); // prints ["name"]
    console.log(prototypeProps); // prints ["numLegs"]
    +
    + +## Instructions +
    +Add all of the own properties of beagle to the array ownProps. Add all of the prototype properties of Dog to the array prototypeProps. +
    + +## Tests +
    + +```yml +- text: The ownProps array should include "name". + testString: 'assert(ownProps.indexOf("name") !== -1, "The ownProps array should include "name".");' +- text: The prototypeProps array should include "numLegs". + testString: 'assert(prototypeProps.indexOf("numLegs") !== -1, "The prototypeProps array should include "numLegs".");' +- text: Solve this challenge without using the built in method Object.keys(). + testString: 'assert(!/\Object.keys/.test(code), "Solve this challenge without using the built in method Object.keys().");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +function Dog(name) { + this.name = name; +} + +Dog.prototype.numLegs = 4; + +let beagle = new Dog("Snoopy"); + +let ownProps = []; +let prototypeProps = []; + +// Add your code below this line + + + +``` + +
    + + + +
    + +## Solution +
    + + +```js +function Dog(name) { + this.name = name; +} + +Dog.prototype.numLegs = 4; + +let beagle = new Dog("Snoopy"); + +let ownProps = []; +let prototypeProps = []; +for (let prop in beagle) { + if (beagle.hasOwnProperty(prop)) { + ownProps.push(prop); + } else { + prototypeProps.push(prop); + } +} +``` + +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/object-oriented-programming/Make Code More Reusable with the this Keyword.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/object-oriented-programming/Make Code More Reusable with the this Keyword.md new file mode 100644 index 0000000000..49379e0e9e --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/object-oriented-programming/Make Code More Reusable with the this Keyword.md @@ -0,0 +1,73 @@ +--- +id: 587d7dad367417b2b2512b76 +title: Make Code More Reusable with the this Keyword +challengeType: 1 +--- + +## Description +
    +The last challenge introduced a method to the duck object. It used duck.name dot notation to access the value for the name property within the return statement: +sayName: function() {return "The name of this duck is " + duck.name + ".";} +While this is a valid way to access the object's property, there is a pitfall here. If the variable name changes, any code referencing the original name would need to be updated as well. In a short object definition, it isn't a problem, but if an object has many references to its properties there is a greater chance for error. +A way to avoid these issues is with the this keyword: +
    let duck = {
      name: "Aflac",
      numLegs: 2,
      sayName: function() {return "The name of this duck is " + this.name + ".";}
    };
    +this is a deep topic, and the above example is only one way to use it. In the current context, this refers to the object that the method is associated with: duck. +If the object's name is changed to mallard, it is not necessary to find all the references to duck in the code. It makes the code reusable and easier to read. +
    + +## Instructions +
    +Modify the dog.sayLegs method to remove any references to dog. Use the duck example for guidance. +
    + +## Tests +
    + +```yml +- text: dog.sayLegs() should return the given string. + testString: 'assert(dog.sayLegs() === "This dog has 4 legs.", "dog.sayLegs() should return the given string.");' +- text: Your code should use the this keyword to access the numLegs property of dog. + testString: 'assert(code.match(/this\.numLegs/g), "Your code should use the this keyword to access the numLegs property of dog.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +let dog = { + name: "Spot", + numLegs: 4, + sayLegs: function() {return "This dog has " + dog.numLegs + " legs.";} +}; + +dog.sayLegs(); +``` + +
    + + + +
    + +## Solution +
    + + +```js +let dog = { + name: "Spot", + numLegs: 4, + sayLegs () { + return 'This dog has ' + this.numLegs + ' legs.'; + } +}; + +dog.sayLegs(); +``` + +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/object-oriented-programming/Override Inherited Methods.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/object-oriented-programming/Override Inherited Methods.md new file mode 100644 index 0000000000..7f10a50aea --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/object-oriented-programming/Override Inherited Methods.md @@ -0,0 +1,88 @@ +--- +id: 587d7db1367417b2b2512b88 +title: Override Inherited Methods +challengeType: 1 +--- + +## Description +
    +In previous lessons, you learned that an object can inherit its behavior (methods) from another object by cloning its prototype object: +
    ChildObject.prototype = Object.create(ParentObject.prototype);
    +Then the ChildObject received its own methods by chaining them onto its prototype: +
    ChildObject.prototype.methodName = function() {...};
    +It's possible to override an inherited method. It's done the same way - by adding a method to ChildObject.prototype using the same method name as the one to override. +Here's an example of Bird overriding the eat() method inherited from Animal: +
    function Animal() { }
    Animal.prototype.eat = function() {
      return "nom nom nom";
    };
    function Bird() { }

    // Inherit all methods from Animal
    Bird.prototype = Object.create(Animal.prototype);

    // Bird.eat() overrides Animal.eat()
    Bird.prototype.eat = function() {
      return "peck peck peck";
    };
    +If you have an instance let duck = new Bird(); and you call duck.eat(), this is how JavaScript looks for the method on duck’s prototype chain: +1. duck => Is eat() defined here? No. +2. Bird => Is eat() defined here? => Yes. Execute it and stop searching. +3. Animal => eat() is also defined, but JavaScript stopped searching before reaching this level. +4. Object => JavaScript stopped searching before reaching this level. +
    + +## Instructions +
    +Override the fly() method for Penguin so that it returns "Alas, this is a flightless bird." +
    + +## Tests +
    + +```yml +- text: 'penguin.fly() should return the string "Alas, this is a flightless bird."' + testString: 'assert(penguin.fly() === "Alas, this is a flightless bird.", "penguin.fly() should return the string "Alas, this is a flightless bird."");' +- text: The bird.fly() method should return "I am flying!" + testString: 'assert((new Bird()).fly() === "I am flying!", "The bird.fly() method should return "I am flying!"");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +function Bird() { } + +Bird.prototype.fly = function() { return "I am flying!"; }; + +function Penguin() { } +Penguin.prototype = Object.create(Bird.prototype); +Penguin.prototype.constructor = Penguin; + +// Add your code below this line + + + +// Add your code above this line + +let penguin = new Penguin(); +console.log(penguin.fly()); +``` + +
    + + + +
    + +## Solution +
    + + +```js +function Bird() { } + +Bird.prototype.fly = function() { return "I am flying!"; }; + +function Penguin() { } +Penguin.prototype = Object.create(Bird.prototype); +Penguin.prototype.constructor = Penguin; +Penguin.prototype.fly = () => 'Alas, this is a flightless bird.'; +let penguin = new Penguin(); +console.log(penguin.fly()); +``` + +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/object-oriented-programming/Remember to Set the Constructor Property when Changing the Prototype.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/object-oriented-programming/Remember to Set the Constructor Property when Changing the Prototype.md new file mode 100644 index 0000000000..b4382c381d --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/object-oriented-programming/Remember to Set the Constructor Property when Changing the Prototype.md @@ -0,0 +1,80 @@ +--- +id: 587d7daf367417b2b2512b80 +title: Remember to Set the Constructor Property when Changing the Prototype +challengeType: 1 +--- + +## Description +
    +There is one crucial side effect of manually setting the prototype to a new object. It erased the constructor property! The code in the previous challenge would print the following for duck: +
    console.log(duck.constructor)
    // prints ‘undefined’ - Oops!
    +To fix this, whenever a prototype is manually set to a new object, remember to define the constructor property: +
    Bird.prototype = {
      constructor: Bird, // define the constructor property
      numLegs: 2,
      eat: function() {
        console.log("nom nom nom");
      },
      describe: function() {
        console.log("My name is " + this.name);
      }
    };
    +
    + +## Instructions +
    +Define the constructor property on the Dog prototype. +
    + +## Tests +
    + +```yml +- text: Dog.prototype should set the constructor property. + testString: 'assert(Dog.prototype.constructor === Dog, "Dog.prototype should set the constructor property.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +function Dog(name) { + this.name = name; +} + +// Modify the code below this line +Dog.prototype = { + + numLegs: 2, + eat: function() { + console.log("nom nom nom"); + }, + describe: function() { + console.log("My name is " + this.name); + } +}; +``` + +
    + + + +
    + +## Solution +
    + + +```js +function Dog(name) { + this.name = name; +} +Dog.prototype = { + constructor: Dog, + numLegs: 2, + eat: function() { + console.log("nom nom nom"); + }, + describe: function() { + console.log("My name is " + this.name); + } +}; +``` + +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/object-oriented-programming/Reset an Inherited Constructor Property.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/object-oriented-programming/Reset an Inherited Constructor Property.md new file mode 100644 index 0000000000..6adf25d9f2 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/object-oriented-programming/Reset an Inherited Constructor Property.md @@ -0,0 +1,81 @@ +--- +id: 587d7db1367417b2b2512b86 +title: Reset an Inherited Constructor Property +challengeType: 1 +--- + +## Description +
    +When an object inherits its prototype from another object, it also inherits the supertype's constructor property. +Here's an example: +
    function Bird() { }
    Bird.prototype = Object.create(Animal.prototype);
    let duck = new Bird();
    duck.constructor // function Animal(){...}
    +But duck and all instances of Bird should show that they were constructed by Bird and not Animal. To do so, you can manually set Bird's constructor property to the Bird object: +
    Bird.prototype.constructor = Bird;
    duck.constructor // function Bird(){...}
    +
    + +## Instructions +
    +Fix the code so duck.constructor and beagle.constructor return their respective constructors. +
    + +## Tests +
    + +```yml +- text: Bird.prototype should be an instance of Animal. + testString: 'assert(Animal.prototype.isPrototypeOf(Bird.prototype), "Bird.prototype should be an instance of Animal.");' +- text: duck.constructor should return Bird. + testString: 'assert(duck.constructor === Bird, "duck.constructor should return Bird.");' +- text: Dog.prototype should be an instance of Animal. + testString: 'assert(Animal.prototype.isPrototypeOf(Dog.prototype), "Dog.prototype should be an instance of Animal.");' +- text: beagle.constructor should return Dog. + testString: 'assert(beagle.constructor === Dog, "beagle.constructor should return Dog.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +function Animal() { } +function Bird() { } +function Dog() { } + +Bird.prototype = Object.create(Animal.prototype); +Dog.prototype = Object.create(Animal.prototype); + +// Add your code below this line + + + +let duck = new Bird(); +let beagle = new Dog(); +``` + +
    + + + +
    + +## Solution +
    + + +```js +function Animal() { } +function Bird() { } +function Dog() { } +Bird.prototype = Object.create(Animal.prototype); +Dog.prototype = Object.create(Animal.prototype); +Dog.prototype.constructor = Dog; +Bird.prototype.constructor = Bird; +let duck = new Bird(); +let beagle = new Dog(); +``` + +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/object-oriented-programming/Set the Child's Prototype to an Instance of the Parent.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/object-oriented-programming/Set the Child's Prototype to an Instance of the Parent.md new file mode 100644 index 0000000000..6ef45bcd04 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/object-oriented-programming/Set the Child's Prototype to an Instance of the Parent.md @@ -0,0 +1,84 @@ +--- +id: 587d7db1367417b2b2512b85 +title: Set the Child's Prototype to an Instance of the Parent +challengeType: 1 +--- + +## Description +
    +In the previous challenge you saw the first step for inheriting behavior from the supertype (or parent) Animal: making a new instance of Animal. +This challenge covers the next step: set the prototype of the subtype (or child)—in this case, Bird—to be an instance of Animal. +
    Bird.prototype = Object.create(Animal.prototype);
    +Remember that the prototype is like the "recipe" for creating an object. In a way, the recipe for Bird now includes all the key "ingredients" from Animal. +
    let duck = new Bird("Donald");
    duck.eat(); // prints "nom nom nom"
    +duck inherits all of Animal's properties, including the eat method. +
    + +## Instructions +
    +Modify the code so that instances of Dog inherit from Animal. +
    + +## Tests +
    + +```yml +- text: Dog.prototype should be an instance of Animal. + testString: 'assert(Animal.prototype.isPrototypeOf(Dog.prototype), "Dog.prototype should be an instance of Animal.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +function Animal() { } + +Animal.prototype = { + constructor: Animal, + eat: function() { + console.log("nom nom nom"); + } +}; + +function Dog() { } + +// Add your code below this line + + +let beagle = new Dog(); +beagle.eat(); // Should print "nom nom nom" +``` + +
    + + + +
    + +## Solution +
    + + +```js +function Animal() { } + +Animal.prototype = { + constructor: Animal, + eat: function() { + console.log("nom nom nom"); + } +}; + +function Dog() { } +Dog.prototype = Object.create(Animal.prototype); + +let beagle = new Dog(); +beagle.eat(); +``` + +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/object-oriented-programming/Understand Own Properties.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/object-oriented-programming/Understand Own Properties.md new file mode 100644 index 0000000000..cf6638e392 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/object-oriented-programming/Understand Own Properties.md @@ -0,0 +1,86 @@ +--- +id: 587d7dae367417b2b2512b7b +title: Understand Own Properties +challengeType: 1 +--- + +## Description +
    +In the following example, the Bird constructor defines two properties: name and numLegs: +
    function Bird(name) {
      this.name = name;
      this.numLegs = 2;
    }

    let duck = new Bird("Donald");
    let canary = new Bird("Tweety");
    +name and numLegs are called own properties, because they are defined directly on the instance object. That means that duck and canary each has its own separate copy of these properties. +In fact every instance of Bird will have its own copy of these properties. +The following code adds all of the own properties of duck to the array ownProps: +
    let ownProps = [];

    for (let property in duck) {
      if(duck.hasOwnProperty(property)) {
        ownProps.push(property);
      }
    }

    console.log(ownProps); // prints [ "name", "numLegs" ]
    +
    + +## Instructions +
    +Add the own properties of canary to the array ownProps. +
    + +## Tests +
    + +```yml +- text: ownProps should include the values "numLegs" and "name". + testString: 'assert(ownProps.indexOf("name") !== -1 && ownProps.indexOf("numLegs") !== -1, "ownProps should include the values "numLegs" and "name".");' +- text: Solve this challenge without using the built in method Object.keys(). + testString: 'assert(!/\Object.keys/.test(code), "Solve this challenge without using the built in method Object.keys().");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +function Bird(name) { + this.name = name; + this.numLegs = 2; +} + +let canary = new Bird("Tweety"); +let ownProps = []; +// Add your code below this line + + + +``` + +
    + + + +
    + +## Solution +
    + + +```js +function Bird(name) { + this.name = name; + this.numLegs = 2; +} + +let canary = new Bird("Tweety"); +function getOwnProps (obj) { + const props = []; + + for (let prop in obj) { + if (obj.hasOwnProperty(prop)) { + props.push(prop); + } + } + + return props; +} + +const ownProps = getOwnProps(canary); +``` + +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/object-oriented-programming/Understand Where an Object’s Prototype Comes From.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/object-oriented-programming/Understand Where an Object’s Prototype Comes From.md new file mode 100644 index 0000000000..42f6bb702e --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/object-oriented-programming/Understand Where an Object’s Prototype Comes From.md @@ -0,0 +1,66 @@ +--- +id: 587d7db0367417b2b2512b81 +title: Understand Where an Object’s Prototype Comes From +challengeType: 1 +--- + +## Description +
    +Just like people inherit genes from their parents, an object inherits its prototype directly from the constructor function that created it. For example, here the Bird constructor creates the duck object: +
    function Bird(name) {
      this.name = name;
    }

    let duck = new Bird("Donald");
    +duck inherits its prototype from the Bird constructor function. You can show this relationship with the isPrototypeOf method: +
    Bird.prototype.isPrototypeOf(duck);
    // returns true
    +
    + +## Instructions +
    +Use isPrototypeOf to check the prototype of beagle. +
    + +## Tests +
    + +```yml +- text: Show that Dog.prototype is the prototype of beagle + testString: 'assert(/Dog\.prototype\.isPrototypeOf\(beagle\)/.test(code), "Show that Dog.prototype is the prototype of beagle");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +function Dog(name) { + this.name = name; +} + +let beagle = new Dog("Snoopy"); + +// Add your code below this line + + +``` + +
    + + + +
    + +## Solution +
    + + +```js +function Dog(name) { + this.name = name; +} +let beagle = new Dog("Snoopy"); +Dog.prototype.isPrototypeOf(beagle); +``` + +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/object-oriented-programming/Understand the Constructor Property.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/object-oriented-programming/Understand the Constructor Property.md new file mode 100644 index 0000000000..8e41e0ba01 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/object-oriented-programming/Understand the Constructor Property.md @@ -0,0 +1,73 @@ +--- +id: 587d7daf367417b2b2512b7e +title: Understand the Constructor Property +challengeType: 1 +--- + +## Description +
    +There is a special constructor property located on the object instances duck and beagle that were created in the previous challenges: +
    let duck = new Bird();
    let beagle = new Dog();

    console.log(duck.constructor === Bird); //prints true
    console.log(beagle.constructor === Dog); //prints true
    +Note that the constructor property is a reference to the constructor function that created the instance. +The advantage of the constructor property is that it's possible to check for this property to find out what kind of object it is. Here's an example of how this could be used: +
    function joinBirdFraternity(candidate) {
      if (candidate.constructor === Bird) {
        return true;
      } else {
        return false;
      }
    }
    +Note
    Since the constructor property can be overwritten (which will be covered in the next two challenges) it’s generally better to use the instanceof method to check the type of an object. +
    + +## Instructions +
    +Write a joinDogFraternity function that takes a candidate parameter and, using the constructor property, return true if the candidate is a Dog, otherwise return false. +
    + +## Tests +
    + +```yml +- text: joinDogFraternity should be defined as a function. + testString: 'assert(typeof(joinDogFraternity) === "function", "joinDogFraternity should be defined as a function.");' +- text: joinDogFraternity should return true ifcandidate is an instance of Dog. + testString: 'assert(joinDogFraternity(new Dog("")) === true, "joinDogFraternity should return true ifcandidate is an instance of Dog.");' +- text: joinDogFraternity should use the constructor property. + testString: 'assert(/\.constructor/.test(code) && !/instanceof/.test(code), "joinDogFraternity should use the constructor property.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +function Dog(name) { + this.name = name; +} + +// Add your code below this line +function joinDogFraternity(candidate) { + +} + +``` + +
    + + + +
    + +## Solution +
    + + +```js +function Dog(name) { + this.name = name; +} +function joinDogFraternity(candidate) { + return candidate.constructor === Dog; +} +``` + +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/object-oriented-programming/Understand the Immediately Invoked Function Expression (IIFE).md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/object-oriented-programming/Understand the Immediately Invoked Function Expression (IIFE).md new file mode 100644 index 0000000000..c03bd300e8 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/object-oriented-programming/Understand the Immediately Invoked Function Expression (IIFE).md @@ -0,0 +1,61 @@ +--- +id: 587d7db2367417b2b2512b8b +title: Understand the Immediately Invoked Function Expression (IIFE) +challengeType: 1 +--- + +## Description +
    +A common pattern in JavaScript is to execute a function as soon as it is declared: +
    (function () {
      console.log("Chirp, chirp!");
    })(); // this is an anonymous function expression that executes right away
    // Outputs "Chirp, chirp!" immediately
    +Note that the function has no name and is not stored in a variable. The two parentheses () at the end of the function expression cause it to be immediately executed or invoked. This pattern is known as an immediately invoked function expression or IIFE. +
    + +## Instructions +
    +Rewrite the function makeNest and remove its call so instead it's an anonymous immediately invoked function expression (IIFE). +
    + +## Tests +
    + +```yml +- text: The function should be anonymous. + testString: 'assert(/\(\s*?function\s*?\(\s*?\)\s*?{/.test(code), "The function should be anonymous.");' +- text: Your function should have parentheses at the end of the expression to call it immediately. + testString: 'assert(/}\s*?\)\s*?\(\s*?\)/.test(code), "Your function should have parentheses at the end of the expression to call it immediately.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +function makeNest() { + console.log("A cozy nest is ready"); +} + +makeNest(); +``` + +
    + + + +
    + +## Solution +
    + + +```js +(function () { + console.log("A cozy nest is ready"); +})(); +``` + +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/object-oriented-programming/Understand the Prototype Chain.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/object-oriented-programming/Understand the Prototype Chain.md new file mode 100644 index 0000000000..815de8ca5a --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/object-oriented-programming/Understand the Prototype Chain.md @@ -0,0 +1,74 @@ +--- +id: 587d7db0367417b2b2512b82 +title: Understand the Prototype Chain +challengeType: 1 +--- + +## Description +
    +All objects in JavaScript (with a few exceptions) have a prototype. Also, an object’s prototype itself is an object. +
    function Bird(name) {
      this.name = name;
    }

    typeof Bird.prototype; // => object
    +Because a prototype is an object, a prototype can have its own prototype! In this case, the prototype of Bird.prototype is Object.prototype: +
    Object.prototype.isPrototypeOf(Bird.prototype);
    // returns true
    +How is this useful? You may recall the hasOwnProperty method from a previous challenge: +
    let duck = new Bird("Donald");
    duck.hasOwnProperty("name"); // => true
    +The hasOwnProperty method is defined in Object.prototype, which can be accessed by Bird.prototype, which can then be accessed by duck. This is an example of the prototype chain. +In this prototype chain, Bird is the supertype for duck, while duck is the subtype. Object is a supertype for both Bird and duck. +Object is a supertype for all objects in JavaScript. Therefore, any object can use the hasOwnProperty method. +
    + +## Instructions +
    +Modify the code to show the correct prototype chain. +
    + +## Tests +
    + +```yml +- text: Your code should show that Object.prototype is the prototype of Dog.prototype") + testString: 'assert(/Object\.prototype\.isPrototypeOf/.test(code), "Your code should show that Object.prototype is the prototype of Dog.prototype");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +function Dog(name) { + this.name = name; +} + +let beagle = new Dog("Snoopy"); + +Dog.prototype.isPrototypeOf(beagle); // => true + +// Fix the code below so that it evaluates to true +???.isPrototypeOf(Dog.prototype); + +``` + +
    + + + +
    + +## Solution +
    + + +```js +function Dog(name) { + this.name = name; +} +let beagle = new Dog("Snoopy"); +Dog.prototype.isPrototypeOf(beagle); +Object.prototype.isPrototypeOf(Dog.prototype); +``` + +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/object-oriented-programming/Use Closure to Protect Properties Within an Object from Being Modified Externally.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/object-oriented-programming/Use Closure to Protect Properties Within an Object from Being Modified Externally.md new file mode 100644 index 0000000000..c7e88bc74a --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/object-oriented-programming/Use Closure to Protect Properties Within an Object from Being Modified Externally.md @@ -0,0 +1,67 @@ +--- +id: 587d7db2367417b2b2512b8a +title: Use Closure to Protect Properties Within an Object from Being Modified Externally +challengeType: 1 +--- + +## Description +
    +In the previous challenge, bird had a public property name. It is considered public because it can be accessed and changed outside of bird's definition. +
    bird.name = "Duffy";
    +Therefore, any part of your code can easily change the name of bird to any value. Think about things like passwords and bank accounts being easily changeable by any part of your codebase. That could cause a lot of issues. +The simplest way to make properties private is by creating a variable within the constructor function. This changes the scope of that variable to be within the constructor function versus available globally. This way, the property can only be accessed and changed by methods also within the constructor function. +
    function Bird() {
      let hatchedEgg = 10; // private property

      this.getHatchedEggCount = function() { // publicly available method that a bird object can use
        return hatchedEgg;
      };
    }
    let ducky = new Bird();
    ducky.getHatchedEggCount(); // returns 10
    +Here getHachedEggCount is a privileged method, because it has access to the private variable hatchedEgg. This is possible because hatchedEgg is declared in the same context as getHachedEggCount. In JavaScript, a function always has access to the context in which it was created. This is called closure. +
    + +## Instructions +
    +Change how weight is declared in the Bird function so it is a private variable. Then, create a method getWeight that returns the value of weight. +
    + +## Tests +
    + +```yml +- text: The weight property should be a private variable. + testString: 'assert(!code.match(/this\.weight/g), "The weight property should be a private variable.");' +- text: Your code should create a method in Bird called getWeight that returns the weight. + testString: 'assert((new Bird()).getWeight() === 15, "Your code should create a method in Bird called getWeight that returns the weight.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +function Bird() { + this.weight = 15; + + +} + +``` + +
    + + + +
    + +## Solution +
    + + +```js +function Bird() { + let weight = 15; + + this.getWeight = () => weight; +} +``` + +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/object-oriented-programming/Use Dot Notation to Access the Properties of an Object.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/object-oriented-programming/Use Dot Notation to Access the Properties of an Object.md new file mode 100644 index 0000000000..7131789865 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/object-oriented-programming/Use Dot Notation to Access the Properties of an Object.md @@ -0,0 +1,66 @@ +--- +id: 587d7dac367417b2b2512b74 +title: Use Dot Notation to Access the Properties of an Object +challengeType: 1 +--- + +## Description +
    +The last challenge created an object with various properties, now you'll see how to access the values of those properties. Here's an example: +
    let duck = {
      name: "Aflac",
      numLegs: 2
    };
    console.log(duck.name);
    // This prints "Aflac" to the console
    +Dot notation is used on the object name, duck, followed by the name of the property, name, to access the value of "Aflac". +
    + +## Instructions +
    +Print both properties of the dog object below to your console. +
    + +## Tests +
    + +```yml +- text: Your should use console.log to print the value for the name property of the dog object. + testString: 'assert(/console.log\(.*dog\.name.*\)/g.test(code), "Your should use console.log to print the value for the name property of the dog object.");' +- text: Your should use console.log to print the value for the numLegs property of the dog object. + testString: 'assert(/console.log\(.*dog\.numLegs.*\)/g.test(code), "Your should use console.log to print the value for the numLegs property of the dog object.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +let dog = { + name: "Spot", + numLegs: 4 +}; +// Add your code below this line + + +``` + +
    + + + +
    + +## Solution +
    + + +```js +let dog = { + name: "Spot", + numLegs: 4 +}; +console.log(dog.name); +console.log(dog.numLegs); +``` + +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/object-oriented-programming/Use Inheritance So You Don't Repeat Yourself.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/object-oriented-programming/Use Inheritance So You Don't Repeat Yourself.md new file mode 100644 index 0000000000..47efd13b66 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/object-oriented-programming/Use Inheritance So You Don't Repeat Yourself.md @@ -0,0 +1,111 @@ +--- +id: 587d7db0367417b2b2512b83 +title: Use Inheritance So You Don't Repeat Yourself +challengeType: 1 +--- + +## Description +
    +There's a principle in programming called Don't Repeat Yourself (DRY). The reason repeated code is a problem is because any change requires fixing code in multiple places. This usually means more work for programmers and more room for errors. +Notice in the example below that the describe method is shared by Bird and Dog: +
    Bird.prototype = {
      constructor: Bird,
      describe: function() {
        console.log("My name is " + this.name);
      }
    };

    Dog.prototype = {
      constructor: Dog,
      describe: function() {
        console.log("My name is " + this.name);
      }
    };
    +The describe method is repeated in two places. The code can be edited to follow the DRY principle by creating a supertype (or parent) called Animal: +
    function Animal() { };

    Animal.prototype = {
      constructor: Animal,
      describe: function() {
        console.log("My name is " + this.name);
      }
    };
    +Since Animal includes the describe method, you can remove it from Bird and Dog: +
    Bird.prototype = {
      constructor: Bird
    };

    Dog.prototype = {
      constructor: Dog
    };
    +
    + +## Instructions +
    +The eat method is repeated in both Cat and Bear. Edit the code in the spirit of DRY by moving the eat method to the Animal supertype. +
    + +## Tests +
    + +```yml +- text: Animal.prototype should have the eat property. + testString: 'assert(Animal.prototype.hasOwnProperty("eat"), "Animal.prototype should have the eat property.");' +- text: Bear.prototype should not have the eat property. + testString: 'assert(!(Bear.prototype.hasOwnProperty("eat")), "Bear.prototype should not have the eat property.");' +- text: Cat.prototype should not have the eat property. + testString: 'assert(!(Cat.prototype.hasOwnProperty("eat")), "Cat.prototype should not have the eat property.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +function Cat(name) { + this.name = name; +} + +Cat.prototype = { + constructor: Cat, + eat: function() { + console.log("nom nom nom"); + } +}; + +function Bear(name) { + this.name = name; +} + +Bear.prototype = { + constructor: Bear, + eat: function() { + console.log("nom nom nom"); + } +}; + +function Animal() { } + +Animal.prototype = { + constructor: Animal, + +}; +``` + +
    + + + +
    + +## Solution +
    + + +```js +function Cat(name) { + this.name = name; +} + +Cat.prototype = { + constructor: Cat +}; + +function Bear(name) { + this.name = name; +} + +Bear.prototype = { + constructor: Bear +}; + +function Animal() { } + +Animal.prototype = { + constructor: Animal, + eat: function() { + console.log("nom nom nom"); + } +}; +``` + +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/object-oriented-programming/Use Prototype Properties to Reduce Duplicate Code.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/object-oriented-programming/Use Prototype Properties to Reduce Duplicate Code.md new file mode 100644 index 0000000000..ff10de8e73 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/object-oriented-programming/Use Prototype Properties to Reduce Duplicate Code.md @@ -0,0 +1,73 @@ +--- +id: 587d7dae367417b2b2512b7c +title: Use Prototype Properties to Reduce Duplicate Code +challengeType: 1 +--- + +## Description +
    +Since numLegs will probably have the same value for all instances of Bird, you essentially have a duplicated variable numLegs inside each Bird instance. +This may not be an issue when there are only two instances, but imagine if there are millions of instances. That would be a lot of duplicated variables. +A better way is to use Bird’s prototype. The prototype is an object that is shared among ALL instances of Bird. Here's how to add numLegs to the Bird prototype: +
    Bird.prototype.numLegs = 2;
    +Now all instances of Bird have the numLegs property. +
    console.log(duck.numLegs); // prints 2
    console.log(canary.numLegs); // prints 2
    +Since all instances automatically have the properties on the prototype, think of a prototype as a "recipe" for creating objects. +Note that the prototype for duck and canary is part of the Bird constructor as Bird.prototype. Nearly every object in JavaScript has a prototype property which is part of the constructor function that created it. +
    + +## Instructions +
    +Add a numLegs property to the prototype of Dog +
    + +## Tests +
    + +```yml +- text: beagle should have a numLegs property. + testString: 'assert(beagle.numLegs !== undefined, "beagle should have a numLegs property.");' +- text: beagle.numLegs should be a number. + testString: 'assert(typeof(beagle.numLegs) === "number" , "beagle.numLegs should be a number.");' +- text: numLegs should be a prototype property not an own property. + testString: 'assert(beagle.hasOwnProperty("numLegs") === false, "numLegs should be a prototype property not an own property.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +function Dog(name) { + this.name = name; +} + + + +// Add your code above this line +let beagle = new Dog("Snoopy"); +``` + +
    + + + +
    + +## Solution +
    + + +```js +function Dog (name) { + this.name = name; +} +Dog.prototype.numLegs = 4; +let beagle = new Dog("Snoopy"); +``` + +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/object-oriented-programming/Use a Constructor to Create Objects.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/object-oriented-programming/Use a Constructor to Create Objects.md new file mode 100644 index 0000000000..99319a3009 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/object-oriented-programming/Use a Constructor to Create Objects.md @@ -0,0 +1,71 @@ +--- +id: 587d7dad367417b2b2512b78 +title: Use a Constructor to Create Objects +challengeType: 1 +--- + +## Description +
    +Here's the Bird constructor from the previous challenge: +
    function Bird() {
      this.name = "Albert";
      this.color = "blue";
      this.numLegs = 2;
      // "this" inside the constructor always refers to the object being created
    }

    let blueBird = new Bird();
    +Notice that the new operator is used when calling a constructor. This tells JavaScript to create a new instance of Bird called blueBird. Without the new operator, this inside the constructor would not point to the newly created object, giving unexpected results. +Now blueBird has all the properties defined inside the Bird constructor: +
    blueBird.name; // => Albert
    blueBird.color; // => blue
    blueBird.numLegs; // => 2
    +Just like any other object, its properties can be accessed and modified: +
    blueBird.name = 'Elvira';
    blueBird.name; // => Elvira
    +
    + +## Instructions +
    +Use the Dog constructor from the last lesson to create a new instance of Dog, assigning it to a variable hound. +
    + +## Tests +
    + +```yml +- text: hound should be created using the Dog constructor. + testString: 'assert(hound instanceof Dog, "hound should be created using the Dog constructor.");' +- text: Your code should use the new operator to create an instance of Dog. + testString: 'assert(code.match(/new/g), "Your code should use the new operator to create an instance of Dog.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +function Dog() { + this.name = "Rupert"; + this.color = "brown"; + this.numLegs = 4; +} +// Add your code below this line + + +``` + +
    + + + +
    + +## Solution +
    + + +```js +function Dog() { + this.name = "Rupert"; + this.color = "brown"; + this.numLegs = 4; +} +const hound = new Dog(); +``` + +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/object-oriented-programming/Use a Mixin to Add Common Behavior Between Unrelated Objects.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/object-oriented-programming/Use a Mixin to Add Common Behavior Between Unrelated Objects.md new file mode 100644 index 0000000000..cae56b2ea7 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/object-oriented-programming/Use a Mixin to Add Common Behavior Between Unrelated Objects.md @@ -0,0 +1,92 @@ +--- +id: 587d7db2367417b2b2512b89 +title: Use a Mixin to Add Common Behavior Between Unrelated Objects +challengeType: 1 +--- + +## Description +
    +As you have seen, behavior is shared through inheritance. However, there are cases when inheritance is not the best solution. Inheritance does not work well for unrelated objects like Bird and Airplane. They can both fly, but a Bird is not a type of Airplane and vice versa. +For unrelated objects, it's better to use mixins. A mixin allows other objects to use a collection of functions. +
    let flyMixin = function(obj) {
      obj.fly = function() {
        console.log("Flying, wooosh!");
      }
    };
    +The flyMixin takes any object and gives it the fly method. +
    let bird = {
      name: "Donald",
      numLegs: 2
    };

    let plane = {
      model: "777",
      numPassengers: 524
    };

    flyMixin(bird);
    flyMixin(plane);
    +Here bird and plane are passed into flyMixin, which then assigns the fly function to each object. Now bird and plane can both fly: +
    bird.fly(); // prints "Flying, wooosh!"
    plane.fly(); // prints "Flying, wooosh!"
    +Note how the mixin allows for the same fly method to be reused by unrelated objects bird and plane. +
    + +## Instructions +
    +Create a mixin named glideMixin that defines a method named glide. Then use the glideMixin to give both bird and boat the ability to glide. +
    + +## Tests +
    + +```yml +- text: Your code should declare a glideMixin variable that is a function. + testString: 'assert(typeof glideMixin === "function", "Your code should declare a glideMixin variable that is a function.");' +- text: Your code should use the glideMixin on the bird object to give it the glide method. + testString: 'assert(typeof bird.glide === "function", "Your code should use the glideMixin on the bird object to give it the glide method.");' +- text: Your code should use the glideMixin on the boat object to give it the glide method. + testString: 'assert(typeof boat.glide === "function", "Your code should use the glideMixin on the boat object to give it the glide method.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +let bird = { + name: "Donald", + numLegs: 2 +}; + +let boat = { + name: "Warrior", + type: "race-boat" +}; + +// Add your code below this line + + + + + + +``` + +
    + + + +
    + +## Solution +
    + + +```js +let bird = { + name: "Donald", + numLegs: 2 +}; + +let boat = { + name: "Warrior", + type: "race-boat" +}; +function glideMixin (obj) { + obj.glide = () => 'Gliding!'; +} + +glideMixin(bird); +glideMixin(boat); +``` + +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/object-oriented-programming/Use an IIFE to Create a Module.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/object-oriented-programming/Use an IIFE to Create a Module.md new file mode 100644 index 0000000000..e96d23c9ac --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/object-oriented-programming/Use an IIFE to Create a Module.md @@ -0,0 +1,79 @@ +--- +id: 587d7db2367417b2b2512b8c +title: Use an IIFE to Create a Module +challengeType: 1 +--- + +## Description +
    +An immediately invoked function expression (IIFE) is often used to group related functionality into a single object or module. For example, an earlier challenge defined two mixins: +
    function glideMixin(obj) {
      obj.glide = function() {
        console.log("Gliding on the water");
      };
    }
    function flyMixin(obj) {
      obj.fly = function() {
        console.log("Flying, wooosh!");
      };
    }
    +We can group these mixins into a module as follows: +
    let motionModule = (function () {
      return {
        glideMixin: function (obj) {
          obj.glide = function() {
            console.log("Gliding on the water");
          };
        },
        flyMixin: function(obj) {
          obj.fly = function() {
            console.log("Flying, wooosh!");
          };
        }
      }
    }) (); // The two parentheses cause the function to be immediately invoked
    +Note that you have an immediately invoked function expression (IIFE) that returns an object motionModule. This returned object contains all of the mixin behaviors as properties of the object. +The advantage of the module pattern is that all of the motion behaviors can be packaged into a single object that can then be used by other parts of your code. Here is an example using it: +
    motionModule.glideMixin(duck);
    duck.glide();
    +
    + +## Instructions +
    +Create a module named funModule to wrap the two mixins isCuteMixin and singMixin. funModule should return an object. +
    + +## Tests +
    + +```yml +- text: funModule should be defined and return an object. + testString: 'assert(typeof funModule === "object", "funModule should be defined and return an object.");' +- text: funModule.isCuteMixin should access a function. + testString: 'assert(typeof funModule.isCuteMixin === "function", "funModule.isCuteMixin should access a function.");' +- text: funModule.singMixin should access a function. + testString: 'assert(typeof funModule.singMixin === "function", "funModule.singMixin should access a function.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +let isCuteMixin = function(obj) { + obj.isCute = function() { + return true; + }; +}; +let singMixin = function(obj) { + obj.sing = function() { + console.log("Singing to an awesome tune"); + }; +}; +``` + +
    + + + +
    + +## Solution +
    + + +```js +const funModule = (function () { + return { + isCuteMixin: obj => { + obj.isCute = () => true; + }, + singMixin: obj => { + obj.sing = () => console.log("Singing to an awesome tune"); + } + }; +})(); +``` + +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/object-oriented-programming/Verify an Object's Constructor with instanceof.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/object-oriented-programming/Verify an Object's Constructor with instanceof.md new file mode 100644 index 0000000000..de78720614 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/object-oriented-programming/Verify an Object's Constructor with instanceof.md @@ -0,0 +1,69 @@ +--- +id: 587d7dae367417b2b2512b7a +title: Verify an Object's Constructor with instanceof +challengeType: 1 +--- + +## Description +
    +Anytime a constructor function creates a new object, that object is said to be an instance of its constructor. JavaScript gives a convenient way to verify this with the instanceof operator. instanceof allows you to compare an object to a constructor, returning true or false based on whether or not that object was created with the constructor. Here's an example: +
    let Bird = function(name, color) {
      this.name = name;
      this.color = color;
      this.numLegs = 2;
    }

    let crow = new Bird("Alexis", "black");

    crow instanceof Bird; // => true
    +If an object is created without using a constructor, instanceof will verify that it is not an instance of that constructor: +
    let canary = {
      name: "Mildred",
      color: "Yellow",
      numLegs: 2
    };

    canary instanceof Bird; // => false
    +
    + +## Instructions +
    +Create a new instance of the House constructor, calling it myHouse and passing a number of bedrooms. Then, use instanceof to verify that it is an instance of House. +
    + +## Tests +
    + +```yml +- text: myHouse should have a numBedrooms attribute set to a number. + testString: 'assert(typeof myHouse.numBedrooms === "number", "myHouse should have a numBedrooms attribute set to a number.");' +- text: Be sure to verify that myHouse is an instance of House using the instanceof operator. + testString: 'assert(/myHouse\s*instanceof\s*House/.test(code), "Be sure to verify that myHouse is an instance of House using the instanceof operator.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +/* jshint expr: true */ + +function House(numBedrooms) { + this.numBedrooms = numBedrooms; +} + +// Add your code below this line + + + +``` + +
    + + + +
    + +## Solution +
    + + +```js +function House(numBedrooms) { + this.numBedrooms = numBedrooms; +} +const myHouse = new House(4); +console.log(myHouse instanceof House); +``` + +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/object-oriented-programming/meta.json b/curriculum/challenges/02-javascript-algorithms-and-data-structures/object-oriented-programming/meta.json new file mode 100644 index 0000000000..e1e66fa513 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/object-oriented-programming/meta.json @@ -0,0 +1,8 @@ +{ + "name": "Object Oriented Programming", + "dashedName": "object-oriented-programming", + "order": 7, + "time": "5 hours", + "superBlock": "javascript-algorithms-and-data-structures", + "superOrder": 2 +} \ No newline at end of file diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Check for All or None.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Check for All or None.md new file mode 100644 index 0000000000..07815fa933 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Check for All or None.md @@ -0,0 +1,60 @@ +--- +id: 587d7dba367417b2b2512ba8 +title: Check for All or None +challengeType: 1 +--- + +## Description +
    +Sometimes the patterns you want to search for may have parts of it that may or may not exist. However, it may be important to check for them nonetheless. +You can specify the possible existence of an element with a question mark, ?. This checks for zero or one of the preceding element. You can think of this symbol as saying the previous element is optional. +For example, there are slight differences in American and British English and you can use the question mark to match both spellings. +
    let american = "color";
    let british = "colour";
    let rainbowRegex= /colou?r/;
    rainbowRegex.test(american); // Returns true
    rainbowRegex.test(british); // Returns true
    +
    + +## Instructions +
    +Change the regex favRegex to match both the American English (favorite) and the British English (favourite) version of the word. +
    + +## Tests +
    + +```yml +- text: 'Your regex should use the optional symbol, ?.' + testString: 'assert(favRegex.source.match(/\?/).length > 0, "Your regex should use the optional symbol, ?.");' +- text: Your regex should match "favorite" + testString: 'assert(favRegex.test("favorite"), "Your regex should match "favorite"");' +- text: Your regex should match "favourite" + testString: 'assert(favRegex.test("favourite"), "Your regex should match "favourite"");' +- text: Your regex should not match "fav" + testString: 'assert(!favRegex.test("fav"), "Your regex should not match "fav"");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +let favWord = "favorite"; +let favRegex = /change/; // Change this line +let result = favRegex.test(favWord); +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Extract Matches.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Extract Matches.md new file mode 100644 index 0000000000..0bd37b3df1 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Extract Matches.md @@ -0,0 +1,57 @@ +--- +id: 587d7db4367417b2b2512b92 +title: Extract Matches +challengeType: 1 +--- + +## Description +
    +So far, you have only been checking if a pattern exists or not within a string. You can also extract the actual matches you found with the .match() method. +To use the .match() method, apply the method on a string and pass in the regex inside the parentheses. Here's an example: +
    "Hello, World!".match(/Hello/);
    // Returns ["Hello"]
    let ourStr = "Regular expressions";
    let ourRegex = /expressions/;
    ourStr.match(ourRegex);
    // Returns ["expressions"]
    +
    + +## Instructions +
    +Apply the .match() method to extract the word coding. +
    + +## Tests +
    + +```yml +- text: The result should have the word coding + testString: 'assert(result.join() === "coding", "The result should have the word coding");' +- text: Your regex codingRegex should search for coding + testString: 'assert(codingRegex.source === "coding", "Your regex codingRegex should search for coding");' +- text: You should use the .match() method. + testString: 'assert(code.match(/\.match\(.*\)/), "You should use the .match() method.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +let extractStr = "Extract the word 'coding' from this string."; +let codingRegex = /change/; // Change this line +let result = extractStr; // Change this line +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Find Characters with Lazy Matching.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Find Characters with Lazy Matching.md new file mode 100644 index 0000000000..3d6cda6236 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Find Characters with Lazy Matching.md @@ -0,0 +1,54 @@ +--- +id: 587d7db6367417b2b2512b9b +title: Find Characters with Lazy Matching +challengeType: 1 +--- + +## Description +
    +In regular expressions, a greedy match finds the longest possible part of a string that fits the regex pattern and returns it as a match. The alternative is called a lazy match, which finds the smallest possible part of the string that satisfies the regex pattern. +You can apply the regex /t[a-z]*i/ to the string "titanic". This regex is basically a pattern that starts with t, ends with i, and has some letters in between. +Regular expressions are by default greedy, so the match would return ["titani"]. It finds the largest sub-string possible to fit the pattern. +However, you can use the ? character to change it to lazy matching. "titanic" matched against the adjusted regex of /t[a-z]*?i/ returns ["ti"]. +
    + +## Instructions +
    +Fix the regex /<.*>/ to return the HTML tag <h1> and not the text "<h1>Winter is coming</h1>". Remember the wildcard . in a regular expression matches any character. +
    + +## Tests +
    + +```yml +- text: The result variable should be an array with <h1> in it + testString: 'assert(result[0] == "

    ", "The result variable should be an array with <h1> in it");' + +``` + +

    + +## Challenge Seed +
    + +
    + +```js +let text = "

    Winter is coming

    "; +let myRegex = /<.*>/; // Change this line +let result = text.match(myRegex); +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Find More Than the First Match.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Find More Than the First Match.md new file mode 100644 index 0000000000..697ec9c7b8 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Find More Than the First Match.md @@ -0,0 +1,61 @@ +--- +id: 587d7db4367417b2b2512b93 +title: Find More Than the First Match +challengeType: 1 +--- + +## Description +
    +So far, you have only been able to extract or search a pattern once. +
    let testStr = "Repeat, Repeat, Repeat";
    let ourRegex = /Repeat/;
    testStr.match(ourRegex);
    // Returns ["Repeat"]
    +To search or extract a pattern more than once, you can use the g flag. +
    let repeatRegex = /Repeat/g;
    testStr.match(repeatRegex);
    // Returns ["Repeat", "Repeat", "Repeat"]
    +
    + +## Instructions +
    +Using the regex starRegex, find and extract both "Twinkle" words from the string twinkleStar. +Note
    You can have multiple flags on your regex like /search/gi +
    + +## Tests +
    + +```yml +- text: Your regex starRegex should use the global flag g + testString: 'assert(starRegex.flags.match(/g/).length == 1, "Your regex starRegex should use the global flag g");' +- text: Your regex starRegex should use the case insensitive flag i + testString: 'assert(starRegex.flags.match(/i/).length == 1, "Your regex starRegex should use the case insensitive flag i");' +- text: Your match should match both occurrences of the word "Twinkle" + testString: 'assert(result.sort().join() == twinkleStar.match(/twinkle/gi).sort().join(), "Your match should match both occurrences of the word "Twinkle"");' +- text: Your match result should have two elements in it. + testString: 'assert(result.length == 2, "Your match result should have two elements in it.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +let twinkleStar = "Twinkle, twinkle, little star"; +let starRegex = /change/; // Change this line +let result = twinkleStar; // Change this line +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Find One or More Criminals in a Hunt.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Find One or More Criminals in a Hunt.md new file mode 100644 index 0000000000..daac00c920 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Find One or More Criminals in a Hunt.md @@ -0,0 +1,72 @@ +--- +id: 587d7db7367417b2b2512b9c +title: Find One or More Criminals in a Hunt +challengeType: 1 +--- + +## Description +
    +Time to pause and test your new regex writing skills. A group of criminals escaped from jail and ran away, but you don't know how many. However, you do know that they stay close together when they are around other people. You are responsible for finding all of the criminals at once. +Here's an example to review how to do this: +The regex /z+/ matches the letter z when it appears one or more times in a row. It would find matches in all of the following strings: +
    "z"
    "zzzzzz"
    "ABCzzzz"
    "zzzzABC"
    "abczzzzzzzzzzzzzzzzzzzzzabc"
    +But it does not find matches in the following strings since there are no letter z characters: +
    ""
    "ABC"
    "abcabc"
    +
    + +## Instructions +
    +Write a greedy regex that finds one or more criminals within a group of other people. A criminal is represented by the capital letter C. +
    + +## Tests +
    + +```yml +- text: Your regex should match one criminal ("C") in "C" + testString: 'assert("C".match(reCriminals) && "C".match(reCriminals)[0] == "C", "Your regex should match one criminal ("C") in "C"");' +- text: Your regex should match two criminals ("CC") in "CC" + testString: 'assert("CC".match(reCriminals) && "CC".match(reCriminals)[0] == "CC", "Your regex should match two criminals ("CC") in "CC"");' +- text: Your regex should match three criminals ("CCC") in "P1P5P4CCCP2P6P3" + testString: 'assert("P1P5P4CCCP2P6P3".match(reCriminals) && "P1P5P4CCCP2P6P3".match(reCriminals)[0] == "CCC", "Your regex should match three criminals ("CCC") in "P1P5P4CCCP2P6P3"");' +- text: Your regex should match five criminals ("CCCCC") in "P6P2P7P4P5CCCCCP3P1" + testString: 'assert("P6P2P7P4P5CCCCCP3P1".match(reCriminals) && "P6P2P7P4P5CCCCCP3P1".match(reCriminals)[0] == "CCCCC", "Your regex should match five criminals ("CCCCC") in "P6P2P7P4P5CCCCCP3P1"");' +- text: Your regex should not match any criminals in "" + testString: 'assert(!reCriminals.test(""), "Your regex should not match any criminals in """);' +- text: Your regex should not match any criminals in "P1P2P3" + testString: 'assert(!reCriminals.test("P1P2P3"), "Your regex should not match any criminals in "P1P2P3"");' +- text: Your regex should match fifty criminals ("CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC") in "P2P1P5P4CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCP3". + testString: 'assert("P2P1P5P4CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCP3".match(reCriminals) && "P2P1P5P4CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCP3".match(reCriminals)[0] == "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC", "Your regex should match fifty criminals ("CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC") in "P2P1P5P4CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCP3".");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +// example crowd gathering +let crowd = 'P1P2P3P4P5P6CCCP7P8P9'; + +let reCriminals = /./; // Change this line + +let matchedCriminals = crowd.match(reCriminals); +console.log(matchedCriminals); +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Ignore Case While Matching.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Ignore Case While Matching.md new file mode 100644 index 0000000000..9a78eace67 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Ignore Case While Matching.md @@ -0,0 +1,71 @@ +--- +id: 587d7db4367417b2b2512b91 +title: Ignore Case While Matching +challengeType: 1 +--- + +## Description +
    +Up until now, you've looked at regexes to do literal matches of strings. But sometimes, you might want to also match case differences. +Case (or sometimes letter case) is the difference between uppercase letters and lowercase letters. Examples of uppercase are "A", "B", and "C". Examples of lowercase are "a", "b", and "c". +You can match both cases using what is called a flag. There are other flags but here you'll focus on the flag that ignores case - the i flag. You can use it by appending it to the regex. An example of using this flag is /ignorecase/i. This regex can match the strings "ignorecase", "igNoreCase", and "IgnoreCase". +
    + +## Instructions +
    +Write a regex fccRegex to match "freeCodeCamp", no matter its case. Your regex should not match any abbreviations or variations with spaces. +
    + +## Tests +
    + +```yml +- text: Your regex should match freeCodeCamp + testString: 'assert(fccRegex.test("freeCodeCamp"), "Your regex should match freeCodeCamp");' +- text: Your regex should match FreeCodeCamp + testString: 'assert(fccRegex.test("FreeCodeCamp"), "Your regex should match FreeCodeCamp");' +- text: Your regex should match FreecodeCamp + testString: 'assert(fccRegex.test("FreecodeCamp"), "Your regex should match FreecodeCamp");' +- text: Your regex should match FreeCodecamp + testString: 'assert(fccRegex.test("FreeCodecamp"), "Your regex should match FreeCodecamp");' +- text: Your regex should not match Free Code Camp + testString: 'assert(!fccRegex.test("Free Code Camp"), "Your regex should not match Free Code Camp");' +- text: Your regex should match FreeCOdeCamp + testString: 'assert(fccRegex.test("FreeCOdeCamp"), "Your regex should match FreeCOdeCamp");' +- text: Your regex should not match FCC + testString: 'assert(!fccRegex.test("FCC"), "Your regex should not match FCC");' +- text: Your regex should match FrEeCoDeCamp + testString: 'assert(fccRegex.test("FrEeCoDeCamp"), "Your regex should match FrEeCoDeCamp");' +- text: Your regex should match FrEeCodECamp + testString: 'assert(fccRegex.test("FrEeCodECamp"), "Your regex should match FrEeCodECamp");' +- text: Your regex should match FReeCodeCAmp + testString: 'assert(fccRegex.test("FReeCodeCAmp"), "Your regex should match FReeCodeCAmp");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +let myString = "freeCodeCamp"; +let fccRegex = /change/; // Change this line +let result = fccRegex.test(myString); +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Match All Letters and Numbers.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Match All Letters and Numbers.md new file mode 100644 index 0000000000..9e83e7be4a --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Match All Letters and Numbers.md @@ -0,0 +1,64 @@ +--- +id: 587d7db7367417b2b2512b9f +title: Match All Letters and Numbers +challengeType: 1 +--- + +## Description +
    +Using character classes, you were able to search for all letters of the alphabet with [a-z]. This kind of character class is common enough that there is a shortcut for it, although it includes a few extra characters as well. +The closest character class in JavaScript to match the alphabet is \w. This shortcut is equal to [A-Za-z0-9_]. This character class matches upper and lowercase letters plus numbers. Note, this character class also includes the underscore character (_). +
    let longHand = /[A-Za-z0-9_]+/;
    let shortHand = /\w+/;
    let numbers = "42";
    let varNames = "important_var";
    longHand.test(numbers); // Returns true
    shortHand.test(numbers); // Returns true
    longHand.test(varNames); // Returns true
    shortHand.test(varNames); // Returns true
    +These shortcut character classes are also known as shorthand character classes. +
    + +## Instructions +
    +Use the shorthand character class \w to count the number of alphanumeric characters in various quotes and strings. +
    + +## Tests +
    + +```yml +- text: Your regex should use the global flag. + testString: 'assert(alphabetRegexV2.global, "Your regex should use the global flag.");' +- text: Your regex should use the shorthand character + testString: 'assert(/\\w/.test(alphabetRegexV2.source), "Your regex should use the shorthand character \w to match all characters which are alphanumeric.");' +- text: Your regex should find 31 alphanumeric characters in "The five boxing wizards jump quickly." + testString: 'assert("The five boxing wizards jump quickly.".match(alphabetRegexV2).length === 31, "Your regex should find 31 alphanumeric characters in "The five boxing wizards jump quickly."");' +- text: Your regex should find 32 alphanumeric characters in "Pack my box with five dozen liquor jugs." + testString: 'assert("Pack my box with five dozen liquor jugs.".match(alphabetRegexV2).length === 32, "Your regex should find 32 alphanumeric characters in "Pack my box with five dozen liquor jugs."");' +- text: Your regex should find 30 alphanumeric characters in "How vexingly quick daft zebras jump!" + testString: 'assert("How vexingly quick daft zebras jump!".match(alphabetRegexV2).length === 30, "Your regex should find 30 alphanumeric characters in "How vexingly quick daft zebras jump!"");' +- text: Your regex should find 36 alphanumeric characters in "123 456 7890 ABC def GHI jkl MNO pqr STU vwx YZ." + testString: 'assert("123 456 7890 ABC def GHI jkl MNO pqr STU vwx YZ.".match(alphabetRegexV2).length === 36, "Your regex should find 36 alphanumeric characters in "123 456 7890 ABC def GHI jkl MNO pqr STU vwx YZ."");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +let quoteSample = "The five boxing wizards jump quickly."; +let alphabetRegexV2 = /change/; // Change this line +let result = quoteSample.match(alphabetRegexV2).length; +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Match All Non-Numbers.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Match All Non-Numbers.md new file mode 100644 index 0000000000..ecb1baeb62 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Match All Non-Numbers.md @@ -0,0 +1,66 @@ +--- +id: 587d7db8367417b2b2512ba1 +title: Match All Non-Numbers +challengeType: 1 +--- + +## Description +
    +The last challenge showed how to search for digits using the shortcut \d with a lowercase d. You can also search for non-digits using a similar shortcut that uses an uppercase D instead. +The shortcut to look for non-digit characters is \D. This is equal to the character class [^0-9], which looks for a single character that is not a number between zero and nine. +
    + +## Instructions +
    +Use the shorthand character class for non-digits \D to count how many non-digits are in movie titles. +
    + +## Tests +
    + +```yml +- text: Your regex should use the shortcut character to match non-digit characters + testString: 'assert(/\\D/.test(noNumRegex.source), "Your regex should use the shortcut character to match non-digit characters");' +- text: Your regex should use the global flag. + testString: 'assert(noNumRegex.global, "Your regex should use the global flag.");' +- text: Your regex should find no non-digits in "9". + testString: 'assert("9".match(noNumRegex) == null, "Your regex should find no non-digits in "9".");' +- text: Your regex should find 6 non-digits in "Catch 22". + testString: 'assert("Catch 22".match(noNumRegex).length == 6, "Your regex should find 6 non-digits in "Catch 22".");' +- text: Your regex should find 11 non-digits in "101 Dalmatians". + testString: 'assert("101 Dalmatians".match(noNumRegex).length == 11, "Your regex should find 11 non-digits in "101 Dalmatians".");' +- text: 'Your regex should find 15 non-digits in "One, Two, Three".' + testString: 'assert("One, Two, Three".match(noNumRegex).length == 15, "Your regex should find 15 non-digits in "One, Two, Three".");' +- text: Your regex should find 12 non-digits in "21 Jump Street". + testString: 'assert("21 Jump Street".match(noNumRegex).length == 12, "Your regex should find 12 non-digits in "21 Jump Street".");' +- text: 'Your regex should find 17 non-digits in "2001: A Space Odyssey".' + testString: 'assert("2001: A Space Odyssey".match(noNumRegex).length == 17, "Your regex should find 17 non-digits in "2001: A Space Odyssey".");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +let numString = "Your sandwich will be $5.00"; +let noNumRegex = /change/; // Change this line +let result = numString.match(noNumRegex).length; +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Match All Numbers.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Match All Numbers.md new file mode 100644 index 0000000000..e975657a6c --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Match All Numbers.md @@ -0,0 +1,66 @@ +--- +id: 5d712346c441eddfaeb5bdef +title: Match All Numbers +challengeType: 1 +--- + +## Description +
    +You've learned shortcuts for common string patterns like alphanumerics. Another common pattern is looking for just digits or numbers. +The shortcut to look for digit characters is \d, with a lowercase d. This is equal to the character class [0-9], which looks for a single character of any number between zero and nine. +
    + +## Instructions +
    +Use the shorthand character class \d to count how many digits are in movie titles. Written out numbers ("six" instead of 6) do not count. +
    + +## Tests +
    + +```yml +- text: Your regex should use the shortcut character to match digit characters + testString: 'assert(/\\d/.test(numRegex.source), "Your regex should use the shortcut character to match digit characters");' +- text: Your regex should use the global flag. + testString: 'assert(numRegex.global, "Your regex should use the global flag.");' +- text: Your regex should find 1 digit in "9". + testString: 'assert("9".match(numRegex).length == 1, "Your regex should find 1 digit in "9".");' +- text: Your regex should find 2 digits in "Catch 22". + testString: 'assert("Catch 22".match(numRegex).length == 2, "Your regex should find 2 digits in "Catch 22".");' +- text: Your regex should find 3 digits in "101 Dalmatians". + testString: 'assert("101 Dalmatians".match(numRegex).length == 3, "Your regex should find 3 digits in "101 Dalmatians".");' +- text: 'Your regex should find no digits in "One, Two, Three".' + testString: 'assert("One, Two, Three".match(numRegex) == null, "Your regex should find no digits in "One, Two, Three".");' +- text: Your regex should find 2 digits in "21 Jump Street". + testString: 'assert("21 Jump Street".match(numRegex).length == 2, "Your regex should find 2 digits in "21 Jump Street".");' +- text: 'Your regex should find 4 digits in "2001: A Space Odyssey".' + testString: 'assert("2001: A Space Odyssey".match(numRegex).length == 4, "Your regex should find 4 digits in "2001: A Space Odyssey".");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +let numString = "Your sandwich will be $5.00"; +let numRegex = /change/; // Change this line +let result = numString.match(numRegex).length; +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Match Anything with Wildcard Period.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Match Anything with Wildcard Period.md new file mode 100644 index 0000000000..4b109c0660 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Match Anything with Wildcard Period.md @@ -0,0 +1,71 @@ +--- +id: 587d7db5367417b2b2512b94 +title: Match Anything with Wildcard Period +challengeType: 1 +--- + +## Description +
    +Sometimes you won't (or don't need to) know the exact characters in your patterns. Thinking of all words that match, say, a misspelling would take a long time. Luckily, you can save time using the wildcard character: . +The wildcard character . will match any one character. The wildcard is also called dot and period. You can use the wildcard character just like any other character in the regex. For example, if you wanted to match "hug", "huh", "hut", and "hum", you can use the regex /hu./ to match all four words. +
    let humStr = "I'll hum a song";
    let hugStr = "Bear hug";
    let huRegex = /hu./;
    humStr.match(huRegex); // Returns ["hum"]
    hugStr.match(huRegex); // Returns ["hug"]
    +
    + +## Instructions +
    +Complete the regex unRegex so that it matches the strings "run", "sun", "fun", "pun", "nun", and "bun". Your regex should use the wildcard character. +
    + +## Tests +
    + +```yml +- text: You should use the .test() method. + testString: 'assert(code.match(/\.test\(.*\)/), "You should use the .test() method.");' +- text: You should use the wildcard character in your regex unRegex + testString: 'assert(/\./.test(unRegex.source), "You should use the wildcard character in your regex unRegex");' +- text: Your regex unRegex should match "run" in "Let us go on a run." + testString: 'assert(unRegex.test("Let us go on a run."), "Your regex unRegex should match "run" in "Let us go on a run."");' +- text: Your regex unRegex should match "sun" in "The sun is out today." + testString: 'assert(unRegex.test("The sun is out today."), "Your regex unRegex should match "sun" in "The sun is out today."");' +- text: Your regex unRegex should match "fun" in "Coding is a lot of fun." + testString: 'assert(unRegex.test("Coding is a lot of fun."), "Your regex unRegex should match "fun" in "Coding is a lot of fun."");' +- text: Your regex unRegex should match "pun" in "Seven days without a pun makes one weak." + testString: 'assert(unRegex.test("Seven days without a pun makes one weak."), "Your regex unRegex should match "pun" in "Seven days without a pun makes one weak."");' +- text: Your regex unRegex should match "nun" in "One takes a vow to be a nun." + testString: 'assert(unRegex.test("One takes a vow to be a nun."), "Your regex unRegex should match "nun" in "One takes a vow to be a nun."");' +- text: Your regex unRegex should match "bun" in "She got fired from the hot dog stand for putting her hair in a bun." + testString: 'assert(unRegex.test("She got fired from the hot dog stand for putting her hair in a bun."), "Your regex unRegex should match "bun" in "She got fired from the hot dog stand for putting her hair in a bun."");' +- text: Your regex unRegex should not match "There is a bug in my code." + testString: 'assert(!unRegex.test("There is a bug in my code."), "Your regex unRegex should not match "There is a bug in my code."");' +- text: Your regex unRegex should not match "Catch me if you can." + testString: 'assert(!unRegex.test("Can me if you can."), "Your regex unRegex should not match "Catch me if you can."");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +let exampleStr = "Let's have fun with regular expressions!"; +let unRegex = /change/; // Change this line +let result = unRegex.test(exampleStr); +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Match Beginning String Patterns.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Match Beginning String Patterns.md new file mode 100644 index 0000000000..456f87d7d0 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Match Beginning String Patterns.md @@ -0,0 +1,59 @@ +--- +id: 587d7db7367417b2b2512b9d +title: Match Beginning String Patterns +challengeType: 1 +--- + +## Description +
    +Prior challenges showed that regular expressions can be used to look for a number of matches. They are also used to search for patterns in specific positions in strings. +In an earlier challenge, you used the caret character (^) inside a character set to create a negated character set in the form [^thingsThatWillNotBeMatched]. Outside of a character set, the caret is used to search for patterns at the beginning of strings. +
    let firstString = "Ricky is first and can be found.";
    let firstRegex = /^Ricky/;
    firstRegex.test(firstString);
    // Returns true
    let notFirst = "You can't find Ricky now.";
    firstRegex.test(notFirst);
    // Returns false
    +
    + +## Instructions +
    +Use the caret character in a regex to find "Cal" only in the beginning of the string rickyAndCal. +
    + +## Tests +
    + +```yml +- text: Your regex should search for "Cal" with a capital letter. + testString: 'assert(calRegex.source == "^Cal", "Your regex should search for "Cal" with a capital letter.");' +- text: Your regex should not use any flags. + testString: 'assert(calRegex.flags == "", "Your regex should not use any flags.");' +- text: Your regex should match "Cal" at the beginning of the string. + testString: 'assert(calRegex.test("Cal and Ricky both like racing."), "Your regex should match "Cal" at the beginning of the string.");' +- text: Your regex should not match "Cal" in the middle of a string. + testString: 'assert(!calRegex.test("Ricky and Cal both like racing."), "Your regex should not match "Cal" in the middle of a string.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +let rickyAndCal = "Cal and Ricky both like racing."; +let calRegex = /change/; // Change this line +let result = calRegex.test(rickyAndCal); +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Match Characters that Occur One or More Times.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Match Characters that Occur One or More Times.md new file mode 100644 index 0000000000..b8657fea62 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Match Characters that Occur One or More Times.md @@ -0,0 +1,58 @@ +--- +id: 587d7db6367417b2b2512b99 +title: Match Characters that Occur One or More Times +challengeType: 1 +--- + +## Description +
    +Sometimes, you need to match a character (or group of characters) that appears one or more times in a row. This means it occurs at least once, and may be repeated. +You can use the + character to check if that is the case. Remember, the character or pattern has to be present consecutively. That is, the character has to repeat one after the other. +For example, /a+/g would find one match in "abc" and return ["a"]. Because of the +, it would also find a single match in "aabc" and return ["aa"]. +If it were instead checking the string "abab", it would find two matches and return ["a", "a"] because the a characters are not in a row - there is a b between them. Finally, since there is no "a" in the string "bcd", it wouldn't find a match. +
    + +## Instructions +
    +You want to find matches when the letter s occurs one or more times in "Mississippi". Write a regex that uses the + sign. +
    + +## Tests +
    + +```yml +- text: Your regex myRegex should use the + sign to match one or more s characters. + testString: 'assert(/\+/.test(myRegex.source), "Your regex myRegex should use the + sign to match one or more s characters.");' +- text: Your regex myRegex should match 2 items. + testString: 'assert(result.length == 2, "Your regex myRegex should match 2 items.");' +- text: The result variable should be an array with two matches of "ss" + testString: 'assert(result[0] == "ss" && result[1] == "ss", "The result variable should be an array with two matches of "ss"");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +let difficultSpelling = "Mississippi"; +let myRegex = /change/; // Change this line +let result = difficultSpelling.match(myRegex); +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Match Characters that Occur Zero or More Times.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Match Characters that Occur Zero or More Times.md new file mode 100644 index 0000000000..230fc6cbc6 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Match Characters that Occur Zero or More Times.md @@ -0,0 +1,61 @@ +--- +id: 587d7db6367417b2b2512b9a +title: Match Characters that Occur Zero or More Times +challengeType: 1 +--- + +## Description +
    +The last challenge used the plus + sign to look for characters that occur one or more times. There's also an option that matches characters that occur zero or more times. +The character to do this is the asterisk or star: *. +
    let soccerWord = "gooooooooal!";
    let gPhrase = "gut feeling";
    let oPhrase = "over the moon";
    let goRegex = /go*/;
    soccerWord.match(goRegex); // Returns ["goooooooo"]
    gPhrase.match(goRegex); // Returns ["g"]
    oPhrase.match(goRegex); // Returns null
    +
    + +## Instructions +
    +Create a regex chewieRegex that uses the * character to match all the upper and lower"a" characters in chewieQuote. Your regex does not need flags, and it should not match any of the other quotes. +
    + +## Tests +
    + +```yml +- text: Your regex chewieRegex should use the * character to match zero or more a characters. + testString: 'assert(/\*/.test(chewieRegex.source), "Your regex chewieRegex should use the * character to match zero or more a characters.");' +- text: Your regex chewieRegex should match 16 characters. + testString: 'assert(result[0].length === 16, "Your regex chewieRegex should match 16 characters.");' +- text: Your regex should match "Aaaaaaaaaaaaaaaa". + testString: 'assert(result[0] === "Aaaaaaaaaaaaaaaa", "Your regex should match "Aaaaaaaaaaaaaaaa".");' +- text: 'Your regex should not match any characters in "He made a fair move. Screaming about it can't help you."' + testString: 'assert(!"He made a fair move. Screaming about it can\"t help you.".match(chewieRegex), "Your regex should not match any characters in "He made a fair move. Screaming about it can't help you."");' +- text: 'Your regex should not match any characters in "Let him have it. It's not wise to upset a Wookiee."' + testString: 'assert(!"Let him have it. It\"s not wise to upset a Wookiee.".match(chewieRegex), "Your regex should not match any characters in "Let him have it. It's not wise to upset a Wookiee."");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +let chewieQuote = "Aaaaaaaaaaaaaaaarrrgh!"; +let chewieRegex = /change/; // Change this line +let result = chewieQuote.match(chewieRegex); +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Match Ending String Patterns.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Match Ending String Patterns.md new file mode 100644 index 0000000000..d3d4c44d3f --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Match Ending String Patterns.md @@ -0,0 +1,57 @@ +--- +id: 587d7db7367417b2b2512b9e +title: Match Ending String Patterns +challengeType: 1 +--- + +## Description +
    +In the last challenge, you learned to use the caret character to search for patterns at the beginning of strings. There is also a way to search for patterns at the end of strings. +You can search the end of strings using the dollar sign character $ at the end of the regex. +
    let theEnding = "This is a never ending story";
    let storyRegex = /story$/;
    storyRegex.test(theEnding);
    // Returns true
    let noEnding = "Sometimes a story will have to end";
    storyRegex.test(noEnding);
    // Returns false
    +
    + +## Instructions +
    +Use the anchor character ($) to match the string "caboose" at the end of the string caboose. +
    + +## Tests +
    + +```yml +- text: You should search for "caboose" with the dollar sign $ anchor in your regex. + testString: 'assert(lastRegex.source == "caboose$", "You should search for "caboose" with the dollar sign $ anchor in your regex.");' +- text: Your regex should not use any flags. + testString: 'assert(lastRegex.flags == "", "Your regex should not use any flags.");' +- text: You should match "caboose" at the end of the string "The last car on a train is the caboose" + testString: 'assert(lastRegex.test("The last car on a train is the caboose"), "You should match "caboose" at the end of the string "The last car on a train is the caboose"");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +let caboose = "The last car on a train is the caboose"; +let lastRegex = /change/; // Change this line +let result = lastRegex.test(caboose); +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Match Everything But Letters and Numbers.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Match Everything But Letters and Numbers.md new file mode 100644 index 0000000000..933911cf9c --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Match Everything But Letters and Numbers.md @@ -0,0 +1,63 @@ +--- +id: 587d7db8367417b2b2512ba0 +title: Match Everything But Letters and Numbers +challengeType: 1 +--- + +## Description +
    +You've learned that you can use a shortcut to match alphanumerics [A-Za-z0-9_] using \w. A natural pattern you might want to search for is the opposite of alphanumerics. +You can search for the opposite of the \w with \W. Note, the opposite pattern uses a capital letter. This shortcut is the same as [^A-Za-z0-9_]. +
    let shortHand = /\W/;
    let numbers = "42%";
    let sentence = "Coding!";
    numbers.match(shortHand); // Returns ["%"]
    sentence.match(shortHand); // Returns ["!"]
    +
    + +## Instructions +
    +Use the shorthand character class \W to count the number of non-alphanumeric characters in various quotes and strings. +
    + +## Tests +
    + +```yml +- text: Your regex should use the global flag. + testString: 'assert(nonAlphabetRegex.global, "Your regex should use the global flag.");' +- text: Your regex should find 6 non-alphanumeric characters in "The five boxing wizards jump quickly.". + testString: 'assert("The five boxing wizards jump quickly.".match(nonAlphabetRegex).length == 6, "Your regex should find 6 non-alphanumeric characters in "The five boxing wizards jump quickly.".");' +- text: Your regex should use the shorthand character. + testString: 'assert(/\\W/.test(nonAlphabetRegex.source), "Your regex should use the shorthand character to match characters which are non-alphanumeric.");' +- text: Your regex should find 8 non-alphanumeric characters in "Pack my box with five dozen liquor jugs." + testString: 'assert("Pack my box with five dozen liquor jugs.".match(nonAlphabetRegex).length == 8, "Your regex should find 8 non-alphanumeric characters in "Pack my box with five dozen liquor jugs."");' +- text: Your regex should find 6 non-alphanumeric characters in "How vexingly quick daft zebras jump!" + testString: 'assert("How vexingly quick daft zebras jump!".match(nonAlphabetRegex).length == 6, "Your regex should find 6 non-alphanumeric characters in "How vexingly quick daft zebras jump!"");' +- text: Your regex should find 12 non-alphanumeric characters in "123 456 7890 ABC def GHI jkl MNO pqr STU vwx YZ." + testString: 'assert("123 456 7890 ABC def GHI jkl MNO pqr STU vwx YZ.".match(nonAlphabetRegex).length == 12, "Your regex should find 12 non-alphanumeric characters in "123 456 7890 ABC def GHI jkl MNO pqr STU vwx YZ."");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +let quoteSample = "The five boxing wizards jump quickly."; +let nonAlphabetRegex = /change/; // Change this line +let result = quoteSample.match(nonAlphabetRegex).length; +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Match Letters of the Alphabet.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Match Letters of the Alphabet.md new file mode 100644 index 0000000000..9a61486bbb --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Match Letters of the Alphabet.md @@ -0,0 +1,59 @@ +--- +id: 587d7db5367417b2b2512b96 +title: Match Letters of the Alphabet +challengeType: 1 +--- + +## Description +
    +You saw how you can use character sets to specify a group of characters to match, but that's a lot of typing when you need to match a large range of characters (for example, every letter in the alphabet). Fortunately, there is a built-in feature that makes this short and simple. +Inside a character set, you can define a range of characters to match using a hyphen character: -. +For example, to match lowercase letters a through e you would use [a-e]. +
    let catStr = "cat";
    let batStr = "bat";
    let matStr = "mat";
    let bgRegex = /[a-e]at/;
    catStr.match(bgRegex); // Returns ["cat"]
    batStr.match(bgRegex); // Returns ["bat"]
    matStr.match(bgRegex); // Returns null
    +
    + +## Instructions +
    +Match all the letters in the string quoteSample. +Note
    Be sure to match both upper- and lowercase letters. +
    + +## Tests +
    + +```yml +- text: Your regex alphabetRegex should match 35 items. + testString: 'assert(result.length == 35, "Your regex alphabetRegex should match 35 items.");' +- text: Your regex alphabetRegex should use the global flag. + testString: 'assert(alphabetRegex.flags.match(/g/).length == 1, "Your regex alphabetRegex should use the global flag.");' +- text: Your regex alphabetRegex should use the case insensitive flag. + testString: 'assert(alphabetRegex.flags.match(/i/).length == 1, "Your regex alphabetRegex should use the case insensitive flag.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +let quoteSample = "The quick brown fox jumps over the lazy dog."; +let alphabetRegex = /change/; // Change this line +let result = alphabetRegex; // Change this line +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Match Literal Strings.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Match Literal Strings.md new file mode 100644 index 0000000000..c412bfb087 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Match Literal Strings.md @@ -0,0 +1,59 @@ +--- +id: 587d7db3367417b2b2512b8f +title: Match Literal Strings +challengeType: 1 +--- + +## Description +
    +In the last challenge, you searched for the word "Hello" using the regular expression /Hello/. That regex searched for a literal match of the string "Hello". Here's another example searching for a literal match of the string "Kevin": +
    let testStr = "Hello, my name is Kevin.";
    let testRegex = /Kevin/;
    testRegex.test(testStr);
    // Returns true
    +Any other forms of "Kevin" will not match. For example, the regex /Kevin/ will not match "kevin" or "KEVIN". +
    let wrongRegex = /kevin/;
    wrongRegex.test(testStr);
    // Returns false
    +A future challenge will show how to match those other forms as well. +
    + +## Instructions +
    +Complete the regex waldoRegex to find "Waldo" in the string waldoIsHiding with a literal match. +
    + +## Tests +
    + +```yml +- text: Your regex waldoRegex should find "Waldo" + testString: 'assert(waldoRegex.test(waldoIsHiding), "Your regex waldoRegex should find "Waldo"");' +- text: Your regex waldoRegex should not search for anything else. + testString: 'assert(!waldoRegex.test("Somewhere is hiding in this text."), "Your regex waldoRegex should not search for anything else.");' +- text: You should perform a literal string match with your regex. + testString: 'assert(!/\/.*\/i/.test(code), "You should perform a literal string match with your regex.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +let waldoIsHiding = "Somewhere Waldo is hiding in this text."; +let waldoRegex = /search/; // Change this line +let result = waldoRegex.test(waldoIsHiding); +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Match Non-Whitespace Characters.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Match Non-Whitespace Characters.md new file mode 100644 index 0000000000..9aa09b4d69 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Match Non-Whitespace Characters.md @@ -0,0 +1,61 @@ +--- +id: 587d7db9367417b2b2512ba4 +title: Match Non-Whitespace Characters +challengeType: 1 +--- + +## Description +
    +You learned about searching for whitespace using \s, with a lowercase s. You can also search for everything except whitespace. +Search for non-whitespace using \S, which is an uppercase s. This pattern will not match whitespace, carriage return, tab, form feed, and new line characters. You can think of it being similar to the character class [^ \r\t\f\n\v]. +
    let whiteSpace = "Whitespace. Whitespace everywhere!"
    let nonSpaceRegex = /\S/g;
    whiteSpace.match(nonSpaceRegex).length; // Returns 32
    +
    + +## Instructions +
    +Change the regex countNonWhiteSpace to look for multiple non-whitespace characters in a string. +
    + +## Tests +
    + +```yml +- text: Your regex should use the global flag. + testString: 'assert(countNonWhiteSpace.global, "Your regex should use the global flag.");' +- text: Your regex should use the shorthand character + testString: 'assert(/\\S/.test(countNonWhiteSpace.source), "Your regex should use the shorthand character \S/code> to match all non-whitespace characters.");' +- text: Your regex should find 35 non-spaces in "Men are from Mars and women are from Venus." + testString: 'assert("Men are from Mars and women are from Venus.".match(countNonWhiteSpace).length == 35, "Your regex should find 35 non-spaces in "Men are from Mars and women are from Venus."");' +- text: 'Your regex should find 23 non-spaces in "Space: the final frontier."' + testString: 'assert("Space: the final frontier.".match(countNonWhiteSpace).length == 23, "Your regex should find 23 non-spaces in "Space: the final frontier."");' +- text: Your regex should find 21 non-spaces in "MindYourPersonalSpace" + testString: 'assert("MindYourPersonalSpace".match(countNonWhiteSpace).length == 21, "Your regex should find 21 non-spaces in "MindYourPersonalSpace"");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +let sample = "Whitespace is important in separating words"; +let countNonWhiteSpace = /change/; // Change this line +let result = sample.match(countNonWhiteSpace); +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Match Numbers and Letters of the Alphabet.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Match Numbers and Letters of the Alphabet.md new file mode 100644 index 0000000000..f8ecc0d3e8 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Match Numbers and Letters of the Alphabet.md @@ -0,0 +1,58 @@ +--- +id: 587d7db5367417b2b2512b97 +title: Match Numbers and Letters of the Alphabet +challengeType: 1 +--- + +## Description +
    +Using the hyphen (-) to match a range of characters is not limited to letters. It also works to match a range of numbers. +For example, /[0-5]/ matches any number between 0 and 5, including the 0 and 5. +Also, it is possible to combine a range of letters and numbers in a single character set. +
    let jennyStr = "Jenny8675309";
    let myRegex = /[a-z0-9]/ig;
    // matches all letters and numbers in jennyStr
    jennyStr.match(myRegex);
    +
    + +## Instructions +
    +Create a single regex that matches a range of letters between h and s, and a range of numbers between 2 and 6. Remember to include the appropriate flags in the regex. +
    + +## Tests +
    + +```yml +- text: Your regex myRegex should match 17 items. + testString: 'assert(result.length == 17, "Your regex myRegex should match 17 items.");' +- text: Your regex myRegex should use the global flag. + testString: 'assert(myRegex.flags.match(/g/).length == 1, "Your regex myRegex should use the global flag.");' +- text: Your regex myRegex should use the case insensitive flag. + testString: 'assert(myRegex.flags.match(/i/).length == 1, "Your regex myRegex should use the case insensitive flag.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +let quoteSample = "Blueberry 3.141592653s are delicious."; +let myRegex = /change/; // Change this line +let result = myRegex; // Change this line +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Match Single Character with Multiple Possibilities.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Match Single Character with Multiple Possibilities.md new file mode 100644 index 0000000000..186984847f --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Match Single Character with Multiple Possibilities.md @@ -0,0 +1,63 @@ +--- +id: 587d7db5367417b2b2512b95 +title: Match Single Character with Multiple Possibilities +challengeType: 1 +--- + +## Description +
    +You learned how to match literal patterns (/literal/) and wildcard character (/./). Those are the extremes of regular expressions, where one finds exact matches and the other matches everything. There are options that are a balance between the two extremes. +You can search for a literal pattern with some flexibility with character classes. Character classes allow you to define a group of characters you wish to match by placing them inside square ([ and ]) brackets. +For example, you want to match "bag", "big", and "bug" but not "bog". You can create the regex /b[aiu]g/ to do this. The [aiu] is the character class that will only match the characters "a", "i", or "u". +
    let bigStr = "big";
    let bagStr = "bag";
    let bugStr = "bug";
    let bogStr = "bog";
    let bgRegex = /b[aiu]g/;
    bigStr.match(bgRegex); // Returns ["big"]
    bagStr.match(bgRegex); // Returns ["bag"]
    bugStr.match(bgRegex); // Returns ["bug"]
    bogStr.match(bgRegex); // Returns null
    +
    + +## Instructions +
    +Use a character class with vowels (a, e, i, o, u) in your regex vowelRegex to find all the vowels in the string quoteSample. +Note
    Be sure to match both upper- and lowercase vowels. +
    + +## Tests +
    + +```yml +- text: You should find all 25 vowels. + testString: 'assert(result.length == 25, "You should find all 25 vowels.");' +- text: Your regex vowelRegex should use a character class. + testString: 'assert(/\[.*\]/.test(vowelRegex.source), "Your regex vowelRegex should use a character class.");' +- text: Your regex vowelRegex should use the global flag. + testString: 'assert(vowelRegex.flags.match(/g/).length == 1, "Your regex vowelRegex should use the global flag.");' +- text: Your regex vowelRegex should use the case insensitive flag. + testString: 'assert(vowelRegex.flags.match(/i/).length == 1, "Your regex vowelRegex should use the case insensitive flag.");' +- text: Your regex should not match any consonants. + testString: 'assert(!/[b-df-hj-np-tv-z]/gi.test(result.join()), "Your regex should not match any consonants.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +let quoteSample = "Beware of bugs in the above code; I have only proved it correct, not tried it."; +let vowelRegex = /change/; // Change this line +let result = vowelRegex; // Change this line +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Match Single Characters Not Specified.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Match Single Characters Not Specified.md new file mode 100644 index 0000000000..b7c2e1b3ef --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Match Single Characters Not Specified.md @@ -0,0 +1,57 @@ +--- +id: 587d7db6367417b2b2512b98 +title: Match Single Characters Not Specified +challengeType: 1 +--- + +## Description +
    +So far, you have created a set of characters that you want to match, but you could also create a set of characters that you do not want to match. These types of character sets are called negated character sets. +To create a negated character set, you place a caret character (^) after the opening bracket and before the characters you do not want to match. +For example, /[^aeiou]/gi matches all characters that are not a vowel. Note that characters like ., !, [, @, / and white space are matched - the negated vowel character set only excludes the vowel characters. +
    + +## Instructions +
    +Create a single regex that matches all characters that are not a number or a vowel. Remember to include the appropriate flags in the regex. +
    + +## Tests +
    + +```yml +- text: Your regex myRegex should match 9 items. + testString: 'assert(result.length == 9, "Your regex myRegex should match 9 items.");' +- text: Your regex myRegex should use the global flag. + testString: 'assert(myRegex.flags.match(/g/).length == 1, "Your regex myRegex should use the global flag.");' +- text: Your regex myRegex should use the case insensitive flag. + testString: 'assert(myRegex.flags.match(/i/).length == 1, "Your regex myRegex should use the case insensitive flag.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +let quoteSample = "3 blind mice."; +let myRegex = /change/; // Change this line +let result = myRegex; // Change this line +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Match Whitespace.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Match Whitespace.md new file mode 100644 index 0000000000..b439690a5f --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Match Whitespace.md @@ -0,0 +1,61 @@ +--- +id: 587d7db8367417b2b2512ba3 +title: Match Whitespace +challengeType: 1 +--- + +## Description +
    +The challenges so far have covered matching letters of the alphabet and numbers. You can also match the whitespace or spaces between letters. +You can search for whitespace using \s, which is a lowercase s. This pattern not only matches whitespace, but also carriage return, tab, form feed, and new line characters. You can think of it as similar to the character class [ \r\t\f\n\v]. +
    let whiteSpace = "Whitespace. Whitespace everywhere!"
    let spaceRegex = /\s/g;
    whiteSpace.match(spaceRegex);
    // Returns [" ", " "]
    +
    + +## Instructions +
    +Change the regex countWhiteSpace to look for multiple whitespace characters in a string. +
    + +## Tests +
    + +```yml +- text: Your regex should use the global flag. + testString: 'assert(countWhiteSpace.global, "Your regex should use the global flag.");' +- text: Your regex should use the shorthand character + testString: 'assert(/\\s/.test(countWhiteSpace.source), "Your regex should use the shorthand character \s to match all whitespace characters.");' +- text: Your regex should find eight spaces in "Men are from Mars and women are from Venus." + testString: 'assert("Men are from Mars and women are from Venus.".match(countWhiteSpace).length == 8, "Your regex should find eight spaces in "Men are from Mars and women are from Venus."");' +- text: 'Your regex should find three spaces in "Space: the final frontier."' + testString: 'assert("Space: the final frontier.".match(countWhiteSpace).length == 3, "Your regex should find three spaces in "Space: the final frontier."");' +- text: Your regex should find no spaces in "MindYourPersonalSpace" + testString: 'assert("MindYourPersonalSpace".match(countWhiteSpace) == null, "Your regex should find no spaces in "MindYourPersonalSpace"");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +let sample = "Whitespace is important in separating words"; +let countWhiteSpace = /change/; // Change this line +let result = sample.match(countWhiteSpace); +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Match a Literal String with Different Possibilities.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Match a Literal String with Different Possibilities.md new file mode 100644 index 0000000000..bc3ca9f6d3 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Match a Literal String with Different Possibilities.md @@ -0,0 +1,66 @@ +--- +id: 587d7db4367417b2b2512b90 +title: Match a Literal String with Different Possibilities +challengeType: 1 +--- + +## Description +
    +Using regexes like /coding/, you can look for the pattern "coding" in another string. +This is powerful to search single strings, but it's limited to only one pattern. You can search for multiple patterns using the alternation or OR operator: |. +This operator matches patterns either before or after it. For example, if you wanted to match "yes" or "no", the regex you want is /yes|no/. +You can also search for more than just two patterns. You can do this by adding more patterns with more OR operators separating them, like /yes|no|maybe/. +
    + +## Instructions +
    +Complete the regex petRegex to match the pets "dog", "cat", "bird", or "fish". +
    + +## Tests +
    + +```yml +- text: Your regex petRegex should return true for the string "John has a pet dog." + testString: 'assert(petRegex.test("John has a pet dog."), "Your regex petRegex should return true for the string "John has a pet dog."");' +- text: Your regex petRegex should return false for the string "Emma has a pet rock." + testString: 'assert(!petRegex.test("Emma has a pet rock."), "Your regex petRegex should return false for the string "Emma has a pet rock."");' +- text: Your regex petRegex should return true for the string "Emma has a pet bird." + testString: 'assert(petRegex.test("Emma has a pet bird."), "Your regex petRegex should return true for the string "Emma has a pet bird."");' +- text: Your regex petRegex should return true for the string "Liz has a pet cat." + testString: 'assert(petRegex.test("Liz has a pet cat."), "Your regex petRegex should return true for the string "Liz has a pet cat."");' +- text: Your regex petRegex should return false for the string "Kara has a pet dolphin." + testString: 'assert(!petRegex.test("Kara has a pet dolphin."), "Your regex petRegex should return false for the string "Kara has a pet dolphin."");' +- text: Your regex petRegex should return true for the string "Alice has a pet fish." + testString: 'assert(petRegex.test("Alice has a pet fish."), "Your regex petRegex should return true for the string "Alice has a pet fish."");' +- text: Your regex petRegex should return false for the string "Jimmy has a pet computer." + testString: 'assert(!petRegex.test("Jimmy has a pet computer."), "Your regex petRegex should return false for the string "Jimmy has a pet computer."");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +let petString = "James has a pet cat."; +let petRegex = /change/; // Change this line +let result = petRegex.test(petString); +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Positive and Negative Lookahead.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Positive and Negative Lookahead.md new file mode 100644 index 0000000000..9854242866 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Positive and Negative Lookahead.md @@ -0,0 +1,74 @@ +--- +id: 587d7dba367417b2b2512ba9 +title: Positive and Negative Lookahead +challengeType: 1 +--- + +## Description +
    +Lookaheads are patterns that tell JavaScript to look-ahead in your string to check for patterns further along. This can be useful when you want to search for multiple patterns over the same string. +There are two kinds of lookaheads: positive lookahead and negative lookahead. +A positive lookahead will look to make sure the element in the search pattern is there, but won't actually match it. A positive lookahead is used as (?=...) where the ... is the required part that is not matched. +On the other hand, a negative lookahead will look to make sure the element in the search pattern is not there. A negative lookahead is used as (?!...) where the ... is the pattern that you do not want to be there. The rest of the pattern is returned if the negative lookahead part is not present. +Lookaheads are a bit confusing but some examples will help. +
    let quit = "qu";
    let noquit = "qt";
    let quRegex= /q(?=u)/;
    let qRegex = /q(?!u)/;
    quit.match(quRegex); // Returns ["q"]
    noquit.match(qRegex); // Returns ["q"]
    +A more practical use of lookaheads is to check two or more patterns in one string. Here is a (naively) simple password checker that looks for between 3 and 6 characters and at least one number: +
    let password = "abc123";
    let checkPass = /(?=\w{3,6})(?=\D*\d)/;
    checkPass.test(password); // Returns true
    +
    + +## Instructions +
    +Use lookaheads in the pwRegex to match passwords that are greater than 5 characters long and have two consecutive digits. +
    + +## Tests +
    + +```yml +- text: Your regex should use two positive lookaheads. + testString: 'assert(pwRegex.source.match(/\(\?=.*?\)\(\?=.*?\)/) !== null, "Your regex should use two positive lookaheads.");' +- text: Your regex should not match "astronaut" + testString: 'assert(!pwRegex.test("astronaut"), "Your regex should not match "astronaut"");' +- text: Your regex should not match "airplanes" + testString: 'assert(!pwRegex.test("airplanes"), "Your regex should not match "airplanes"");' +- text: Your regex should not match "banan1" + testString: 'assert(!pwRegex.test("banan1"), "Your regex should not match "banan1"");' +- text: Your regex should match "bana12" + testString: 'assert(pwRegex.test("bana12"), "Your regex should match "bana12"");' +- text: Your regex should match "abc123" + testString: 'assert(pwRegex.test("abc123"), "Your regex should match "abc123"");' +- text: Your regex should not match "123" + testString: 'assert(!pwRegex.test("123"), "Your regex should not match "123"");' +- text: Your regex should not match "1234" + testString: 'assert(!pwRegex.test("1234"), "Your regex should not match "1234"");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +let sampleWord = "astronaut"; +let pwRegex = /change/; // Change this line +let result = pwRegex.test(sampleWord); +``` + +
    + + + +
    + +## Solution +
    + + +```js +var pwRegex = /(?=\w{5})(?=\D*\d{2})/; +``` + +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Remove Whitespace from Start and End.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Remove Whitespace from Start and End.md new file mode 100644 index 0000000000..8e01e35bca --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Remove Whitespace from Start and End.md @@ -0,0 +1,56 @@ +--- +id: 587d7dbb367417b2b2512bac +title: Remove Whitespace from Start and End +challengeType: 1 +--- + +## Description +
    +Sometimes whitespace characters around strings are not wanted but are there. Typical processing of strings is to remove the whitespace at the start and end of it. +
    + +## Instructions +
    +Write a regex and use the appropriate string methods to remove whitespace at the beginning and end of strings. +Note
    The .trim() method would work here, but you'll need to complete this challenge using regular expressions. +
    + +## Tests +
    + +```yml +- text: 'result should equal to "Hello, World!"' + testString: 'assert(result == "Hello, World!", "result should equal to "Hello, World!"");' +- text: You should not use the .trim() method. + testString: 'assert(!code.match(/\.trim\(.*?\)/), "You should not use the .trim() method.");' +- text: The result variable should not be set equal to a string. + testString: 'assert(!code.match(/result\s*=\s*".*?"/), "The result variable should not be set equal to a string.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +let hello = " Hello, World! "; +let wsRegex = /change/; // Change this line +let result = hello; // Change this line +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Restrict Possible Usernames.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Restrict Possible Usernames.md new file mode 100644 index 0000000000..ea951e3d64 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Restrict Possible Usernames.md @@ -0,0 +1,65 @@ +--- +id: 587d7db8367417b2b2512ba2 +title: Restrict Possible Usernames +challengeType: 1 +--- + +## Description +
    +Usernames are used everywhere on the internet. They are what give users a unique identity on their favorite sites. +You need to check all the usernames in a database. Here are some simple rules that users have to follow when creating their username. +1) The only numbers in the username have to be at the end. There can be zero or more of them at the end. +2) Username letters can be lowercase and uppercase. +3) Usernames have to be at least two characters long. A two-letter username can only use alphabet letter characters. +
    + +## Instructions +
    +Change the regex userCheck to fit the constraints listed above. +
    + +## Tests +
    + +```yml +- text: Your regex should match JACK + testString: 'assert(userCheck.test("JACK"), "Your regex should match JACK");' +- text: Your regex should not match J + testString: 'assert(!userCheck.test("J"), "Your regex should not match J");' +- text: Your regex should match Oceans11 + testString: 'assert(userCheck.test("Oceans11"), "Your regex should match Oceans11");' +- text: Your regex should match RegexGuru + testString: 'assert(userCheck.test("RegexGuru"), "Your regex should match RegexGuru");' +- text: Your regex should not match 007 + testString: 'assert(!userCheck.test("007"), "Your regex should not match 007");' +- text: Your regex should not match 9 + testString: 'assert(!userCheck.test("9"), "Your regex should not match 9");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +let username = "JackOfAllTrades"; +let userCheck = /change/; // Change this line +let result = userCheck.test(username); +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Reuse Patterns Using Capture Groups.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Reuse Patterns Using Capture Groups.md new file mode 100644 index 0000000000..fe14b17125 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Reuse Patterns Using Capture Groups.md @@ -0,0 +1,74 @@ +--- +id: 587d7dbb367417b2b2512baa +title: Reuse Patterns Using Capture Groups +challengeType: 1 +--- + +## Description +
    +Some patterns you search for will occur multiple times in a string. It is wasteful to manually repeat that regex. There is a better way to specify when you have multiple repeat substrings in your string. +You can search for repeat substrings using capture groups. Parentheses, ( and ), are used to find repeat substrings. You put the regex of the pattern that will repeat in between the parentheses. +To specify where that repeat string will appear, you use a backslash (\) and then a number. This number starts at 1 and increases with each additional capture group you use. An example would be \1 to match the first group. +The example below matches any word that occurs twice separated by a space: +
    let repeatStr = "regex regex";
    let repeatRegex = /(\w+)\s\1/;
    repeatRegex.test(repeatStr); // Returns true
    repeatStr.match(repeatRegex); // Returns ["regex regex", "regex"]
    +Using the .match() method on a string will return an array with the string it matches, along with its capture group. +
    + +## Instructions +
    +Use capture groups in reRegex to match numbers that are repeated only three times in a string, each separated by a space. +
    + +## Tests +
    + +```yml +- text: Your regex should use the shorthand character class for digits. + testString: 'assert(reRegex.source.match(/\\d/), "Your regex should use the shorthand character class for digits.");' +- text: Your regex should reuse the capture group twice. + testString: 'assert(reRegex.source.match(/\\\d/g).length === 2, "Your regex should reuse the capture group twice.");' +- text: Your regex should have two spaces separating the three numbers. + testString: 'assert(reRegex.source.match(/\\s/g).length === 2, "Your regex should have two spaces separating the three numbers.");' +- text: Your regex should match "42 42 42". + testString: 'assert(reRegex.test("42 42 42"), "Your regex should match "42 42 42".");' +- text: Your regex should match "100 100 100". + testString: 'assert(reRegex.test("100 100 100"), "Your regex should match "100 100 100".");' +- text: Your regex should not match "42 42 42 42". + testString: 'assert.equal(("42 42 42 42").match(reRegex.source), null, "Your regex should not match "42 42 42 42".");' +- text: Your regex should not match "42 42". + testString: 'assert.equal(("42 42").match(reRegex.source), null, "Your regex should not match "42 42".");' +- text: Your regex should not match "101 102 103". + testString: 'assert(!reRegex.test("101 102 103"), "Your regex should not match "101 102 103".");' +- text: Your regex should not match "1 2 3". + testString: 'assert(!reRegex.test("1 2 3"), "Your regex should not match "1 2 3".");' +- text: Your regex should match "10 10 10". + testString: 'assert(reRegex.test("10 10 10"), "Your regex should match "10 10 10".");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +let repeatNum = "42 42 42"; +let reRegex = /change/; // Change this line +let result = reRegex.test(repeatNum); +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Specify Exact Number of Matches.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Specify Exact Number of Matches.md new file mode 100644 index 0000000000..a7c4b97e69 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Specify Exact Number of Matches.md @@ -0,0 +1,64 @@ +--- +id: 587d7db9367417b2b2512ba7 +title: Specify Exact Number of Matches +challengeType: 1 +--- + +## Description +
    +You can specify the lower and upper number of patterns with quantity specifiers using curly brackets. Sometimes you only want a specific number of matches. +To specify a certain number of patterns, just have that one number between the curly brackets. +For example, to match only the word "hah" with the letter a 3 times, your regex would be /ha{3}h/. +
    let A4 = "haaaah";
    let A3 = "haaah";
    let A100 = "h" + "a".repeat(100) + "h";
    let multipleHA = /ha{3}h/;
    multipleHA.test(A4); // Returns false
    multipleHA.test(A3); // Returns true
    multipleHA.test(A100); // Returns false
    +
    + +## Instructions +
    +Change the regex timRegex to match the word "Timber" only when it has four letter m's. +
    + +## Tests +
    + +```yml +- text: Your regex should use curly brackets. + testString: 'assert(timRegex.source.match(/{.*?}/).length > 0, "Your regex should use curly brackets.");' +- text: Your regex should not match "Timber" + testString: 'assert(!timRegex.test("Timber"), "Your regex should not match "Timber"");' +- text: Your regex should not match "Timmber" + testString: 'assert(!timRegex.test("Timmber"), "Your regex should not match "Timmber"");' +- text: Your regex should not match "Timmmber" + testString: 'assert(!timRegex.test("Timmmber"), "Your regex should not match "Timmmber"");' +- text: Your regex should match "Timmmmber" + testString: 'assert(timRegex.test("Timmmmber"), "Your regex should match "Timmmmber"");' +- text: Your regex should not match "Timber" with 30 m's in it. + testString: 'assert(!timRegex.test("Ti" + "m".repeat(30) + "ber"), "Your regex should not match "Timber" with 30 m\"s in it.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +let timStr = "Timmmmber"; +let timRegex = /change/; // Change this line +let result = timRegex.test(timStr); +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Specify Only the Lower Number of Matches.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Specify Only the Lower Number of Matches.md new file mode 100644 index 0000000000..eddcd4d70b --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Specify Only the Lower Number of Matches.md @@ -0,0 +1,66 @@ +--- +id: 587d7db9367417b2b2512ba6 +title: Specify Only the Lower Number of Matches +challengeType: 1 +--- + +## Description +
    +You can specify the lower and upper number of patterns with quantity specifiers using curly brackets. Sometimes you only want to specify the lower number of patterns with no upper limit. +To only specify the lower number of patterns, keep the first number followed by a comma. +For example, to match only the string "hah" with the letter a appearing at least 3 times, your regex would be /ha{3,}h/. +
    let A4 = "haaaah";
    let A2 = "haah";
    let A100 = "h" + "a".repeat(100) + "h";
    let multipleA = /ha{3,}h/;
    multipleA.test(A4); // Returns true
    multipleA.test(A2); // Returns false
    multipleA.test(A100); // Returns true
    +
    + +## Instructions +
    +Change the regex haRegex to match the word "Hazzah" only when it has four or more letter z's. +
    + +## Tests +
    + +```yml +- text: Your regex should use curly brackets. + testString: 'assert(haRegex.source.match(/{.*?}/).length > 0, "Your regex should use curly brackets.");' +- text: Your regex should not match "Hazzah" + testString: 'assert(!haRegex.test("Hazzah"), "Your regex should not match "Hazzah"");' +- text: Your regex should not match "Hazzzah" + testString: 'assert(!haRegex.test("Hazzzah"), "Your regex should not match "Hazzzah"");' +- text: Your regex should match "Hazzzzah" + testString: 'assert(haRegex.test("Hazzzzah"), "Your regex should match "Hazzzzah"");' +- text: Your regex should match "Hazzzzzah" + testString: 'assert(haRegex.test("Hazzzzzah"), "Your regex should match "Hazzzzzah"");' +- text: Your regex should match "Hazzzzzzah" + testString: 'assert(haRegex.test("Hazzzzzzah"), "Your regex should match "Hazzzzzzah"");' +- text: Your regex should match "Hazzah" with 30 z\'s in it. + testString: 'assert(haRegex.test("Ha" + "z".repeat(30) + "ah"), "Your regex should match "Hazzah" with 30 z\"s in it.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +let haStr = "Hazzzzah"; +let haRegex = /change/; // Change this line +let result = haRegex.test(haStr); +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Specify Upper and Lower Number of Matches.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Specify Upper and Lower Number of Matches.md new file mode 100644 index 0000000000..5a564032a0 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Specify Upper and Lower Number of Matches.md @@ -0,0 +1,66 @@ +--- +id: 587d7db9367417b2b2512ba5 +title: Specify Upper and Lower Number of Matches +challengeType: 1 +--- + +## Description +
    +Recall that you use the plus sign + to look for one or more characters and the asterisk * to look for zero or more characters. These are convenient but sometimes you want to match a certain range of patterns. +You can specify the lower and upper number of patterns with quantity specifiers. Quantity specifiers are used with curly brackets ({ and }). You put two numbers between the curly brackets - for the lower and upper number of patterns. +For example, to match only the letter a appearing between 3 and 5 times in the string "ah", your regex would be /a{3,5}h/. +
    let A4 = "aaaah";
    let A2 = "aah";
    let multipleA = /a{3,5}h/;
    multipleA.test(A4); // Returns true
    multipleA.test(A2); // Returns false
    +
    + +## Instructions +
    +Change the regex ohRegex to match only 3 to 6 letter h's in the word "Oh no". +
    + +## Tests +
    + +```yml +- text: Your regex should use curly brackets. + testString: 'assert(ohRegex.source.match(/{.*?}/).length > 0, "Your regex should use curly brackets.");' +- text: Your regex should not match "Ohh no" + testString: 'assert(!ohRegex.test("Ohh no"), "Your regex should not match "Ohh no"");' +- text: Your regex should match "Ohhh no" + testString: 'assert(ohRegex.test("Ohhh no"), "Your regex should match "Ohhh no"");' +- text: Your regex should match "Ohhhh no" + testString: 'assert(ohRegex.test("Ohhhh no"), "Your regex should match "Ohhhh no"");' +- text: Your regex should match "Ohhhhh no" + testString: 'assert(ohRegex.test("Ohhhhh no"), "Your regex should match "Ohhhhh no"");' +- text: Your regex should match "Ohhhhhh no" + testString: 'assert(ohRegex.test("Ohhhhhh no"), "Your regex should match "Ohhhhhh no"");' +- text: Your regex should not match "Ohhhhhhh no" + testString: 'assert(!ohRegex.test("Ohhhhhhh no"), "Your regex should not match "Ohhhhhhh no"");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +let ohStr = "Ohhh no"; +let ohRegex = /change/; // Change this line +let result = ohRegex.test(ohStr); +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Use Capture Groups to Search and Replace.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Use Capture Groups to Search and Replace.md new file mode 100644 index 0000000000..433ab795d8 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Use Capture Groups to Search and Replace.md @@ -0,0 +1,60 @@ +--- +id: 587d7dbb367417b2b2512bab +title: Use Capture Groups to Search and Replace +challengeType: 1 +--- + +## Description +
    +Searching is useful. However, you can make searching even more powerful when it also changes (or replaces) the text you match. +You can search and replace text in a string using .replace() on a string. The inputs for .replace() is first the regex pattern you want to search for. The second parameter is the string to replace the match or a function to do something. +
    let wrongText = "The sky is silver.";
    let silverRegex = /silver/;
    wrongText.replace(silverRegex, "blue");
    // Returns "The sky is blue."
    +You can also access capture groups in the replacement string with dollar signs ($). +
    "Code Camp".replace(/(\w+)\s(\w+)/, '$2 $1');
    // Returns "Camp Code"
    +
    + +## Instructions +
    +Write a regex so that it will search for the string "good". Then update the replaceText variable to replace "good" with "okey-dokey". +
    + +## Tests +
    + +```yml +- text: You should use .replace() to search and replace. + testString: 'assert(code.match(/\.replace\(.*\)/), "You should use .replace() to search and replace.");' +- text: Your regex should change "This sandwich is good." to "This sandwich is okey-dokey." + testString: 'assert(result == "This sandwich is okey-dokey." && replaceText === "okey-dokey", "Your regex should change "This sandwich is good." to "This sandwich is okey-dokey."");' +- text: You should not change the last line. + testString: 'assert(code.match(/result\s*=\s*huhText\.replace\(.*?\)/), "You should not change the last line.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +let huhText = "This sandwich is good."; +let fixRegex = /change/; // Change this line +let replaceText = ""; // Change this line +let result = huhText.replace(fixRegex, replaceText); +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Using the Test Method.md b/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Using the Test Method.md new file mode 100644 index 0000000000..501bae5513 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/Using the Test Method.md @@ -0,0 +1,56 @@ +--- +id: 587d7db3367417b2b2512b8e +title: Using the Test Method +challengeType: 1 +--- + +## Description +
    +Regular expressions are used in programming languages to match parts of strings. You create patterns to help you do that matching. +If you want to find the word "the" in the string "The dog chased the cat", you could use the following regular expression: /the/. Notice that quote marks are not required within the regular expression. +JavaScript has multiple ways to use regexes. One way to test a regex is using the .test() method. The .test() method takes the regex, applies it to a string (which is placed inside the parentheses), and returns true or false if your pattern finds something or not. +
    let testStr = "freeCodeCamp";
    let testRegex = /Code/;
    testRegex.test(testStr);
    // Returns true
    +
    + +## Instructions +
    +Apply the regex myRegex on the string myString using the .test() method. +
    + +## Tests +
    + +```yml +- text: You should use .test() to test the regex. + testString: 'assert(code.match(/myRegex.test\(\s*myString\s*\)/), "You should use .test() to test the regex.");' +- text: Your result should return true. + testString: 'assert(result === true, "Your result should return true.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```js +let myString = "Hello, World!"; +let myRegex = /Hello/; +let result = myRegex; // Change this line +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/meta.json b/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/meta.json new file mode 100644 index 0000000000..050c00ae36 --- /dev/null +++ b/curriculum/challenges/02-javascript-algorithms-and-data-structures/regular-expressions/meta.json @@ -0,0 +1,8 @@ +{ + "name": "Regular Expressions", + "dashedName": "regular-expressions", + "order": 3, + "time": "5 hours", + "superBlock": "javascript-algorithms-and-data-structures", + "superOrder": 2 +} \ No newline at end of file diff --git a/curriculum/challenges/03-front-end-libraries/bootstrap/Add Elements within Your Bootstrap Wells.md b/curriculum/challenges/03-front-end-libraries/bootstrap/Add Elements within Your Bootstrap Wells.md new file mode 100644 index 0000000000..cfa69c61f3 --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/bootstrap/Add Elements within Your Bootstrap Wells.md @@ -0,0 +1,72 @@ +--- +id: bad87fee1348bd9aec908849 +title: Add Elements within Your Bootstrap Wells +challengeType: 0 +--- + +## Description +
    +Now we're several div elements deep on each column of our row. This is as deep as we'll need to go. Now we can add our button elements. +Nest three button elements within each of your well div elements. +
    + +## Instructions +
    + +
    + +## Tests +
    + +```yml +- text: Nest three button elements within each of your div elements with class well. + testString: 'assert($("div.well:eq(0)").children("button").length === 3 && $("div.well:eq(1)").children("button").length === 3, "Nest three button elements within each of your div elements with class well.");' +- text: You should have a total of 6 button elements. + testString: 'assert($("button") && $("button").length > 5, "You should have a total of 6 button elements.");' +- text: Make sure all your button elements have closing tags. + testString: 'assert(code.match(/<\/button>/g) && code.match(/
    + +## Challenge Seed +
    + +
    + +```html +
    +

    jQuery Playground

    +
    +
    +
    + + + +
    +
    +
    +
    + + + +
    +
    +
    +
    +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/03-front-end-libraries/bootstrap/Add Font Awesome Icons to all of our Buttons.md b/curriculum/challenges/03-front-end-libraries/bootstrap/Add Font Awesome Icons to all of our Buttons.md new file mode 100644 index 0000000000..1266c791ed --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/bootstrap/Add Font Awesome Icons to all of our Buttons.md @@ -0,0 +1,114 @@ +--- +id: bad87fee1348bd9aedc08845 +title: Add Font Awesome Icons to all of our Buttons +required: + - link: 'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.2.0/css/font-awesome.css' + raw: true +challengeType: 0 +--- + +## Description +
    +Font Awesome is a convenient library of icons. These icons are vector graphics, stored in the .svg file format. These icons are treated just like fonts. You can specify their size using pixels, and they will assume the font size of their parent HTML elements. +Use Font Awesome to add an info-circle icon to your info button and a trash icon to your delete button. +Note: The span element is an acceptable alternative to the i element for the directions below. +
    + +## Instructions +
    + +
    + +## Tests +
    + +```yml +- text: 'You should add a <i class="fa fa-info-circle"></i> within your info button element.' + testString: 'assert($(".btn-info > i").is(".fa.fa-info-circle") || $(".btn-info > span").is(".fa.fa-info-circle"), "You should add a <i class="fa fa-info-circle"></i> within your info button element.");' +- text: 'You should add a <i class="fa fa-trash"></i> within your delete button element.' + testString: 'assert($(".btn-danger > i").is(".fa.fa-trash") || $(".btn-danger > span").is(".fa.fa-trash"), "You should add a <i class="fa fa-trash"></i> within your delete button element.");' +- text: 'Make sure each of your i elements has a closing tag and <i class="fa fa-thumbs-up"></i> is in your like button element.' + testString: 'assert(code.match(/<\/i>|<\/span/g) && code.match(/<\/i|<\/span>/g).length > 2 && ($(".btn-primary > i").is(".fa.fa-thumbs-up") || $(".btn-primary > span").is(".fa.fa-thumbs-up")), "Make sure each of your i elements has a closing tag and <i class="fa fa-thumbs-up"></i> is in your like button element.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```html + + + +
    +
    +
    +

    CatPhotoApp

    +
    +
    + A cute orange cat lying on its back. +
    +
    + Three kittens running towards the camera. +
    +
    + +
    +
    + +
    +
    + +
    +
    +

    Things cats love:

    +
      +
    • cat nip
    • +
    • laser pointers
    • +
    • lasagna
    • +
    +

    Top 3 things cats hate:

    +
      +
    1. flea treatment
    2. +
    3. thunder
    4. +
    5. other cats
    6. +
    +
    + + + + + + + +
    +
    +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/03-front-end-libraries/bootstrap/Add Font Awesome Icons to our Buttons.md b/curriculum/challenges/03-front-end-libraries/bootstrap/Add Font Awesome Icons to our Buttons.md new file mode 100644 index 0000000000..69462fed00 --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/bootstrap/Add Font Awesome Icons to our Buttons.md @@ -0,0 +1,121 @@ +--- +id: bad87fee1348bd9aedd08845 +title: Add Font Awesome Icons to our Buttons +required: + - link: 'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.2.0/css/font-awesome.css' + raw: true +challengeType: 0 +--- + +## Description +
    +Font Awesome is a convenient library of icons. These icons are vector graphics, stored in the .svg file format. These icons are treated just like fonts. You can specify their size using pixels, and they will assume the font size of their parent HTML elements. +You can include Font Awesome in any app by adding the following code to the top of your HTML: +<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css" integrity="sha384-XdYbMnZ/QjLh6iI4ogqCTaIjrFk87ip+ekIjefZch0Y+PvJ8CDYtEs1ipDmPorQ+" crossorigin="anonymous"> +In this case, we've already added it for you to this page behind the scenes. +The i element was originally used to make other elements italic, but is now commonly used for icons. You can add the Font Awesome classes to the i element to turn it into an icon, for example: +<i class="fa fa-info-circle"></i> +Note that the span element is also acceptable for use with icons. +Use Font Awesome to add a thumbs-up icon to your like button by giving it an i element with the classes fa and fa-thumbs-up; make sure to keep the text "Like" next to the icon. +
    + +## Instructions +
    + +
    + +## Tests +
    + +```yml +- text: Add an i element with the classes fa and fa-thumbs-up. + testString: 'assert($("i").is(".fa.fa-thumbs-up") || $("span").is(".fa.fa-thumbs-up"), "Add an i element with the classes fa and fa-thumbs-up.");' +- text: Your fa-thumbs-up icon should be located within the Like button. + testString: 'assert(($("i.fa-thumbs-up").parent().text().match(/Like/gi) && $(".btn-primary > i").is(".fa.fa-thumbs-up")) || ($("span.fa-thumbs-up").parent().text().match(/Like/gi) && $(".btn-primary > span").is(".fa.fa-thumbs-up")), "Your fa-thumbs-up icon should be located within the Like button.");' +- text: Nest your i element within your button element. + testString: 'assert($("button").children("i").length > 0 || $("button").children("span").length > 0, "Nest your i element within your button element.");' +- text: Make sure your icon element has a closing tag. + testString: 'assert(code.match(/<\/i>|<\/span>/g), "Make sure your icon element has a closing tag.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```html + + + +
    +
    +
    +

    CatPhotoApp

    +
    +
    + A cute orange cat lying on its back. +
    +
    + Three kittens running towards the camera. +
    +
    + +
    +
    + +
    +
    + +
    +
    +

    Things cats love:

    +
      +
    • cat nip
    • +
    • laser pointers
    • +
    • lasagna
    • +
    +

    Top 3 things cats hate:

    +
      +
    1. flea treatment
    2. +
    3. thunder
    4. +
    5. other cats
    6. +
    +
    + + + + + + + +
    +
    +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/03-front-end-libraries/bootstrap/Add id Attributes to Bootstrap Elements.md b/curriculum/challenges/03-front-end-libraries/bootstrap/Add id Attributes to Bootstrap Elements.md new file mode 100644 index 0000000000..1d50abe945 --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/bootstrap/Add id Attributes to Bootstrap Elements.md @@ -0,0 +1,74 @@ +--- +id: bad87fee1348bd9aec908853 +title: Add id Attributes to Bootstrap Elements +challengeType: 0 +--- + +## Description +
    +Recall that in addition to class attributes, you can give each of your elements an id attribute. +Each id must be unique to a specific element and used only once per page. +Let's give a unique id to each of our div elements of class well. +Remember that you can give an element an id like this: +<div class="well" id="center-well"> +Give the well on the left the id of left-well. Give the well on the right the id of right-well. +
    + +## Instructions +
    + +
    + +## Tests +
    + +```yml +- text: Give your left well the id of left-well. + testString: 'assert($(".col-xs-6").children("#left-well") && $(".col-xs-6").children("#left-well").length > 0, "Give your left well the id of left-well.");' +- text: Give your right well the id of right-well. + testString: 'assert($(".col-xs-6").children("#right-well") && $(".col-xs-6").children("#right-well").length > 0, "Give your right well the id of right-well.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```html +
    +

    jQuery Playground

    +
    +
    +
    + + + +
    +
    +
    +
    + + + +
    +
    +
    +
    +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/03-front-end-libraries/bootstrap/Apply the Default Bootstrap Button Style.md b/curriculum/challenges/03-front-end-libraries/bootstrap/Apply the Default Bootstrap Button Style.md new file mode 100644 index 0000000000..6d1b75bf09 --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/bootstrap/Apply the Default Bootstrap Button Style.md @@ -0,0 +1,71 @@ +--- +id: bad87fee1348bd9aec908850 +title: Apply the Default Bootstrap Button Style +challengeType: 0 +guideUrl: 'https://guide.freecodecamp.org/certificates/apply-the-default-bootstrap-button-style' +--- + +## Description +
    +Bootstrap has another button class called btn-default. +Apply both the btn and btn-default classes to each of your button elements. +
    + +## Instructions +
    + +
    + +## Tests +
    + +```yml +- text: Apply the btn class to each of your button elements. + testString: 'assert($(".btn").length > 5, "Apply the btn class to each of your button elements.");' +- text: Apply the btn-default class to each of your button elements. + testString: 'assert($(".btn-default").length > 5, "Apply the btn-default class to each of your button elements.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```html +
    +

    jQuery Playground

    +
    +
    +
    + + + +
    +
    +
    +
    + + + +
    +
    +
    +
    +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/03-front-end-libraries/bootstrap/Call out Optional Actions with btn-info.md b/curriculum/challenges/03-front-end-libraries/bootstrap/Call out Optional Actions with btn-info.md new file mode 100644 index 0000000000..bc8795c78a --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/bootstrap/Call out Optional Actions with btn-info.md @@ -0,0 +1,114 @@ +--- +id: bad87fee1348cd8acef08813 +title: Call out Optional Actions with btn-info +challengeType: 0 +--- + +## Description +
    +Bootstrap comes with several pre-defined colors for buttons. The btn-info class is used to call attention to optional actions that the user can take. +Create a new block-level Bootstrap button below your "Like" button with the text "Info", and add Bootstrap's btn-info and btn-block classes to it. +Note that these buttons still need the btn and btn-block classes. +
    + +## Instructions +
    + +
    + +## Tests +
    + +```yml +- text: Create a new button element with the text "Info". + testString: 'assert(new RegExp("info","gi").test($("button").text()), "Create a new button element with the text "Info".");' +- text: Both of your Bootstrap buttons should have the btn and btn-block classes. + testString: 'assert($("button.btn-block.btn").length > 1, "Both of your Bootstrap buttons should have the btn and btn-block classes.");' +- text: Your new button should have the class btn-info. + testString: 'assert($("button").hasClass("btn-info"), "Your new button should have the class btn-info.");' +- text: Make sure all your button elements have a closing tag. + testString: 'assert(code.match(/<\/button>/g) && code.match(/
    + +## Challenge Seed +
    + +
    + +```html + + + +
    +

    CatPhotoApp

    + +

    Click here for cat photos.

    + + A cute orange cat lying on its back. + + Three kittens running towards the camera. + +

    Things cats love:

    +
      +
    • cat nip
    • +
    • laser pointers
    • +
    • lasagna
    • +
    +

    Top 3 things cats hate:

    +
      +
    1. flea treatment
    2. +
    3. thunder
    4. +
    5. other cats
    6. +
    +
    + + + + + + + +
    +
    +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/03-front-end-libraries/bootstrap/Center Text with Bootstrap.md b/curriculum/challenges/03-front-end-libraries/bootstrap/Center Text with Bootstrap.md new file mode 100644 index 0000000000..eff1465bbc --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/bootstrap/Center Text with Bootstrap.md @@ -0,0 +1,109 @@ +--- +id: bad87fee1348bd8acde08812 +title: Center Text with Bootstrap +challengeType: 0 +--- + +## Description +
    +Now that we're using Bootstrap, we can center our heading element to make it look better. All we need to do is add the class text-center to our h2 element. +Remember that you can add several classes to the same element by separating each of them with a space, like this: +<h2 class="red-text text-center">your text</h2> +
    + +## Instructions +
    + +
    + +## Tests +
    + +```yml +- text: Your h2 element should be centered by applying the class text-center + testString: 'assert($("h2").hasClass("text-center"), "Your h2 element should be centered by applying the class text-center");' +- text: Your h2 element should still have the class red-text + testString: 'assert($("h2").hasClass("red-text"), "Your h2 element should still have the class red-text");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```html + + + +
    +

    CatPhotoApp

    + +

    Click here for cat photos.

    + + A cute orange cat lying on its back. + + Three kittens running towards the camera. +

    Things cats love:

    +
      +
    • cat nip
    • +
    • laser pointers
    • +
    • lasagna
    • +
    +

    Top 3 things cats hate:

    +
      +
    1. flea treatment
    2. +
    3. thunder
    4. +
    5. other cats
    6. +
    +
    + + + + + + + +
    +
    +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/03-front-end-libraries/bootstrap/Create Bootstrap Wells.md b/curriculum/challenges/03-front-end-libraries/bootstrap/Create Bootstrap Wells.md new file mode 100644 index 0000000000..160348ce13 --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/bootstrap/Create Bootstrap Wells.md @@ -0,0 +1,64 @@ +--- +id: bad87fee1348bd9aec908848 +title: Create Bootstrap Wells +challengeType: 0 +--- + +## Description +
    +Bootstrap has a class called well that can create a visual sense of depth for your columns. +Nest one div element with the class well within each of your col-xs-6 div elements. +
    + +## Instructions +
    + +
    + +## Tests +
    + +```yml +- text: Add a div element with the class well inside each of your div elements with the class "col-xs-6" + testString: 'assert($("div.col-xs-6").not(":has(>div.well)").length < 1, "Add a div element with the class well inside each of your div elements with the class "col-xs-6"");' +- text: Nest both of your div elements with the class "col-xs-6" within your div element with the class "row". + testString: 'assert($("div.row > div.col-xs-6").length > 1, "Nest both of your div elements with the class "col-xs-6" within your div element with the class "row".");' +- text: Make sure all your div elements have closing tags. + testString: 'assert(code.match(/<\/div>/g) && code.match(/
    /g).length === code.match(/
    div elements have closing tags.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```html +
    +

    jQuery Playground

    +
    +
    + +
    +
    + +
    +
    +
    +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/03-front-end-libraries/bootstrap/Create a Block Element Bootstrap Button.md b/curriculum/challenges/03-front-end-libraries/bootstrap/Create a Block Element Bootstrap Button.md new file mode 100644 index 0000000000..19682cb625 --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/bootstrap/Create a Block Element Bootstrap Button.md @@ -0,0 +1,119 @@ +--- +id: bad87fee1348cd8acef08812 +title: Create a Block Element Bootstrap Button +challengeType: 0 +--- + +## Description +
    +Normally, your button elements with the btn and btn-default classes are only as wide as the text that they contain. For example: +<button class="btn btn-default">Submit</button> +This button would only be as wide as the word "Submit". + +By making them block elements with the additional class of btn-block, your button will stretch to fill your page's entire horizontal space and any elements following it will flow onto a "new line" below the block. +<button class="btn btn-default btn-block">Submit</button> +This button would take up 100% of the available width. + +Note that these buttons still need the btn class. +Add Bootstrap's btn-block class to your Bootstrap button. +
    + +## Instructions +
    + +
    + +## Tests +
    + +```yml +- text: Your button should still have the btn and btn-default classes. + testString: 'assert($("button").hasClass("btn") && $("button").hasClass("btn-default"), "Your button should still have the btn and btn-default classes.");' +- text: Your button should have the class btn-block. + testString: 'assert($("button").hasClass("btn-block"), "Your button should have the class btn-block.");' +- text: Make sure all your button elements have a closing tag. + testString: 'assert(code.match(/<\/button>/g) && code.match(/
    + +## Challenge Seed +
    + +
    + +```html + + + +
    +

    CatPhotoApp

    + +

    Click here for cat photos.

    + + A cute orange cat lying on its back. + + Three kittens running towards the camera. + +

    Things cats love:

    +
      +
    • cat nip
    • +
    • laser pointers
    • +
    • lasagna
    • +
    +

    Top 3 things cats hate:

    +
      +
    1. flea treatment
    2. +
    3. thunder
    4. +
    5. other cats
    6. +
    +
    + + + + + + + +
    +
    +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/03-front-end-libraries/bootstrap/Create a Bootstrap Button.md b/curriculum/challenges/03-front-end-libraries/bootstrap/Create a Bootstrap Button.md new file mode 100644 index 0000000000..eeeeb1f922 --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/bootstrap/Create a Bootstrap Button.md @@ -0,0 +1,111 @@ +--- +id: bad87fee1348cd8acdf08812 +title: Create a Bootstrap Button +challengeType: 0 +--- + +## Description +
    +Bootstrap has its own styles for button elements, which look much better than the plain HTML ones. +Create a new button element below your large kitten photo. Give it the btn and btn-default classes, as well as the text of "Like". +
    + +## Instructions +
    + +
    + +## Tests +
    + +```yml +- text: Create a new button element with the text "Like". + testString: 'assert(new RegExp("like","gi").test($("button").text()) && ($("img.img-responsive + button.btn").length > 0), "Create a new button element with the text "Like".");' +- text: 'Your new button should have two classes: btn and btn-default.' + testString: 'assert($("button").hasClass("btn") && $("button").hasClass("btn-default"), "Your new button should have two classes: btn and btn-default.");' +- text: Make sure all your button elements have a closing tag. + testString: 'assert(code.match(/<\/button>/g) && code.match(/
    + +## Challenge Seed +
    + +
    + +```html + + + +
    +

    CatPhotoApp

    + +

    Click here for cat photos.

    + + A cute orange cat lying on its back. + + Three kittens running towards the camera. + +

    Things cats love:

    +
      +
    • cat nip
    • +
    • laser pointers
    • +
    • lasagna
    • +
    +

    Top 3 things cats hate:

    +
      +
    1. flea treatment
    2. +
    3. thunder
    4. +
    5. other cats
    6. +
    +
    + + + + + + + +
    +
    +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/03-front-end-libraries/bootstrap/Create a Bootstrap Headline.md b/curriculum/challenges/03-front-end-libraries/bootstrap/Create a Bootstrap Headline.md new file mode 100644 index 0000000000..79e2be98db --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/bootstrap/Create a Bootstrap Headline.md @@ -0,0 +1,60 @@ +--- +id: bad87fee1348bd9aec908846 +title: Create a Bootstrap Headline +challengeType: 0 +--- + +## Description +
    +Now let's build something from scratch to practice our HTML, CSS and Bootstrap skills. +We'll build a jQuery playground, which we'll soon put to use in our jQuery challenges. +To start with, create an h3 element, with the text jQuery Playground. +Color your h3 element with the text-primary Bootstrap class, and center it with the text-center Bootstrap class. +
    + +## Instructions +
    + +
    + +## Tests +
    + +```yml +- text: Add a h3 element to your page. + testString: 'assert($("h3") && $("h3").length > 0, "Add a h3 element to your page.");' +- text: Make sure your h3 element has a closing tag. + testString: 'assert(code.match(/<\/h3>/g) && code.match(/

    /g).length === code.match(/

    h3 element has a closing tag.");' +- text: Your h3 element should be colored by applying the class text-primary + testString: 'assert($("h3").hasClass("text-primary"), "Your h3 element should be colored by applying the class text-primary");' +- text: Your h3 element should be centered by applying the class text-center + testString: 'assert($("h3").hasClass("text-center"), "Your h3 element should be centered by applying the class text-center");' +- text: Your h3 element should have the text jQuery Playground. + testString: 'assert.isTrue((/jquery(\s)+playground/gi).test($("h3").text()), "Your h3 element should have the text jQuery Playground.");' + +``` + +

    + +## Challenge Seed +
    + +
    + +```html + +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/03-front-end-libraries/bootstrap/Create a Bootstrap Row.md b/curriculum/challenges/03-front-end-libraries/bootstrap/Create a Bootstrap Row.md new file mode 100644 index 0000000000..4c28f8bcfa --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/bootstrap/Create a Bootstrap Row.md @@ -0,0 +1,60 @@ +--- +id: bad87fee1348bd9bec908846 +title: Create a Bootstrap Row +challengeType: 0 +--- + +## Description +
    +Now we'll create a Bootstrap row for our inline elements. +Create a div element below the h3 tag, with a class of row. +
    + +## Instructions +
    + +
    + +## Tests +
    + +```yml +- text: Add a div element below your h3 element. + testString: 'assert(($("div").length > 1) && ($("div.row h3.text-primary").length == 0) && ($("div.row + h3.text-primary").length == 0) && ($("h3.text-primary + div.row").length > 0), "Add a div element below your h3 element.");' +- text: Your div element should have the class row + testString: 'assert($("div").hasClass("row"), "Your div element should have the class row");' +- text: Your row div should be nested inside the container-fluid div + testString: 'assert($("div.container-fluid div.row").length > 0, "Your row div should be nested inside the container-fluid div");' +- text: Make sure your div element has a closing tag. + testString: 'assert(code.match(/<\/div>/g) && code.match(/
    /g).length === code.match(/
    div element has a closing tag.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```html +
    +

    jQuery Playground

    + +
    + +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/03-front-end-libraries/bootstrap/Create a Class to Target with jQuery Selectors.md b/curriculum/challenges/03-front-end-libraries/bootstrap/Create a Class to Target with jQuery Selectors.md new file mode 100644 index 0000000000..c66c1b1e50 --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/bootstrap/Create a Class to Target with jQuery Selectors.md @@ -0,0 +1,68 @@ +--- +id: bad87fee1348bd9aec908852 +title: Create a Class to Target with jQuery Selectors +challengeType: 0 +--- + +## Description +
    +Not every class needs to have corresponding CSS. Sometimes we create classes just for the purpose of selecting these elements more easily using jQuery. +Give each of your button elements the class target. +
    + +## Instructions +
    + +
    + +## Tests +
    + +```yml +- text: Apply the target class to each of your button elements. + testString: 'assert($(".target").length > 5, "Apply the target class to each of your button elements.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```html +
    +

    jQuery Playground

    +
    +
    +
    + + + +
    +
    +
    +
    + + + +
    +
    +
    +
    +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/03-front-end-libraries/bootstrap/Create a Custom Heading.md b/curriculum/challenges/03-front-end-libraries/bootstrap/Create a Custom Heading.md new file mode 100644 index 0000000000..37bb45b8d3 --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/bootstrap/Create a Custom Heading.md @@ -0,0 +1,111 @@ +--- +id: bad87fee1348bd9aede08845 +title: Create a Custom Heading +challengeType: 0 +--- + +## Description +
    +We will make a simple heading for our Cat Photo App by putting the title and relaxing cat image in the same row. +Remember, Bootstrap uses a responsive grid system, which makes it easy to put elements into rows and specify each element's relative width. Most of Bootstrap's classes can be applied to a div element. +Nest your first image and your h2 element within a single <div class="row"> element. Nest your h2 element within a <div class="col-xs-8"> and your image in a <div class="col-xs-4"> so that they are on the same line. +Notice how the image is now just the right size to fit along the text? +
    + +## Instructions +
    + +
    + +## Tests +
    + +```yml +- text: Your h2 element and topmost img element should both be nested together within a div element with the class row. + testString: 'assert($("div.row:has(h2)").length > 0 && $("div.row:has(img)").length > 0, "Your h2 element and topmost img element should both be nested together within a div element with the class row.");' +- text: Nest your topmost img element within a div with the class col-xs-4. + testString: 'assert($("div.col-xs-4:has(img)").length > 0 && $("div.col-xs-4:has(div)").length === 0, "Nest your topmost img element within a div with the class col-xs-4.");' +- text: Nest your h2 element within a div with the class col-xs-8. + testString: 'assert($("div.col-xs-8:has(h2)").length > 0 && $("div.col-xs-8:has(div)").length === 0, "Nest your h2 element within a div with the class col-xs-8.");' +- text: Make sure each of your div elements has a closing tag. + testString: 'assert(code.match(/<\/div>/g) && code.match(/
    /g).length === code.match(/
    div elements has a closing tag.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```html + + + + +
    +

    CatPhotoApp

    + + A cute orange cat lying on its back. + + Three kittens running towards the camera. +
    +
    + +
    +
    + +
    +
    + +
    +
    +

    Things cats love:

    +
      +
    • cat nip
    • +
    • laser pointers
    • +
    • lasagna
    • +
    +

    Top 3 things cats hate:

    +
      +
    1. flea treatment
    2. +
    3. thunder
    4. +
    5. other cats
    6. +
    +
    + + + + + + + +
    +
    +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/03-front-end-libraries/bootstrap/Ditch Custom CSS for Bootstrap.md b/curriculum/challenges/03-front-end-libraries/bootstrap/Ditch Custom CSS for Bootstrap.md new file mode 100644 index 0000000000..3e3e082668 --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/bootstrap/Ditch Custom CSS for Bootstrap.md @@ -0,0 +1,128 @@ +--- +id: bad87fee1347bd9aedf08845 +title: Ditch Custom CSS for Bootstrap +challengeType: 0 +--- + +## Description +
    +We can clean up our code and make our Cat Photo App look more conventional by using Bootstrap's built-in styles instead of the custom styles we created earlier. +Don't worry - there will be plenty of time to customize our CSS later. +Delete the .red-text, p, and .smaller-image CSS declarations from your style element so that the only declarations left in your style element are h2 and thick-green-border. +Then delete the p element that contains a dead link. Then remove the red-text class from your h2 element and replace it with the text-primary Bootstrap class. +Finally, remove the "smaller-image" class from your first img element and replace it with the img-responsive class. +
    + +## Instructions +
    + +
    + +## Tests +
    + +```yml +- text: Your h2 element should no longer have the class red-text. + testString: 'assert(!$("h2").hasClass("red-text"), "Your h2 element should no longer have the class red-text.");' +- text: Your h2 element should now have the class text-primary. + testString: 'assert($("h2").hasClass("text-primary"), "Your h2 element should now have the class text-primary.");' +- text: Your paragraph elements should no longer use the font Monospace. + testString: 'assert(!$("p").css("font-family").match(/monospace/i), "Your paragraph elements should no longer use the font Monospace.");' +- text: Remove the smaller-image class from your top image. + testString: 'assert(!$("img").hasClass("smaller-image"), "Remove the smaller-image class from your top image.");' +- text: Add the img-responsive class to your top image. + testString: 'assert($(".img-responsive").length > 1, "Add the img-responsive class to your top image.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```html + + + +
    +

    CatPhotoApp

    + +

    Click here for cat photos.

    + + A cute orange cat lying on its back. + + Three kittens running towards the camera. +
    +
    + +
    +
    + +
    +
    + +
    +
    +

    Things cats love:

    +
      +
    • cat nip
    • +
    • laser pointers
    • +
    • lasagna
    • +
    +

    Top 3 things cats hate:

    +
      +
    1. flea treatment
    2. +
    3. thunder
    4. +
    5. other cats
    6. +
    +
    + + + + + + + +
    +
    +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/03-front-end-libraries/bootstrap/Give Each Element a Unique id.md b/curriculum/challenges/03-front-end-libraries/bootstrap/Give Each Element a Unique id.md new file mode 100644 index 0000000000..7f8db86285 --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/bootstrap/Give Each Element a Unique id.md @@ -0,0 +1,81 @@ +--- +id: bad87fee1348bd9aec908855 +title: Give Each Element a Unique id +challengeType: 0 +--- + +## Description +
    +We will also want to be able to use jQuery to target each button by its unique id. +Give each of your buttons a unique id, starting with target1 and ending with target6. +Make sure that target1 to target3 are in #left-well, and target4 to target6 are in #right-well. +
    + +## Instructions +
    + +
    + +## Tests +
    + +```yml +- text: One button element should have the id target1. + testString: 'assert($("#left-well").children("#target1") && $("#left-well").children("#target1").length > 0, "One button element should have the id target1.");' +- text: One button element should have the id target2. + testString: 'assert($("#left-well").children("#target2") && $("#left-well").children("#target2").length > 0, "One button element should have the id target2.");' +- text: One button element should have the id target3. + testString: 'assert($("#left-well").children("#target3") && $("#left-well").children("#target3").length > 0, "One button element should have the id target3.");' +- text: One button element should have the id target4. + testString: 'assert($("#right-well").children("#target4") && $("#right-well").children("#target4").length > 0, "One button element should have the id target4.");' +- text: One button element should have the id target5. + testString: 'assert($("#right-well").children("#target5") && $("#right-well").children("#target5").length > 0, "One button element should have the id target5.");' +- text: One button element should have the id target6. + testString: 'assert($("#right-well").children("#target6") && $("#right-well").children("#target6").length > 0, "One button element should have the id target6.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```html +
    +

    jQuery Playground

    +
    +
    +

    #left-well

    +
    + + + +
    +
    +
    +

    #right-well

    +
    + + + +
    +
    +
    +
    +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/03-front-end-libraries/bootstrap/House our page within a Bootstrap container-fluid div.md b/curriculum/challenges/03-front-end-libraries/bootstrap/House our page within a Bootstrap container-fluid div.md new file mode 100644 index 0000000000..58e0bab833 --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/bootstrap/House our page within a Bootstrap container-fluid div.md @@ -0,0 +1,56 @@ +--- +id: bad87fee1348bd9aec908746 +title: House our page within a Bootstrap container-fluid div +challengeType: 0 +--- + +## Description +
    +Now let's make sure all the content on your page is mobile-responsive. +Let's nest your h3 element within a div element with the class container-fluid. +
    + +## Instructions +
    + +
    + +## Tests +
    + +```yml +- text: Your div element should have the class container-fluid. + testString: 'assert($("div").hasClass("container-fluid"), "Your div element should have the class container-fluid.");' +- text: Make sure each of your div elements has a closing tag. + testString: 'assert(code.match(/<\/div>/g) && code.match(/
    /g).length === code.match(/
    div elements has a closing tag.");' +- text: Nest your h3 element inside a div element. + testString: 'assert($("div").children("h3").length >0, "Nest your h3 element inside a div element.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```html +

    jQuery Playground

    + + +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/03-front-end-libraries/bootstrap/Label Bootstrap Buttons.md b/curriculum/challenges/03-front-end-libraries/bootstrap/Label Bootstrap Buttons.md new file mode 100644 index 0000000000..a20561ec6a --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/bootstrap/Label Bootstrap Buttons.md @@ -0,0 +1,80 @@ +--- +id: bad87fee1348bd9aec908856 +title: Label Bootstrap Buttons +challengeType: 0 +--- + +## Description +
    +Just like we labeled our wells, we want to label our buttons. +Give each of your button elements text that corresponds to its id's selector. +
    + +## Instructions +
    + +
    + +## Tests +
    + +```yml +- text: 'Give your button element with the id target1 the text #target1.' + testString: 'assert(new RegExp("#target1","gi").test($("#target1").text()), "Give your button element with the id target1 the text #target1.");' +- text: 'Give your button element with the id target2 the text #target2.' + testString: 'assert(new RegExp("#target2","gi").test($("#target2").text()), "Give your button element with the id target2 the text #target2.");' +- text: 'Give your button element with the id target3 the text #target3.' + testString: 'assert(new RegExp("#target3","gi").test($("#target3").text()), "Give your button element with the id target3 the text #target3.");' +- text: 'Give your button element with the id target4 the text #target4.' + testString: 'assert(new RegExp("#target4","gi").test($("#target4").text()), "Give your button element with the id target4 the text #target4.");' +- text: 'Give your button element with the id target5 the text #target5.' + testString: 'assert(new RegExp("#target5","gi").test($("#target5").text()), "Give your button element with the id target5 the text #target5.");' +- text: 'Give your button element with the id target6 the text #target6.' + testString: 'assert(new RegExp("#target6","gi").test($("#target6").text()), "Give your button element with the id target6 the text #target6.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```html +
    +

    jQuery Playground

    +
    +
    +

    #left-well

    +
    + + + +
    +
    +
    +

    #right-well

    +
    + + + +
    +
    +
    +
    +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/03-front-end-libraries/bootstrap/Label Bootstrap Wells.md b/curriculum/challenges/03-front-end-libraries/bootstrap/Label Bootstrap Wells.md new file mode 100644 index 0000000000..5d5cd5d4c9 --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/bootstrap/Label Bootstrap Wells.md @@ -0,0 +1,77 @@ +--- +id: bad87fee1348bd9aec908854 +title: Label Bootstrap Wells +challengeType: 0 +--- + +## Description +
    +For the sake of clarity, let's label both of our wells with their ids. +Above your left-well, inside its col-xs-6 div element, add a h4 element with the text #left-well. +Above your right-well, inside its col-xs-6 div element, add a h4 element with the text #right-well. +
    + +## Instructions +
    + +
    + +## Tests +
    + +```yml +- text: 'Add an h4 element to each of your <div class="col-xs-6"> elements.' + testString: 'assert($(".col-xs-6").children("h4") && $(".col-xs-6").children("h4").length > 1, "Add an h4 element to each of your <div class="col-xs-6"> elements.");' +- text: 'One h4 element should have the text #left-well.' + testString: 'assert(new RegExp("#left-well","gi").test($("h4").text()), "One h4 element should have the text #left-well.");' +- text: 'One h4 element should have the text #right-well.' + testString: 'assert(new RegExp("#right-well","gi").test($("h4").text()), "One h4 element should have the text #right-well.");' +- text: Make sure all your h4 elements have closing tags. + testString: 'assert(code.match(/<\/h4>/g) && code.match(/

    /g).length === code.match(/

    h4 elements have closing tags.");' + +``` + +

    + +## Challenge Seed +
    + +
    + +```html +
    +

    jQuery Playground

    +
    +
    + +
    + + + +
    +
    +
    + +
    + + + +
    +
    +
    +
    +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/03-front-end-libraries/bootstrap/Line up Form Elements Responsively with Bootstrap.md b/curriculum/challenges/03-front-end-libraries/bootstrap/Line up Form Elements Responsively with Bootstrap.md new file mode 100644 index 0000000000..beff3c0022 --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/bootstrap/Line up Form Elements Responsively with Bootstrap.md @@ -0,0 +1,131 @@ +--- +id: bad87fee1348bd9aec908845 +title: Line up Form Elements Responsively with Bootstrap +required: + - link: 'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.2.0/css/font-awesome.css' + raw: true +challengeType: 0 +--- + +## Description +
    +Now let's get your form input and your submission button on the same line. We'll do this the same way we have previously: by using a div element with the class row, and other div elements within it using the col-xs-* class. +Nest both your form's text input and submit button within a div with the class row. Nest your form's text input within a div with the class of col-xs-7. Nest your form's submit button in a div with the class col-xs-5. +This is the last challenge we'll do for our Cat Photo App for now. We hope you've enjoyed learning Font Awesome, Bootstrap, and responsive design! +
    + +## Instructions +
    + +
    + +## Tests +
    + +```yml +- text: Nest your form submission button and text input in a div with class row. + testString: 'assert($("div.row:has(input[type=\"text\"])").length > 0 && $("div.row:has(button[type=\"submit\"])").length > 0, "Nest your form submission button and text input in a div with class row.");' +- text: Nest your form text input in a div with the class col-xs-7. + testString: 'assert($("div.col-xs-7:has(input[type=\"text\"])").length > 0, "Nest your form text input in a div with the class col-xs-7.");' +- text: Nest your form submission button in a div with the class col-xs-5. + testString: 'assert($("div.col-xs-5:has(button[type=\"submit\"])").length > 0, "Nest your form submission button in a div with the class col-xs-5.");' +- text: Make sure each of your div elements has a closing tag. + testString: 'assert(code.match(/<\/div>/g) && code.match(/
    /g).length === code.match(/
    div elements has a closing tag.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```html + + + +
    +
    +
    +

    CatPhotoApp

    +
    +
    + A cute orange cat lying on its back. +
    +
    + Three kittens running towards the camera. +
    +
    + +
    +
    + +
    +
    + +
    +
    +

    Things cats love:

    +
      +
    • cat nip
    • +
    • laser pointers
    • +
    • lasagna
    • +
    +

    Top 3 things cats hate:

    +
      +
    1. flea treatment
    2. +
    3. thunder
    4. +
    5. other cats
    6. +
    +
    +
    +
    + +
    +
    + +
    +
    +
    +
    + +
    +
    + +
    +
    + +
    +
    + + +
    +
    +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/03-front-end-libraries/bootstrap/Make Images Mobile Responsive.md b/curriculum/challenges/03-front-end-libraries/bootstrap/Make Images Mobile Responsive.md new file mode 100644 index 0000000000..c5aceeccbf --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/bootstrap/Make Images Mobile Responsive.md @@ -0,0 +1,114 @@ +--- +id: bad87fee1348bd9acde08812 +title: Make Images Mobile Responsive +challengeType: 0 +--- + +## Description +
    +First, add a new image below the existing one. Set its src attribute to https://bit.ly/fcc-running-cats. +It would be great if this image could be exactly the width of our phone's screen. +Fortunately, with Bootstrap, all we need to do is add the img-responsive class to your image. Do this, and the image should perfectly fit the width of your page. +
    + +## Instructions +
    + +
    + +## Tests +
    + +```yml +- text: You should have a total of two images. + testString: 'assert($("img").length === 2, "You should have a total of two images.");' +- text: Your new image should be below your old one and have the class img-responsive. + testString: 'assert($("img:eq(1)").hasClass("img-responsive"), "Your new image should be below your old one and have the class img-responsive.");' +- text: Your new image should not have the class smaller-image. + testString: 'assert(!$("img:eq(1)").hasClass("smaller-image"), "Your new image should not have the class smaller-image.");' +- text: 'Your new image should have a src of https://bit.ly/fcc-running-cats.' + testString: 'assert($("img:eq(1)").attr("src") === "https://bit.ly/fcc-running-cats", "Your new image should have a src of https://bit.ly/fcc-running-cats.");' +- text: Make sure your new img element has a closing angle bracket. + testString: 'assert(code.match(//g).length === 2 && code.match(/img element has a closing angle bracket.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```html + + + +
    +

    CatPhotoApp

    + +

    Click here for cat photos.

    + + A cute orange cat lying on its back. + +

    Things cats love:

    +
      +
    • cat nip
    • +
    • laser pointers
    • +
    • lasagna
    • +
    +

    Top 3 things cats hate:

    +
      +
    1. flea treatment
    2. +
    3. thunder
    4. +
    5. other cats
    6. +
    +
    + + + + + + + +
    +
    +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/03-front-end-libraries/bootstrap/Responsively Style Checkboxes.md b/curriculum/challenges/03-front-end-libraries/bootstrap/Responsively Style Checkboxes.md new file mode 100644 index 0000000000..d15d7f3ead --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/bootstrap/Responsively Style Checkboxes.md @@ -0,0 +1,120 @@ +--- +id: bad87fee1348bd9aeda08845 +title: Responsively Style Checkboxes +required: + - link: 'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.2.0/css/font-awesome.css' + raw: true +challengeType: 0 +--- + +## Description +
    +You can use Bootstrap's col-xs-* classes on form elements, too! This way, our checkboxes will be evenly spread out across the page, regardless of how wide the screen resolution is. +Nest all three of your checkboxes in a <div class="row"> element. Then nest each of them in a <div class="col-xs-4"> element. +
    + +## Instructions +
    + +
    + +## Tests +
    + +```yml +- text: Nest all of your checkboxes inside one div with the class row. + testString: 'assert($("div.row:has(input[type=\"checkbox\"])").length > 0, "Nest all of your checkboxes inside one div with the class row.");' +- text: Nest each of your checkboxes inside its own div with the class col-xs-4. + testString: 'assert($("div.col-xs-4:has(input[type=\"checkbox\"])").length > 2, "Nest each of your checkboxes inside its own div with the class col-xs-4.");' +- text: Make sure each of your div elements has a closing tag. + testString: 'assert(code.match(/<\/div>/g) && code.match(/
    /g).length === code.match(/
    div elements has a closing tag.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```html + + + +
    +
    +
    +

    CatPhotoApp

    +
    +
    + A cute orange cat lying on its back. +
    +
    + Three kittens running towards the camera. +
    +
    + +
    +
    + +
    +
    + +
    +
    +

    Things cats love:

    +
      +
    • cat nip
    • +
    • laser pointers
    • +
    • lasagna
    • +
    +

    Top 3 things cats hate:

    +
      +
    1. flea treatment
    2. +
    3. thunder
    4. +
    5. other cats
    6. +
    +
    +
    +
    + +
    +
    + +
    +
    + + + + + +
    +
    +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/03-front-end-libraries/bootstrap/Responsively Style Radio Buttons.md b/curriculum/challenges/03-front-end-libraries/bootstrap/Responsively Style Radio Buttons.md new file mode 100644 index 0000000000..64e34bd984 --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/bootstrap/Responsively Style Radio Buttons.md @@ -0,0 +1,114 @@ +--- +id: bad87fee1348bd9aedb08845 +title: Responsively Style Radio Buttons +required: + - link: 'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.2.0/css/font-awesome.css' + raw: true +challengeType: 0 +--- + +## Description +
    +You can use Bootstrap's col-xs-* classes on form elements, too! This way, our radio buttons will be evenly spread out across the page, regardless of how wide the screen resolution is. +Nest both your radio buttons within a <div class="row"> element. Then nest each of them within a <div class="col-xs-6"> element. +Note: As a reminder, radio buttons are input elements of type radio. +
    + +## Instructions +
    + +
    + +## Tests +
    + +```yml +- text: Nest all of your radio buttons inside one div with the class row. + testString: 'assert($("div.row:has(input[type=\"radio\"])").length > 0, "Nest all of your radio buttons inside one div with the class row.");' +- text: Nest each of your radio buttons inside its own div with the class col-xs-6. + testString: 'assert($("div.col-xs-6:has(input[type=\"radio\"])").length > 1, "Nest each of your radio buttons inside its own div with the class col-xs-6.");' +- text: Make sure each of your div elements has a closing tag. + testString: 'assert(code.match(/<\/div>/g) && code.match(/
    /g).length === code.match(/
    div elements has a closing tag.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```html + + + +
    +
    +
    +

    CatPhotoApp

    +
    +
    + A cute orange cat lying on its back. +
    +
    + Three kittens running towards the camera. +
    +
    + +
    +
    + +
    +
    + +
    +
    +

    Things cats love:

    +
      +
    • cat nip
    • +
    • laser pointers
    • +
    • lasagna
    • +
    +

    Top 3 things cats hate:

    +
      +
    1. flea treatment
    2. +
    3. thunder
    4. +
    5. other cats
    6. +
    +
    + + + + + + + +
    +
    +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/03-front-end-libraries/bootstrap/Split Your Bootstrap Row.md b/curriculum/challenges/03-front-end-libraries/bootstrap/Split Your Bootstrap Row.md new file mode 100644 index 0000000000..a068dd99b4 --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/bootstrap/Split Your Bootstrap Row.md @@ -0,0 +1,58 @@ +--- +id: bad87fee1348bd9aec908847 +title: Split Your Bootstrap Row +challengeType: 0 +--- + +## Description +
    +Now that we have a Bootstrap Row, let's split it into two columns to house our elements. +Create two div elements within your row, both with the class col-xs-6. +
    + +## Instructions +
    + +
    + +## Tests +
    + +```yml +- text: Nest two div class="col-xs-6" elements within your div class="row" element. + testString: 'assert($("div.row > div.col-xs-6").length > 1, "Nest two div class="col-xs-6" elements within your div class="row" element.");' +- text: Make sure all your div elements have closing tags. + testString: 'assert(code.match(/<\/div>/g) && code.match(/
    /g).length === code.match(/
    div elements have closing tags.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```html +
    +

    jQuery Playground

    +
    + + +
    +
    +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/03-front-end-libraries/bootstrap/Style Text Inputs as Form Controls.md b/curriculum/challenges/03-front-end-libraries/bootstrap/Style Text Inputs as Form Controls.md new file mode 100644 index 0000000000..dad3458bc1 --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/bootstrap/Style Text Inputs as Form Controls.md @@ -0,0 +1,131 @@ +--- +id: bad87fee1348bd9aed908845 +title: Style Text Inputs as Form Controls +required: + - link: 'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.2.0/css/font-awesome.css' + raw: true +challengeType: 0 +--- + +## Description +
    +You can add the fa-paper-plane Font Awesome icon by adding <i class="fa fa-paper-plane"></i> within your submit button element. +Give your form's text input field a class of form-control. Give your form's submit button the classes btn btn-primary. Also give this button the Font Awesome icon of fa-paper-plane. +All textual <input>, <textarea>, and <select> elements with the class .form-control have a width of 100%. +
    + +## Instructions +
    + +
    + +## Tests +
    + +```yml +- text: Give the submit button in your form the classes btn btn-primary. + testString: 'assert($("button[type=\"submit\"]").hasClass("btn btn-primary"), "Give the submit button in your form the classes btn btn-primary.");' +- text: 'Add a <i class="fa fa-paper-plane"></i> within your submit button element.' + testString: 'assert($("button[type=\"submit\"]:has(i.fa.fa-paper-plane)").length > 0, "Add a <i class="fa fa-paper-plane"></i> within your submit button element.");' +- text: Give the text input in your form the class form-control. + testString: 'assert($("input[type=\"text\"]").hasClass("form-control"), "Give the text input in your form the class form-control.");' +- text: Make sure each of your i elements has a closing tag. + testString: 'assert(code.match(/<\/i>/g) && code.match(/<\/i/g).length > 3, "Make sure each of your i elements has a closing tag.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```html + + + +
    +
    +
    +

    CatPhotoApp

    +
    +
    + A cute orange cat lying on its back. +
    +
    + Three kittens running towards the camera. +
    +
    + +
    +
    + +
    +
    + +
    +
    +

    Things cats love:

    +
      +
    • cat nip
    • +
    • laser pointers
    • +
    • lasagna
    • +
    +

    Top 3 things cats hate:

    +
      +
    1. flea treatment
    2. +
    3. thunder
    4. +
    5. other cats
    6. +
    +
    +
    +
    + +
    +
    + +
    +
    +
    +
    + +
    +
    + +
    +
    + +
    +
    + + +
    +
    +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/03-front-end-libraries/bootstrap/Taste the Bootstrap Button Color Rainbow.md b/curriculum/challenges/03-front-end-libraries/bootstrap/Taste the Bootstrap Button Color Rainbow.md new file mode 100644 index 0000000000..9e2c950aee --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/bootstrap/Taste the Bootstrap Button Color Rainbow.md @@ -0,0 +1,112 @@ +--- +id: bad87fee1348cd8acef08811 +title: Taste the Bootstrap Button Color Rainbow +challengeType: 0 +--- + +## Description +
    +The btn-primary class is the main color you'll use in your app. It is useful for highlighting actions you want your user to take. +Replace Bootstrap's btn-default class by btn-primary in your button. +Note that this button will still need the btn and btn-block classes. +
    + +## Instructions +
    + +
    + +## Tests +
    + +```yml +- text: Your button should have the class btn-primary. + testString: 'assert($("button").hasClass("btn-primary"), "Your button should have the class btn-primary.");' +- text: Your button should still have the btn and btn-block classes. + testString: 'assert($("button").hasClass("btn-block") && $("button").hasClass("btn"), "Your button should still have the btn and btn-block classes.");' +- text: Make sure all your button elements have a closing tag. + testString: 'assert(code.match(/<\/button>/g) && code.match(/
    + +## Challenge Seed +
    + +
    + +```html + + + +
    +

    CatPhotoApp

    + +

    Click here for cat photos.

    + + A cute orange cat lying on its back. + + Three kittens running towards the camera. + +

    Things cats love:

    +
      +
    • cat nip
    • +
    • laser pointers
    • +
    • lasagna
    • +
    +

    Top 3 things cats hate:

    +
      +
    1. flea treatment
    2. +
    3. thunder
    4. +
    5. other cats
    6. +
    +
    + + + + + + + +
    +
    +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/03-front-end-libraries/bootstrap/Use Comments to Clarify Code.md b/curriculum/challenges/03-front-end-libraries/bootstrap/Use Comments to Clarify Code.md new file mode 100644 index 0000000000..31a6170b99 --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/bootstrap/Use Comments to Clarify Code.md @@ -0,0 +1,78 @@ +--- +id: bad87fee1348bd9aec908857 +title: Use Comments to Clarify Code +challengeType: 0 +--- + +## Description +
    +When we start using jQuery, we will modify HTML elements without needing to actually change them in HTML. +Let's make sure that everyone knows they shouldn't actually modify any of this code directly. +Remember that you can start a comment with <!-- and end a comment with --> +Add a comment at the top of your HTML that says Only change code above this line. +
    + +## Instructions +
    + +
    + +## Tests +
    + +```yml +- text: 'Start a comment with <!-- at the top of your HTML.' + testString: 'assert(code.match(/^\s*.*this line))\s*.*this line.*\s*-->/gi), "Your comment should have the text Only change code above this line.");' +- text: 'Be sure to close your comment with -->.' + testString: 'assert(code.match(/-->.*\n+.+/g), "Be sure to close your comment with -->.");' +- text: You should have the same number of comment openers and closers. + testString: 'assert(code.match(//g).length, "You should have the same number of comment openers and closers.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```html +
    +

    jQuery Playground

    +
    +
    +

    #left-well

    +
    + + + +
    +
    +
    +

    #right-well

    +
    + + + +
    +
    +
    +
    +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/03-front-end-libraries/bootstrap/Use Responsive Design with Bootstrap Fluid Containers.md b/curriculum/challenges/03-front-end-libraries/bootstrap/Use Responsive Design with Bootstrap Fluid Containers.md new file mode 100644 index 0000000000..d555199262 --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/bootstrap/Use Responsive Design with Bootstrap Fluid Containers.md @@ -0,0 +1,112 @@ +--- +id: bad87fee1348bd9acde08712 +title: Use Responsive Design with Bootstrap Fluid Containers +challengeType: 0 +--- + +## Description +
    +In the HTML5 and CSS section of freeCodeCamp we built a Cat Photo App. Now let's go back to it. This time, we'll style it using the popular Bootstrap responsive CSS framework. +Bootstrap will figure out how wide your screen is and respond by resizing your HTML elements - hence the name Responsive Design. +With responsive design, there is no need to design a mobile version of your website. It will look good on devices with screens of any width. +You can add Bootstrap to any app by adding the following code to the top of your HTML: +<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous"/> +In this case, we've already added it for you to this page behind the scenes. Note that using either > or /> to close the link tag is acceptable. +To get started, we should nest all of our HTML (except the link tag and the style element) in a div element with the class container-fluid. +
    + +## Instructions +
    + +
    + +## Tests +
    + +```yml +- text: Your div element should have the class container-fluid. + testString: 'assert($("div").hasClass("container-fluid"), "Your div element should have the class container-fluid.");' +- text: Make sure your div element has a closing tag. + testString: 'assert(code.match(/<\/div>/g) && code.match(/
    /g).length === code.match(/
    div element has a closing tag.");' +- text: Make sure you have nested all HTML elements after the closing style tag in .container-fluid. + testString: 'assert($(".container-fluid").children().length >= 8, "Make sure you have nested all HTML elements after the closing style tag in .container-fluid.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```html + + + +

    CatPhotoApp

    + +

    Click here for cat photos.

    + +A cute orange cat lying on its back. + +

    Things cats love:

    +
      +
    • cat nip
    • +
    • laser pointers
    • +
    • lasagna
    • +
    +

    Top 3 things cats hate:

    +
      +
    1. flea treatment
    2. +
    3. thunder
    4. +
    5. other cats
    6. +
    +
    + + + + + + + +
    +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/03-front-end-libraries/bootstrap/Use a span to Target Inline Elements.md b/curriculum/challenges/03-front-end-libraries/bootstrap/Use a span to Target Inline Elements.md new file mode 100644 index 0000000000..946b81724c --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/bootstrap/Use a span to Target Inline Elements.md @@ -0,0 +1,116 @@ +--- +id: bad87fee1348bd9aedf08845 +title: Use a span to Target Inline Elements +challengeType: 0 +--- + +## Description +
    +You can use spans to create inline elements. Remember when we used the btn-block class to make the button fill the entire row? + + +That illustrates the difference between an "inline" element and a "block" element. +By using the inline span element, you can put several elements on the same line, and even style different parts of the same line differently. +Nest the word "love" in your "Things cats love" element below within a span element. Then give that span the class text-danger to make the text red. +Here's how you would do this with the "Top 3 things cats hate" element: +<p>Top 3 things cats <span class="text-danger">hate:</span></p> +
    + +## Instructions +
    + +
    + +## Tests +
    + +```yml +- text: Your span element should be inside your p element. + testString: 'assert($("p span") && $("p span").length > 0, "Your span element should be inside your p element.");' +- text: Your span element should have just the text love. + testString: 'assert($("p span") && $("p span").text().match(/love/i) && !$("p span").text().match(/Things cats/i), "Your span element should have just the text love.");' +- text: Your span element should have class text-danger. + testString: 'assert($("span").hasClass("text-danger"), "Your span element should have class text-danger.");' +- text: Make sure your span element has a closing tag. + testString: 'assert(code.match(/<\/span>/g) && code.match(//g).length === code.match(/span element has a closing tag.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```html + + + +
    +

    CatPhotoApp

    + + A cute orange cat lying on its back. + + Three kittens running towards the camera. +
    +
    + +
    +
    + +
    +
    + +
    +
    +

    Things cats love:

    +
      +
    • cat nip
    • +
    • laser pointers
    • +
    • lasagna
    • +
    +

    Top 3 things cats hate:

    +
      +
    1. flea treatment
    2. +
    3. thunder
    4. +
    5. other cats
    6. +
    +
    + + + + + + + +
    +
    +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/03-front-end-libraries/bootstrap/Use the Bootstrap Grid to Put Elements Side By Side.md b/curriculum/challenges/03-front-end-libraries/bootstrap/Use the Bootstrap Grid to Put Elements Side By Side.md new file mode 100644 index 0000000000..e0e27f0ac8 --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/bootstrap/Use the Bootstrap Grid to Put Elements Side By Side.md @@ -0,0 +1,119 @@ +--- +id: bad88fee1348ce8acef08815 +title: Use the Bootstrap Grid to Put Elements Side By Side +challengeType: 0 +--- + +## Description +
    +Bootstrap uses a responsive 12-column grid system, which makes it easy to put elements into rows and specify each element's relative width. Most of Bootstrap's classes can be applied to a div element. +Bootstrap has different column width attributes that it uses depending on how wide the user's screen is. For example, phones have narrow screens, and laptops have wider screens. +Take for example Bootstrap's col-md-* class. Here, md means medium, and * is a number specifying how many columns wide the element should be. In this case, the column width of an element on a medium-sized screen, such as a laptop, is being specified. +In the Cat Photo App that we're building, we'll use col-xs-*, where xs means extra small (like an extra-small mobile phone screen), and * is the number of columns specifying how many columns wide the element should be. +Put the Like, Info and Delete buttons side-by-side by nesting all three of them within one <div class="row"> element, then each of them within a <div class="col-xs-4"> element. +The row class is applied to a div, and the buttons themselves can be nested within it. +
    + +## Instructions +
    + +
    + +## Tests +
    + +```yml +- text: Your buttons should all be nested within the same div element with the class row. + testString: 'assert($("div.row:has(button)").length > 0, "Your buttons should all be nested within the same div element with the class row.");' +- text: Each of your Bootstrap buttons should be nested within its own div element with the class col-xs-4. + testString: 'assert($("div.col-xs-4:has(button)").length > 2, "Each of your Bootstrap buttons should be nested within its own div element with the class col-xs-4.");' +- text: Make sure each of your button elements has a closing tag. + testString: 'assert(code.match(/<\/button>/g) && code.match(/
    + +## Challenge Seed +
    + +
    + +```html + + + +
    +

    CatPhotoApp

    + +

    Click here for cat photos.

    + + A cute orange cat lying on its back. + + Three kittens running towards the camera. + + + +

    Things cats love:

    +
      +
    • cat nip
    • +
    • laser pointers
    • +
    • lasagna
    • +
    +

    Top 3 things cats hate:

    +
      +
    1. flea treatment
    2. +
    3. thunder
    4. +
    5. other cats
    6. +
    +
    + + + + + + + +
    +
    +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/03-front-end-libraries/bootstrap/Warn Your Users of a Dangerous Action with btn-danger.md b/curriculum/challenges/03-front-end-libraries/bootstrap/Warn Your Users of a Dangerous Action with btn-danger.md new file mode 100644 index 0000000000..bc20061488 --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/bootstrap/Warn Your Users of a Dangerous Action with btn-danger.md @@ -0,0 +1,115 @@ +--- +id: bad87fee1348ce8acef08814 +title: Warn Your Users of a Dangerous Action with btn-danger +challengeType: 0 +--- + +## Description +
    +Bootstrap comes with several pre-defined colors for buttons. The btn-danger class is the button color you'll use to notify users that the button performs a destructive action, such as deleting a cat photo. +Create a button with the text "Delete" and give it the class btn-danger. +Note that these buttons still need the btn and btn-block classes. +
    + +## Instructions +
    + +
    + +## Tests +
    + +```yml +- text: Create a new button element with the text "Delete". + testString: 'assert(new RegExp("Delete","gi").test($("button").text()), "Create a new button element with the text "Delete".");' +- text: All of your Bootstrap buttons should have the btn and btn-block classes. + testString: 'assert($("button.btn-block.btn").length > 2, "All of your Bootstrap buttons should have the btn and btn-block classes.");' +- text: Your new button should have the class btn-danger. + testString: 'assert($("button").hasClass("btn-danger"), "Your new button should have the class btn-danger.");' +- text: Make sure all your button elements have a closing tag. + testString: 'assert(code.match(/<\/button>/g) && code.match(/
    + +## Challenge Seed +
    + +
    + +```html + + + +
    +

    CatPhotoApp

    + +

    Click here for cat photos.

    + + A cute orange cat lying on its back. + + Three kittens running towards the camera. + + +

    Things cats love:

    +
      +
    • cat nip
    • +
    • laser pointers
    • +
    • lasagna
    • +
    +

    Top 3 things cats hate:

    +
      +
    1. flea treatment
    2. +
    3. thunder
    4. +
    5. other cats
    6. +
    +
    + + + + + + + +
    +
    +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/03-front-end-libraries/bootstrap/meta.json b/curriculum/challenges/03-front-end-libraries/bootstrap/meta.json new file mode 100644 index 0000000000..ed2e7d1f5d --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/bootstrap/meta.json @@ -0,0 +1,8 @@ +{ + "name": "Bootstrap", + "dashedName": "bootstrap", + "order": 2, + "time": "5 hours", + "superBlock": "front-end-libraries", + "superOrder": 3 +} \ No newline at end of file diff --git a/curriculum/challenges/03-front-end-libraries/front-end-libraries-projects/Build a Drum Machine.md b/curriculum/challenges/03-front-end-libraries/front-end-libraries-projects/Build a Drum Machine.md new file mode 100644 index 0000000000..b098f108ec --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/front-end-libraries-projects/Build a Drum Machine.md @@ -0,0 +1,51 @@ +--- +id: 587d7dbc367417b2b2512bae +title: Build a Drum Machine +isRequired: true +challengeType: 3 +--- + +## Description +
    +Objective: Build a CodePen.io app that is functionally similar to this: https://codepen.io/freeCodeCamp/full/MJyNMd. +Fulfill the below user stories and get all of the tests to pass. Give it your own personal style. +You can use any mix of HTML, JavaScript, CSS, Bootstrap, SASS, React, Redux, and jQuery to complete this project. You should use a frontend framework (like React for example) because this section is about learning frontend frameworks. Additional technologies not listed above are not recommended and using them is at your own risk. We are looking at supporting other frontend frameworks like Angular and Vue, but they are not currently supported. We will accept and try to fix all issue reports that use the suggested technology stack for this project. Happy coding! +User Story #1: I should be able to see an outer container with a corresponding id="drum-machine" that contains all other elements. +User Story #2: Within #drum-machine I can see an element with a corresponding id="display". +User Story #3: Within #drum-machine I can see 9 clickable drum pad elements, each with a class name of drum-pad, a unique id that describes the audio clip the drum pad will be set up to trigger, and an inner text that corresponds to one of the following keys on the keyboard: Q, W, E, A, S, D, Z, X, C. The drum pads MUST be in this order. +User Story #4: Within each .drum-pad, there should be an HTML5 audio element which has a src attribute pointing to an audio clip, a class name of clip, and an id corresponding to the inner text of its parent .drum-pad (e.g. id="Q", id="W", id="E" etc.). +User Story #5: When I click on a .drum-pad element, the audio clip contained in its child audio element should be triggered. +User Story #6: When I press the trigger key associated with each .drum-pad, the audio clip contained in its child audio element should be triggered (e.g. pressing the Q key should trigger the drum pad which contains the string "Q", pressing the W key should trigger the drum pad which contains the string "W", etc.). +User Story #7: When a .drum-pad is triggered, a string describing the associated audio clip is displayed as the inner text of the #display element (each string must be unique). +You can build your project by forking this CodePen pen. Or you can use this CDN link to run the tests in any environment you like: https://cdn.freecodecamp.org/testable-projects-fcc/v1/bundle.js +Once you're done, submit the URL to your working project with all its tests passing. +Remember to use the Read-Search-Ask method if you get stuck. +
    + +## Instructions +
    + +
    + +## Tests +
    + +```yml +[] + +``` + +
    + +## Challenge Seed +
    + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/03-front-end-libraries/front-end-libraries-projects/Build a JavaScript Calculator.md b/curriculum/challenges/03-front-end-libraries/front-end-libraries-projects/Build a JavaScript Calculator.md new file mode 100644 index 0000000000..be6a77efe1 --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/front-end-libraries-projects/Build a JavaScript Calculator.md @@ -0,0 +1,61 @@ +--- +id: bd7158d8c442eddfaeb5bd17 +title: Build a JavaScript Calculator +challengeType: 3 +isRequired: true +--- + +## Description +
    +Objective: Build a CodePen.io app that is functionally similar to this: https://codepen.io/freeCodeCamp/full/wgGVVX. +Fulfill the below user stories and get all of the tests to pass. Give it your own personal style. +You can use any mix of HTML, JavaScript, CSS, Bootstrap, SASS, React, Redux, and jQuery to complete this project. You should use a frontend framework (like React for example) because this section is about learning frontend frameworks. Additional technologies not listed above are not recommended and using them is at your own risk. We are looking at supporting other frontend frameworks like Angular and Vue, but they are not currently supported. We will accept and try to fix all issue reports that use the suggested technology stack for this project. Happy coding! +User Story #1: My calculator should contain a clickable element containing an = (equal sign) with a corresponding id="equals". +User Story #2: My calculator should contain 10 clickable elements containing one number each from 0-9, with the following corresponding IDs: id="zero", id="one", id="two", id="three", id="four", id="five", id="six", id="seven", id="eight", and id="nine". +User Story #3: My calculator should contain 4 clickable elements each containing one of the 4 primary mathematical operators with the following corresponding IDs: id="add", id="subtract", id="multiply", id="divide". +User Story #4: My calculator should contain a clickable element containing a . (decimal point) symbol with a corresponding id="decimal". +User Story #5: My calculator should contain a clickable element with an id="clear". +User Story #6: My calculator should contain an element to display values with a corresponding id="display". +User Story #7: At any time, pressing the clear button clears the input and output values, and returns the calculator to its initialized state; 0 should be shown in the element with the id of display. +User Story #8: As I input numbers, I should be able to see my input in the element with the id of display. +User Story #9: In any order, I should be able to add, subtract, multiply and divide a chain of numbers of any length, and when I hit =, the correct result should be shown in the element with the id of display. +User Story #10: When inputting numbers, my calculator should not allow a number to begin with multiple zeros. +User Story #11: When the decimal element is clicked, a . should append to the currently displayed value; two . in one number should not be accepted. +User Story #12: I should be able to perform any operation (+, -, *, /) on numbers containing decimal points. +User Story #13: If 2 or more operators are entered consecutively, the operation performed should be the last operator entered. +User Story #14: Pressing an operator immediately following = should start a new calculation that operates on the result of the previous evaluation. +User Story #15: My calculator should have several decimal places of precision when it comes to rounding (note that there is no exact standard, but you should be able to handle calculations like 2 / 7 with reasonable precision to at least 4 decimal places). +Note On Calculator Logic: It should be noted that there are two main schools of thought on calculator input logic: immediate execution logic and formula logic. Our example utilizes formula logic and observes order of operation precedence, immediate execution does not. Either is acceptable, but please note that depending on which you choose, your calculator may yield different results than ours for certain equations (see below example). As long as your math can be verified by another production calculator, please do not consider this a bug. +EXAMPLE: 3 + 5 x 6 - 2 / 4 =
    • Immediate Execution Logic: 11.5
    • Formula/Expression Logic: 32.5
    +You can build your project by forking this CodePen pen. Or you can use this CDN link to run the tests in any environment you like: https://cdn.freecodecamp.org/testable-projects-fcc/v1/bundle.js +Once you're done, submit the URL to your working project with all its tests passing. +Remember to use the Read-Search-Ask method if you get stuck. +
    + +## Instructions +
    + +
    + +## Tests +
    + +```yml +[] + +``` + +
    + +## Challenge Seed +
    + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/03-front-end-libraries/front-end-libraries-projects/Build a Markdown Previewer.md b/curriculum/challenges/03-front-end-libraries/front-end-libraries-projects/Build a Markdown Previewer.md new file mode 100644 index 0000000000..08841f2694 --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/front-end-libraries-projects/Build a Markdown Previewer.md @@ -0,0 +1,52 @@ +--- +id: bd7157d8c242eddfaeb5bd13 +title: Build a Markdown Previewer +isRequired: true +challengeType: 3 +--- + +## Description +
    +Objective: Build a CodePen.io app that is functionally similar to this: https://codepen.io/freeCodeCamp/full/GrZVVO. +Fulfill the below user stories and get all of the tests to pass. Give it your own personal style. +You can use any mix of HTML, JavaScript, CSS, Bootstrap, SASS, React, Redux, and jQuery to complete this project. You should use a frontend framework (like React for example) because this section is about learning frontend frameworks. Additional technologies not listed above are not recommended and using them is at your own risk. We are looking at supporting other frontend frameworks like Angular and Vue, but they are not currently supported. We will accept and try to fix all issue reports that use the suggested technology stack for this project. Happy coding! +User Story #1: I can see a textarea element with a corresponding id="editor". +User Story #2: I can see an element with a corresponding id="preview". +User Story #3: When I enter text into the #editor element, the #preview element is updated as I type to display the content of the textarea. +User Story #4: When I enter GitHub flavored markdown into the #editor element, the text is rendered as HTML in the #preview element as I type (HINT: You don't need to parse Markdown yourself - you can import the Marked library for this: https://cdnjs.com/libraries/marked). +User Story #5: When my markdown previewer first loads, the default text in the #editor field should contain valid markdown that represents at least one of each of the following elements: a header (H1 size), a sub header (H2 size), a link, inline code, a code block, a list item, a blockquote, an image, and bolded text. +User Story #6: When my markdown previewer first loads, the default markdown in the #editor field should be rendered as HTML in the #preview element. +Optional Bonus (you do not need to make this test pass): When I click a link rendered by my markdown previewer, the link is opened up in a new tab (HINT: read the Marked.js docs for this one!). +Optional Bonus (you do not need to make this test pass): My markdown previewer interprets carriage returns and renders them as br (line break) elements. +You can build your project by forking this CodePen pen. Or you can use this CDN link to run the tests in any environment you like: https://cdn.freecodecamp.org/testable-projects-fcc/v1/bundle.js +Once you're done, submit the URL to your working project with all its tests passing. +Remember to use the Read-Search-Ask method if you get stuck. +
    + +## Instructions +
    + +
    + +## Tests +
    + +```yml +[] + +``` + +
    + +## Challenge Seed +
    + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/03-front-end-libraries/front-end-libraries-projects/Build a Pomodoro Clock.md b/curriculum/challenges/03-front-end-libraries/front-end-libraries-projects/Build a Pomodoro Clock.md new file mode 100644 index 0000000000..b93210e8ba --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/front-end-libraries-projects/Build a Pomodoro Clock.md @@ -0,0 +1,72 @@ +--- +id: bd7158d8c442eddfaeb5bd0f +title: Build a Pomodoro Clock +isRequired: true +challengeType: 3 +--- + +## Description +
    +Objective: Build a CodePen.io app that is functionally similar to this: https://codepen.io/freeCodeCamp/full/XpKrrW. +Fulfill the below user stories and get all of the tests to pass. Give it your own personal style. +You can use any mix of HTML, JavaScript, CSS, Bootstrap, SASS, React, Redux, and jQuery to complete this project. You should use a frontend framework (like React for example) because this section is about learning frontend frameworks. Additional technologies not listed above are not recommended and using them is at your own risk. We are looking at supporting other frontend frameworks like Angular and Vue, but they are not currently supported. We will accept and try to fix all issue reports that use the suggested technology stack for this project. Happy coding! +User Story #1: I can see an element with id="break-label" that contains a string (e.g. "Break Length"). +User Story #2: I can see an element with id="session-label" that contains a string (e.g. "Session Length"). +User Story #3: I can see two clickable elements with corresponding IDs: id="break-decrement" and id="session-decrement". +User Story #4: I can see two clickable elements with corresponding IDs: id="break-increment" and id="session-increment". +User Story #5: I can see an element with a corresponding id="break-length", which by default (on load) displays a value of 5. +User Story #6: I can see an element with a corresponding id="session-length", which by default displays a value of 25. +User Story #7: I can see an element with a corresponding id="timer-label", that contains a string indicating a session is initialized (e.g. "Session"). +User Story #8: I can see an element with corresponding id="time-left". NOTE: Paused or running, the value in this field should always be displayed in mm:ss format (i.e. 25:00). +User Story #9: I can see a clickable element with a corresponding id="start_stop". +User Story #10: I can see a clickable element with a corresponding id="reset". +User Story #11: When I click the element with the id of reset, any running timer should be stopped, the value within id="break-length" should return to 5, the value within id="session-length" should return to 25, and the element with id="time-left" should reset to it's default state. +User Story #12: When I click the element with the id of break-decrement, the value within id="break-length" decrements by a value of 1, and I can see the updated value. +User Story #13: When I click the element with the id of break-increment, the value within id="break-length" increments by a value of 1, and I can see the updated value. +User Story #14: When I click the element with the id of session-decrement, the value within id="session-length" decrements by a value of 1, and I can see the updated value. +User Story #15: When I click the element with the id of session-increment, the value within id="session-length" increments by a value of 1, and I can see the updated value. +User Story #16: I should not be able to set a session or break length to <= 0. +User Story #17: I should not be able to set a session or break length to > 60. +User Story #18: When I first click the element with id="start_stop", the timer should begin running from the value currently displayed in id="session-length", even if the value has been incremented or decremented from the original value of 25. +User Story #19: If the timer is running, the element with the id of time-left should display the remaining time in mm:ss format (decrementing by a value of 1 and updating the display every 1000ms). +User Story #20: If the timer is running and I click the element with id="start_stop", the countdown should pause. +User Story #21: If the timer is paused and I click the element with id="start_stop", the countdown should resume running from the point at which it was paused. +User Story #22: When a session countdown reaches zero (NOTE: timer MUST reach 00:00), and a new countdown begins, the element with the id of timer-label should display a string indicating a break has begun. +User Story #23: When a session countdown reaches zero (NOTE: timer MUST reach 00:00), a new break countdown should begin, counting down from the value currently displayed in the id="break-length" element. +User Story #24: When a break countdown reaches zero (NOTE: timer MUST reach 00:00), and a new countdown begins, the element with the id of timer-label should display a string indicating a session has begun. +User Story #25: When a break countdown reaches zero (NOTE: timer MUST reach 00:00), a new session countdown should begin, counting down from the value currently displayed in the id="session-length" element. +User Story #26: When a countdown reaches zero (NOTE: timer MUST reach 00:00), a sound indicating that time is up should play. This should utilize an HTML5 audio tag and have a corresponding id="beep". +User Story #27: The audio element with id="beep" must be 1 second or longer. +User Story #28: The audio element with id of beep must stop playing and be rewound to the beginning when the element with the id of reset is clicked. +You can build your project by forking this CodePen pen. Or you can use this CDN link to run the tests in any environment you like: https://cdn.freecodecamp.org/testable-projects-fcc/v1/bundle.js +Once you're done, submit the URL to your working project with all its tests passing. +Remember to use the Read-Search-Ask method if you get stuck. +
    + +## Instructions +
    + +
    + +## Tests +
    + +```yml +[] + +``` + +
    + +## Challenge Seed +
    + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/03-front-end-libraries/front-end-libraries-projects/Build a Random Quote Machine.md b/curriculum/challenges/03-front-end-libraries/front-end-libraries-projects/Build a Random Quote Machine.md new file mode 100644 index 0000000000..149f24c7c0 --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/front-end-libraries-projects/Build a Random Quote Machine.md @@ -0,0 +1,55 @@ +--- +id: bd7158d8c442eddfaeb5bd13 +title: Build a Random Quote Machine +isRequired: true +challengeType: 3 +--- + +## Description +
    +Objective: Build a CodePen.io app that is functionally similar to this: https://codepen.io/freeCodeCamp/full/qRZeGZ. +Fulfill the below user stories and get all of the tests to pass. Give it your own personal style. +You can use any mix of HTML, JavaScript, CSS, Bootstrap, SASS, React, Redux, and jQuery to complete this project. You should use a frontend framework (like React for example) because this section is about learning frontend frameworks. Additional technologies not listed above are not recommended and using them is at your own risk. We are looking at supporting other frontend frameworks like Angular and Vue, but they are not currently supported. We will accept and try to fix all issue reports that use the suggested technology stack for this project. Happy coding! +User Story #1: I can see a wrapper element with a corresponding id="quote-box". +User Story #2: Within #quote-box, I can see an element with a corresponding id="text". +User Story #3: Within #quote-box, I can see an element with a corresponding id="author". +User Story #4: Within #quote-box, I can see a clickable element with a corresponding id="new-quote". +User Story #5: Within #quote-box, I can see a clickable element with a corresponding id="tweet-quote". +User Story #6: On first load, my quote machine displays a random quote in the element with id="text". +User Story #7: On first load, my quote machine displays the random quote's author in the element with id="author". +User Story #8: When the #new-quote button is clicked, my quote machine should fetch a new quote and display it in the #text element. +User Story #9: My quote machine should fetch the new quote's author when the #new-quote button is clicked and display it in the #author element. +User Story #10: I can tweet the current quote by clicking on the #tweet-quote a element. This a element should include the "twitter.com/intent/tweet" path in it's href attribute to tweet the current quote. +User Story #11: The #quote-box wrapper element should be horizontally centered. Please run tests with browser's zoom level at 100% and page maximized. +You can build your project by forking this CodePen pen. Or you can use this CDN link to run the tests in any environment you like: https://cdn.freecodecamp.org/testable-projects-fcc/v1/bundle.js +Once you're done, submit the URL to your working project with all its tests passing. +Remember to use the Read-Search-Ask method if you get stuck. +
    + +## Instructions +
    + +
    + +## Tests +
    + +```yml +[] + +``` + +
    + +## Challenge Seed +
    + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/03-front-end-libraries/front-end-libraries-projects/meta.json b/curriculum/challenges/03-front-end-libraries/front-end-libraries-projects/meta.json new file mode 100644 index 0000000000..61681ce53a --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/front-end-libraries-projects/meta.json @@ -0,0 +1,8 @@ +{ + "name": "Front End Libraries Projects", + "dashedName": "front-end-libraries-projects", + "order": 8, + "time": "150 hours", + "superBlock": "front-end-libraries", + "superOrder": 3 +} \ No newline at end of file diff --git a/curriculum/challenges/03-front-end-libraries/jquery/Change Text Inside an Element Using jQuery.md b/curriculum/challenges/03-front-end-libraries/jquery/Change Text Inside an Element Using jQuery.md new file mode 100644 index 0000000000..69ee7f85c0 --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/jquery/Change Text Inside an Element Using jQuery.md @@ -0,0 +1,93 @@ +--- +id: 564944c91be2204b269d51e3 +title: Change Text Inside an Element Using jQuery +challengeType: 6 +--- + +## Description +
    +Using jQuery, you can change the text between the start and end tags of an element. You can even change HTML markup. +jQuery has a function called .html() that lets you add HTML tags and text within an element. Any content previously within the element will be completely replaced with the content you provide using this function. +Here's how you would rewrite and emphasize the text of our heading: +$("h3").html("<em>jQuery Playground</em>"); +jQuery also has a similar function called .text() that only alters text without adding tags. In other words, this function will not evaluate any HTML tags passed to it, but will instead treat it as the text you want to replace the existing content with. +Change the button with id target4 by emphasizing its text. +Check this link to know more on the difference between <i> and <em> and their uses. +Note that while the <i> tag has traditionally been used to emphasize text, it has since been coopted for use as a tag for icons. The <em> tag is now widely accepted as the tag for emphasis. Either will work for this challenge. +
    + +## Instructions +
    + +
    + +## Tests +
    + +```yml +- text: Emphasize the text in your target4 button by adding HTML tags. + testString: 'assert.isTrue((/|\s*#target4\s*<\/em>|<\/i>/gi).test($("#target4").html()), "Emphasize the text in your target4 button by adding HTML tags.");' +- text: Make sure the text is otherwise unchanged. + testString: 'assert($("#target4") && $("#target4").text().trim() === "#target4", "Make sure the text is otherwise unchanged.");' +- text: Do not alter any other text. + testString: 'assert.isFalse((/|/gi).test($("h3").html()), "Do not alter any other text.");' +- text: Make sure you are using .html() and not .text(). + testString: 'assert(code.match(/\.html\(/g), "Make sure you are using .html() and not .text().");' +- text: Make sure to select button id="target4" with jQuery. + testString: 'assert(code.match(/\$\(\s*?(\"|\")#target4(\"|\")\s*?\)\.html\(/), "Make sure to select button id="target4" with jQuery.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```html + + + + +
    +

    jQuery Playground

    +
    +
    +

    #left-well

    +
    + + + +
    +
    +
    +

    #right-well

    +
    + + + +
    +
    +
    +
    +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/03-front-end-libraries/jquery/Change the CSS of an Element Using jQuery.md b/curriculum/challenges/03-front-end-libraries/jquery/Change the CSS of an Element Using jQuery.md new file mode 100644 index 0000000000..9ffd94d986 --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/jquery/Change the CSS of an Element Using jQuery.md @@ -0,0 +1,91 @@ +--- +id: bad87fee1348bd9aed908826 +title: Change the CSS of an Element Using jQuery +required: + - link: 'https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.2.0/animate.css' +challengeType: 6 +--- + +## Description +
    +We can also change the CSS of an HTML element directly with jQuery. +jQuery has a function called .css() that allows you to change the CSS of an element. +Here's how we would change its color to blue: +$("#target1").css("color", "blue"); +This is slightly different from a normal CSS declaration, because the CSS property and its value are in quotes, and separated with a comma instead of a colon. +Delete your jQuery selectors, leaving an empty document ready function. +Select target1 and change its color to red. +
    + +## Instructions +
    + +
    + +## Tests +
    + +```yml +- text: Your target1 element should have red text. + testString: 'assert($("#target1").css("color") === "rgb(255, 0, 0)", "Your target1 element should have red text.");' +- text: Only use jQuery to add these classes to the element. + testString: 'assert(!code.match(/class.*animated/g), "Only use jQuery to add these classes to the element.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```html + + + + +
    +

    jQuery Playground

    +
    +
    +

    #left-well

    +
    + + + +
    +
    +
    +

    #right-well

    +
    + + + +
    +
    +
    +
    +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/03-front-end-libraries/jquery/Clone an Element Using jQuery.md b/curriculum/challenges/03-front-end-libraries/jquery/Clone an Element Using jQuery.md new file mode 100644 index 0000000000..3419ebf7f5 --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/jquery/Clone an Element Using jQuery.md @@ -0,0 +1,90 @@ +--- +id: bad87fee1348bd9aed508826 +title: Clone an Element Using jQuery +challengeType: 6 +--- + +## Description +
    +In addition to moving elements, you can also copy them from one place to another. +jQuery has a function called clone() that makes a copy of an element. +For example, if we wanted to copy target2 from our left-well to our right-well, we would use: +$("#target2").clone().appendTo("#right-well"); +Did you notice this involves sticking two jQuery functions together? This is called function chaining and it's a convenient way to get things done with jQuery. +Clone your target5 element and append it to your left-well. +
    + +## Instructions +
    + +
    + +## Tests +
    + +```yml +- text: Your target5 element should be inside your right-well. + testString: 'assert($("#right-well").children("#target5").length > 0, "Your target5 element should be inside your right-well.");' +- text: A copy of your target5 element should also be inside your left-well. + testString: 'assert($("#left-well").children("#target5").length > 0, "A copy of your target5 element should also be inside your left-well.");' +- text: Only use jQuery to move these elements. + testString: 'assert(!code.match(/class.*animated/g), "Only use jQuery to move these elements.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```html + + + + +
    +

    jQuery Playground

    +
    +
    +

    #left-well

    +
    + + + +
    +
    +
    +

    #right-well

    +
    + + + +
    +
    +
    +
    +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/03-front-end-libraries/jquery/Delete Your jQuery Functions.md b/curriculum/challenges/03-front-end-libraries/jquery/Delete Your jQuery Functions.md new file mode 100644 index 0000000000..6b04fe7559 --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/jquery/Delete Your jQuery Functions.md @@ -0,0 +1,91 @@ +--- +id: bad87fee1348bd9aeda08726 +title: Delete Your jQuery Functions +required: + - link: 'https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.2.0/animate.css' +challengeType: 6 +--- + +## Description +
    +These animations were cool at first, but now they're getting kind of distracting. +Delete all three of these jQuery functions from your document ready function, but leave your document ready function itself intact. +
    + +## Instructions +
    + +
    + +## Tests +
    + +```yml +- text: Delete all three of your jQuery functions from your document ready function. + testString: 'assert(code.match(/\{\s*\}\);/g), "Delete all three of your jQuery functions from your document ready function.");' +- text: Leave your script element intact. + testString: 'assert(code.match(/ + + + +
    +

    jQuery Playground

    +
    +
    +

    #left-well

    +
    + + + +
    +
    +
    +

    #right-well

    +
    + + + +
    +
    +
    +
    +``` + + + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/03-front-end-libraries/jquery/Disable an Element Using jQuery.md b/curriculum/challenges/03-front-end-libraries/jquery/Disable an Element Using jQuery.md new file mode 100644 index 0000000000..d7add7981a --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/jquery/Disable an Element Using jQuery.md @@ -0,0 +1,87 @@ +--- +id: bad87fee1348bd9aed808826 +title: Disable an Element Using jQuery +challengeType: 6 +--- + +## Description +
    +You can also change the non-CSS properties of HTML elements with jQuery. For example, you can disable buttons. +When you disable a button, it will become grayed-out and can no longer be clicked. +jQuery has a function called .prop() that allows you to adjust the properties of elements. +Here's how you would disable all buttons: +$("button").prop("disabled", true); +Disable only the target1 button. +
    + +## Instructions +
    + +
    + +## Tests +
    + +```yml +- text: Disable your target1 button. + testString: 'assert($("#target1") && $("#target1").prop("disabled") && code.match(/[""]disabled[""],( true|true)/g), "Disable your target1 button.");' +- text: Do not disable any other buttons. + testString: 'assert($("#target2") && !$("#target2").prop("disabled"), "Do not disable any other buttons.");' +- text: Only use jQuery to add these classes to the element. + testString: 'assert(!code.match(/disabled[^<]*>/g), "Only use jQuery to add these classes to the element.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```html + + + + +
    +

    jQuery Playground

    +
    +
    +

    #left-well

    +
    + + + +
    +
    +
    +

    #right-well

    +
    + + + +
    +
    +
    +
    +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/03-front-end-libraries/jquery/Learn How Script Tags and Document Ready Work.md b/curriculum/challenges/03-front-end-libraries/jquery/Learn How Script Tags and Document Ready Work.md new file mode 100644 index 0000000000..1c6bd107d0 --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/jquery/Learn How Script Tags and Document Ready Work.md @@ -0,0 +1,81 @@ +--- +id: bad87fee1348bd9acdd08826 +title: Learn How Script Tags and Document Ready Work +challengeType: 6 +--- + +## Description +
    +Now we're ready to learn jQuery, the most popular JavaScript tool of all time. +Before we can start using jQuery, we need to add some things to our HTML. +First, add a script element at the top of your page. Be sure to close it on the following line. +Your browser will run any JavaScript inside a script element, including jQuery. +Inside your script element, add this code: $(document).ready(function() { to your script. Then close it on the following line (still inside your script element) with: }); +We'll learn more about functions later. The important thing to know is that code you put inside this function will run as soon as your browser has loaded your page. +This is important because without your document ready function, your code may run before your HTML is rendered, which would cause bugs. +
    + +## Instructions +
    + +
    + +## Tests +
    + +```yml +- text: Create a script element making sure it is valid and has a closing tag. + testString: 'assert(code.match(/<\/script\s*>/g) && code.match(//g) && code.match(/<\/script\s*>/g).length === code.match(//g).length, "Create a script element making sure it is valid and has a closing tag.");' +- text: 'You should add $(document).ready(function() { to the beginning of your script element.' + testString: 'assert(code.match(/\$\s*?\(\s*?document\s*?\)\.ready\s*?\(\s*?function\s*?\(\s*?\)\s*?\{/g), "You should add $(document).ready(function() { to the beginning of your script element.");' +- text: 'Close your $(document).ready(function() { function with });' + testString: 'assert(code.match(/\n*?\s*?\}\s*?\);/g), "Close your $(document).ready(function() { function with });");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```html + + +
    +

    jQuery Playground

    +
    +
    +

    #left-well

    +
    + + + +
    +
    +
    +

    #right-well

    +
    + + + +
    +
    +
    +
    +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/03-front-end-libraries/jquery/Remove Classes from an Element with jQuery.md b/curriculum/challenges/03-front-end-libraries/jquery/Remove Classes from an Element with jQuery.md new file mode 100644 index 0000000000..80d2e25beb --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/jquery/Remove Classes from an Element with jQuery.md @@ -0,0 +1,89 @@ +--- +id: bad87fee1348bd9aed918626 +title: Remove Classes from an Element with jQuery +required: + - link: 'https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.2.0/animate.css' +challengeType: 6 +--- + +## Description +
    +In the same way you can add classes to an element with jQuery's addClass() function, you can remove them with jQuery's removeClass() function. +Here's how you would do this for a specific button: +$("#target2").removeClass("btn-default"); +Let's remove the btn-default class from all of our button elements. +
    + +## Instructions +
    + +
    + +## Tests +
    + +```yml +- text: Remove the btn-default class from all of your button elements. + testString: 'assert($(".btn-default").length === 0, "Remove the btn-default class from all of your button elements.");' +- text: Only use jQuery to remove this class from the element. + testString: 'assert(code.match(/btn btn-default/g), "Only use jQuery to remove this class from the element.");' +- text: Only remove the btn-default class. + testString: 'assert(code.match(/\.[\v\s]*removeClass[\s\v]*\([\s\v]*("|")\s*btn-default\s*("|")[\s\v]*\)/gm), "Only remove the btn-default class.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```html + + + + +
    +

    jQuery Playground

    +
    +
    +

    #left-well

    +
    + + + +
    +
    +
    +

    #right-well

    +
    + + + +
    +
    +
    +
    +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/03-front-end-libraries/jquery/Remove an Element Using jQuery.md b/curriculum/challenges/03-front-end-libraries/jquery/Remove an Element Using jQuery.md new file mode 100644 index 0000000000..218b1509f4 --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/jquery/Remove an Element Using jQuery.md @@ -0,0 +1,83 @@ +--- +id: bad87fee1348bd9aed708826 +title: Remove an Element Using jQuery +challengeType: 6 +--- + +## Description +
    +Now let's remove an HTML element from your page using jQuery. +jQuery has a function called .remove() that will remove an HTML element entirely +Remove element target4 from the page by using the .remove() function. +
    + +## Instructions +
    + +
    + +## Tests +
    + +```yml +- text: Use jQuery to remove your target4 element from your page. + testString: 'assert($("#target4").length === 0 && code.match(/\$\([""]#target4[""]\).remove\(\)/g), "Use jQuery to remove your target4 element from your page.");' +- text: Only use jQuery to remove this element. + testString: 'assert(code.match(/id="target4/g) && !code.match(//g) && $("#right-well").length > 0, "Only use jQuery to remove this element.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```html + + + + +
    +

    jQuery Playground

    +
    +
    +

    #left-well

    +
    + + + +
    +
    +
    +

    #right-well

    +
    + + + +
    +
    +
    +
    +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/03-front-end-libraries/jquery/Target Elements by Class Using jQuery.md b/curriculum/challenges/03-front-end-libraries/jquery/Target Elements by Class Using jQuery.md new file mode 100644 index 0000000000..8564444569 --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/jquery/Target Elements by Class Using jQuery.md @@ -0,0 +1,87 @@ +--- +id: bad87fee1348bd9aedc08826 +title: Target Elements by Class Using jQuery +required: + - link: 'https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.2.0/animate.css' +challengeType: 6 +--- + +## Description +
    +You see how we made all of your button elements bounce? We selected them with $("button"), then we added some CSS classes to them with .addClass("animated bounce");. +You just used jQuery's .addClass() function, which allows you to add classes to elements. +First, let's target your div elements with the class well by using the $(".well") selector. +Note that, just like with CSS declarations, you type a . before the class's name. +Then use jQuery's .addClass() function to add the classes animated and shake. +For example, you could make all the elements with the class text-primary shake by adding the following to your document ready function: +$(".text-primary").addClass("animated shake"); +
    + +## Instructions +
    + +
    + +## Tests +
    + +```yml +- text: 'Use the jQuery addClass() function to give the classes animated and shake to all your elements with the class well.' + testString: 'assert($(".well").hasClass("animated") && $(".well").hasClass("shake"), "Use the jQuery addClass() function to give the classes animated and shake to all your elements with the class well.");' +- text: Only use jQuery to add these classes to the element. + testString: 'assert(!code.match(/class\.\*animated/g), "Only use jQuery to add these classes to the element.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```html + + + + +
    +

    jQuery Playground

    +
    +
    +

    #left-well

    +
    + + + +
    +
    +
    +

    #right-well

    +
    + + + +
    +
    +
    +
    +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/03-front-end-libraries/jquery/Target Elements by id Using jQuery.md b/curriculum/challenges/03-front-end-libraries/jquery/Target Elements by id Using jQuery.md new file mode 100644 index 0000000000..55d33872cb --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/jquery/Target Elements by id Using jQuery.md @@ -0,0 +1,90 @@ +--- +id: bad87fee1348bd9aeda08826 +title: Target Elements by id Using jQuery +required: + - link: 'https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.2.0/animate.css' +challengeType: 6 +--- + +## Description +
    +You can also target elements by their id attributes. +First target your button element with the id target3 by using the $("#target3") selector. +Note that, just like with CSS declarations, you type a # before the id's name. +Then use jQuery's .addClass() function to add the classes animated and fadeOut. +Here's how you'd make the button element with the id target6 fade out: +$("#target6").addClass("animated fadeOut"). +
    + +## Instructions +
    + +
    + +## Tests +
    + +```yml +- text: 'Select the button element with the id of target3 and use the jQuery addClass() function to give it the class of animated.' + testString: 'assert($("#target3").hasClass("animated"), "Select the button element with the id of target3 and use the jQuery addClass() function to give it the class of animated.");' +- text: 'Target the element with the id target3 and use the jQuery addClass() function to give it the class fadeOut.' + testString: 'assert(($("#target3").hasClass("fadeOut") || $("#target3").hasClass("fadeout")) && code.match(/\$\(\s*.#target3.\s*\)/g), "Target the element with the id target3 and use the jQuery addClass() function to give it the class fadeOut.");' +- text: Only use jQuery to add these classes to the element. + testString: 'assert(!code.match(/class.*animated/g), "Only use jQuery to add these classes to the element.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```html + + + + +
    +

    jQuery Playground

    +
    +
    +

    #left-well

    +
    + + + +
    +
    +
    +

    #right-well

    +
    + + + +
    +
    +
    +
    +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/03-front-end-libraries/jquery/Target Even Elements Using jQuery.md b/curriculum/challenges/03-front-end-libraries/jquery/Target Even Elements Using jQuery.md new file mode 100644 index 0000000000..ee6242f36a --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/jquery/Target Even Elements Using jQuery.md @@ -0,0 +1,96 @@ +--- +id: bad87fee1348bd9aed008826 +title: Target Even Elements Using jQuery +required: + - link: 'https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.2.0/animate.css' +challengeType: 6 +--- + +## Description +
    +You can also target elements based on their positions using :odd or :even selectors. +Note that jQuery is zero-indexed which means the first element in a selection has a position of 0. This can be a little confusing as, counter-intuitively, :odd selects the second element (position 1), fourth element (position 3), and so on. +Here's how you would target all the odd elements with class target and give them classes: +$(".target:odd").addClass("animated shake"); +Try selecting all the even target elements and giving them the classes of animated and shake. Remember that even refers to the position of elements with a zero-based system in mind. +
    + +## Instructions +
    + +
    + +## Tests +
    + +```yml +- text: All of the target elements that jQuery considers to be even should shake. + testString: 'assert($(".target:even").hasClass("animated") && $(".target:even").hasClass("shake"), "All of the target elements that jQuery considers to be even should shake.");' +- text: 'You should use the :even selector to modify these elements.' + testString: 'assert(code.match(/\:even/g), "You should use the :even selector to modify these elements.");' +- text: Only use jQuery to add these classes to the element. + testString: 'assert(code.match(/\$\(".target:even"\)/g) || code.match(/\$\(".target:even"\)/g) || code.match(/\$\(".target"\).filter\(":even"\)/g) || code.match(/\$\(".target"\).filter\(":even"\)/g), "Only use jQuery to add these classes to the element.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```html + + + + +
    +

    jQuery Playground

    +
    +
    +

    #left-well

    +
    + + + +
    +
    +
    +

    #right-well

    +
    + + + +
    +
    +
    +
    +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/03-front-end-libraries/jquery/Target HTML Elements with Selectors Using jQuery.md b/curriculum/challenges/03-front-end-libraries/jquery/Target HTML Elements with Selectors Using jQuery.md new file mode 100644 index 0000000000..d87b5e45be --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/jquery/Target HTML Elements with Selectors Using jQuery.md @@ -0,0 +1,88 @@ +--- +id: bad87fee1348bd9bedc08826 +title: Target HTML Elements with Selectors Using jQuery +required: + - link: 'https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.2.0/animate.css' +challengeType: 6 +--- + +## Description +
    +Now we have a document ready function. +Now let's write our first jQuery statement. All jQuery functions start with a $, usually referred to as a dollar sign operator, or as bling. +jQuery often selects an HTML element with a selector, then does something to that element. +For example, let's make all of your button elements bounce. Just add this code inside your document ready function: +$("button").addClass("animated bounce"); +Note that we've already included both the jQuery library and the Animate.css library in the background so that you can use them in the editor. So you are using jQuery to apply the Animate.css bounce class to your button elements. +
    + +## Instructions +
    + +
    + +## Tests +
    + +```yml +- text: 'Use the jQuery addClass() function to give the classes animated and bounce to your button elements.' + testString: 'assert($("button").hasClass("animated") && $("button").hasClass("bounce"), "Use the jQuery addClass() function to give the classes animated and bounce to your button elements.");' +- text: Only use jQuery to add these colors to the element. + testString: 'assert(!code.match(/class.*animated/g), "Only use jQuery to add these colors to the element.");' +- text: Your jQuery code should be within the $(document).ready(); function. + testString: 'assert(code.match(/\$\(document\)\.ready\(function.*(\s|\n)*.*button.*.addClass.*\);/g), "Your jQuery code should be within the $(document).ready(); function.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```html + + + + +
    +

    jQuery Playground

    +
    +
    +

    #left-well

    +
    + + + +
    +
    +
    +

    #right-well

    +
    + + + +
    +
    +
    +
    +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/03-front-end-libraries/jquery/Target a Specific Child of an Element Using jQuery.md b/curriculum/challenges/03-front-end-libraries/jquery/Target a Specific Child of an Element Using jQuery.md new file mode 100644 index 0000000000..347dcb5152 --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/jquery/Target a Specific Child of an Element Using jQuery.md @@ -0,0 +1,97 @@ +--- +id: bad87fee1348bd9aed108826 +title: Target a Specific Child of an Element Using jQuery +required: + - link: 'https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.2.0/animate.css' +challengeType: 6 +--- + +## Description +
    +You've seen why id attributes are so convenient for targeting with jQuery selectors. But you won't always have such neat ids to work with. +Fortunately, jQuery has some other tricks for targeting the right elements. +jQuery uses CSS Selectors to target elements. The target:nth-child(n) CSS selector allows you to select all the nth elements with the target class or element type. +Here's how you would give the third element in each well the bounce class: +$(".target:nth-child(3)").addClass("animated bounce"); +Make the second child in each of your well elements bounce. You must select the elements' children with the target class. +
    + +## Instructions +
    + +
    + +## Tests +
    + +```yml +- text: The second element in your target elements should bounce. + testString: 'assert($(".target:nth-child(2)").hasClass("animated") && $(".target:nth-child(2)").hasClass("bounce"), "The second element in your target elements should bounce.");' +- text: Only two elements should bounce. + testString: 'assert($(".animated.bounce").length === 2, "Only two elements should bounce.");' +- text: 'You should use the :nth-child() selector to modify these elements.' + testString: 'assert(code.match(/\:nth-child\(/g), "You should use the :nth-child() selector to modify these elements.");' +- text: Only use jQuery to add these classes to the element. + testString: 'assert(code.match(/\$\(".target:nth-child\(2\)"\)/g) || code.match(/\$\(".target:nth-child\(2\)"\)/g) || code.match(/\$\(".target"\).filter\(":nth-child\(2\)"\)/g) || code.match(/\$\(".target"\).filter\(":nth-child\(2\)"\)/g), "Only use jQuery to add these classes to the element.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```html + + + + +
    +

    jQuery Playground

    +
    +
    +

    #left-well

    +
    + + + +
    +
    +
    +

    #right-well

    +
    + + + +
    +
    +
    +
    +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/03-front-end-libraries/jquery/Target the Children of an Element Using jQuery.md b/curriculum/challenges/03-front-end-libraries/jquery/Target the Children of an Element Using jQuery.md new file mode 100644 index 0000000000..a22456d8f0 --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/jquery/Target the Children of an Element Using jQuery.md @@ -0,0 +1,90 @@ +--- +id: bad87fee1348bd9aed208826 +title: Target the Children of an Element Using jQuery +challengeType: 6 +--- + +## Description +
    +When HTML elements are placed one level below another they are called children of that element. For example, the button elements in this challenge with the text "#target1", "#target2", and "#target3" are all children of the <div class="well" id="left-well"> element. +jQuery has a function called children() that allows you to access the children of whichever element you've selected. +Here's an example of how you would use the children() function to give the children of your left-well element the color blue: +$("#left-well").children().css("color", "blue") +
    + +## Instructions +
    +Give all the children of your right-well element the color orange. +
    + +## Tests +
    + +```yml +- text: 'All children of #right-well should have orange text.' + testString: 'assert($("#right-well").children().css("color") === "rgb(255, 165, 0)", "All children of #right-well should have orange text.");' +- text: 'You should use the children() function to modify these elements.' + testString: 'assert(code.match(/\.children\(\)\.css/g), "You should use the children() function to modify these elements.");' +- text: Only use jQuery to add these classes to the element. + testString: 'assert(code.match(/
    /g), "Only use jQuery to add these classes to the element.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```html + + + + +
    +

    jQuery Playground

    +
    +
    +

    #left-well

    +
    + + + +
    +
    +
    +

    #right-well

    +
    + + + +
    +
    +
    +
    +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/03-front-end-libraries/jquery/Target the Parent of an Element Using jQuery.md b/curriculum/challenges/03-front-end-libraries/jquery/Target the Parent of an Element Using jQuery.md new file mode 100644 index 0000000000..2b3dc7cd2d --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/jquery/Target the Parent of an Element Using jQuery.md @@ -0,0 +1,95 @@ +--- +id: bad87fee1348bd9aed308826 +title: Target the Parent of an Element Using jQuery +challengeType: 6 +--- + +## Description +
    +Every HTML element has a parent element from which it inherits properties. +For example, your jQuery Playground h3 element has the parent element of <div class="container-fluid">, which itself has the parent body. +jQuery has a function called parent() that allows you to access the parent of whichever element you've selected. +Here's an example of how you would use the parent() function if you wanted to give the parent element of the left-well element a background color of blue: +$("#left-well").parent().css("background-color", "blue") +Give the parent of the #target1 element a background-color of red. +
    + +## Instructions +
    + +
    + +## Tests +
    + +```yml +- text: Your left-well element should have a red background. + testString: 'assert($("#left-well").css("background-color") === "red" || $("#left-well").css("background-color") === "rgb(255, 0, 0)" || $("#left-well").css("background-color").toLowerCase() === "#ff0000" || $("#left-well").css("background-color").toLowerCase() === "#f00", "Your left-well element should have a red background.");' +- text: 'You should use the .parent() function to modify this element.' + testString: 'assert(code.match(/\.parent\s*\(\s*\)\s*\.css/g), "You should use the .parent() function to modify this element.");' +- text: 'The .parent() method should be called on the #target1 element.' + testString: 'assert(code.match(/\$\s*?\(\s*?(?:"|")\s*?#target1\s*?(?:"|")\s*?\)\s*?\.parent/gi), "The .parent() method should be called on the #target1 element.");' +- text: Only use jQuery to add these classes to the element. + testString: 'assert(code.match(/
    /g), "Only use jQuery to add these classes to the element.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```html + + + + + +
    +

    jQuery Playground

    +
    +
    +

    #left-well

    +
    + + + +
    +
    +
    +

    #right-well

    +
    + + + +
    +
    +
    +
    + +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/03-front-end-libraries/jquery/Target the Same Element with Multiple jQuery Selectors.md b/curriculum/challenges/03-front-end-libraries/jquery/Target the Same Element with Multiple jQuery Selectors.md new file mode 100644 index 0000000000..8fbd4626f2 --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/jquery/Target the Same Element with Multiple jQuery Selectors.md @@ -0,0 +1,95 @@ +--- +id: bad87fee1348bd9aed908626 +title: Target the Same Element with Multiple jQuery Selectors +required: + - link: 'https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.2.0/animate.css' +challengeType: 6 +--- + +## Description +
    +Now you know three ways of targeting elements: by type: $("button"), by class: $(".btn"), and by id $("#target1"). +Although it is possible to add multiple classes in a single .addClass() call, let's add them to the same element in three separate ways. +Using .addClass(), add only one class at a time to the same element, three different ways: +Add the animated class to all elements with type button. +Add the shake class to all the buttons with class .btn. +Add the btn-primary class to the button with id #target1. +Note
    You should only be targeting one element and adding only one class at a time. Altogether, your three individual selectors will end up adding the three classes shake, animated, and btn-primary to #target1. +
    + +## Instructions +
    + +
    + +## Tests +
    + +```yml +- text: 'Use the $("button") selector.' + testString: 'assert(code.match(/\$\s*?\(\s*?(?:"|")\s*?button\s*?(?:"|")/gi), "Use the $("button") selector.");' +- text: 'Use the $(".btn") selector.' + testString: 'assert(code.match(/\$\s*?\(\s*?(?:"|")\s*?\.btn\s*?(?:"|")/gi), "Use the $(".btn") selector.");' +- text: 'Use the $("#target1") selector.' + testString: 'assert(code.match(/\$\s*?\(\s*?(?:"|")\s*?#target1\s*?(?:"|")/gi), "Use the $("#target1") selector.");' +- text: Only add one class with each of your three selectors. + testString: 'assert(code.match(/addClass/g) && code.match(/addClass\s*?\(\s*?("|")\s*?[\w-]+\s*?\1\s*?\)/g).length > 2, "Only add one class with each of your three selectors.");' +- text: 'Your #target1 element should have the classes animatedshake and btn-primary.' + testString: 'assert($("#target1").hasClass("animated") && $("#target1").hasClass("shake") && $("#target1").hasClass("btn-primary"), "Your #target1 element should have the classes animatedshake and btn-primary.");' +- text: Only use jQuery to add these classes to the element. + testString: 'assert(!code.match(/class.*animated/g), "Only use jQuery to add these classes to the element.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```html + + + + +
    +

    jQuery Playground

    +
    +
    +

    #left-well

    +
    + + + +
    +
    +
    +

    #right-well

    +
    + + + +
    +
    +
    +
    +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/03-front-end-libraries/jquery/Use appendTo to Move Elements with jQuery.md b/curriculum/challenges/03-front-end-libraries/jquery/Use appendTo to Move Elements with jQuery.md new file mode 100644 index 0000000000..5d7378c19d --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/jquery/Use appendTo to Move Elements with jQuery.md @@ -0,0 +1,88 @@ +--- +id: bad87fee1348bd9aed608826 +title: Use appendTo to Move Elements with jQuery +challengeType: 6 +--- + +## Description +
    +Now let's try moving elements from one div to another. +jQuery has a function called appendTo() that allows you to select HTML elements and append them to another element. +For example, if we wanted to move target4 from our right well to our left well, we would use: +$("#target4").appendTo("#left-well"); +Move your target2 element from your left-well to your right-well. +
    + +## Instructions +
    + +
    + +## Tests +
    + +```yml +- text: Your target2 element should not be inside your left-well. + testString: 'assert($("#left-well").children("#target2").length === 0, "Your target2 element should not be inside your left-well.");' +- text: Your target2 element should be inside your right-well. + testString: 'assert($("#right-well").children("#target2").length > 0, "Your target2 element should be inside your right-well.");' +- text: Only use jQuery to move these elements. + testString: 'assert(!code.match(/class.*animated/g), "Only use jQuery to move these elements.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```html + + + + +
    +

    jQuery Playground

    +
    +
    +

    #left-well

    +
    + + + +
    +
    +
    +

    #right-well

    +
    + + + +
    +
    +
    +
    +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/03-front-end-libraries/jquery/Use jQuery to Modify the Entire Page.md b/curriculum/challenges/03-front-end-libraries/jquery/Use jQuery to Modify the Entire Page.md new file mode 100644 index 0000000000..0545252f0a --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/jquery/Use jQuery to Modify the Entire Page.md @@ -0,0 +1,92 @@ +--- +id: bad87fee1348bd9aecb08826 +title: Use jQuery to Modify the Entire Page +required: + - link: 'https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.2.0/animate.css' +challengeType: 6 +--- + +## Description +
    +We're done playing with our jQuery playground. Let's tear it down! +jQuery can target the body element as well. +Here's how we would make the entire body fade out: $("body").addClass("animated fadeOut"); +But let's do something more dramatic. Add the classes animated and hinge to your body element. +
    + +## Instructions +
    + +
    + +## Tests +
    + +```yml +- text: Add the classes animated and hinge to your body element. + testString: 'assert($("body").hasClass("animated") && $("body").hasClass("hinge"), "Add the classes animated and hinge to your body element.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```html + + + + +
    +

    jQuery Playground

    +
    +
    +

    #left-well

    +
    + + + +
    +
    +
    +

    #right-well

    +
    + + + +
    +
    +
    +
    +``` + +
    + + + +
    + +## Solution +
    + +```js +// solution required +``` +
    diff --git a/curriculum/challenges/03-front-end-libraries/jquery/meta.json b/curriculum/challenges/03-front-end-libraries/jquery/meta.json new file mode 100644 index 0000000000..72fd981e8b --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/jquery/meta.json @@ -0,0 +1,8 @@ +{ + "name": "jQuery", + "dashedName": "jquery", + "order": 3, + "time": "3 hours", + "superBlock": "front-end-libraries", + "superOrder": 3 +} \ No newline at end of file diff --git a/curriculum/challenges/03-front-end-libraries/react-and-redux/Connect Redux to React.md b/curriculum/challenges/03-front-end-libraries/react-and-redux/Connect Redux to React.md new file mode 100644 index 0000000000..06f8eae4fc --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/react-and-redux/Connect Redux to React.md @@ -0,0 +1,133 @@ +--- +id: 5a24c314108439a4d4036147 +title: Connect Redux to React +challengeType: 6 +isRequired: false +--- + +## Description +
    +Now that you've written both the mapStateToProps() and the mapDispatchToProps() functions, you can use them to map state and dispatch to the props of one of your React components. The connect method from React Redux can handle this task. This method takes two optional arguments, mapStateToProps() and mapDispatchToProps(). They are optional because you may have a component that only needs access to state but doesn't need to dispatch any actions, or vice versa. +To use this method, pass in the functions as arguments, and immediately call the result with your component. This syntax is a little unusual and looks like: +connect(mapStateToProps, mapDispatchToProps)(MyComponent) +Note: If you want to omit one of the arguments to the connect method, you pass null in its place. +
    + +## Instructions +
    +The code editor has the mapStateToProps() and mapDispatchToProps() functions and a new React component called Presentational. Connect this component to Redux with the connect method from the ReactRedux global object, and call it immediately on the Presentational component. Assign the result to a new const called ConnectedComponent that represents the connected component. That's it, now you're connected to Redux! Try changing either of connect's arguments to null and observe the test results. +
    + +## Tests +
    + +```yml +- text: The Presentational component should render. + testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(AppWrapper)); return mockedComponent.find("Presentational").length === 1; })(), "The Presentational component should render.");' +- text: The Presentational component should receive a prop messages via connect. + testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(AppWrapper)); const props = mockedComponent.find("Presentational").props(); return props.messages === "__INITIAL__STATE__"; })(), "The Presentational component should receive a prop messages via connect.");' +- text: The Presentational component should receive a prop submitNewMessage via connect. + testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(AppWrapper)); const props = mockedComponent.find("Presentational").props(); return typeof props.submitNewMessage === "function"; })(), "The Presentational component should receive a prop submitNewMessage via connect.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```jsx +const addMessage = (message) => { + return { + type: 'ADD', + message: message + } +}; + +const mapStateToProps = (state) => { + return { + messages: state + } +}; + +const mapDispatchToProps = (dispatch) => { + return { + submitNewMessage: (message) => { + dispatch(addMessage(message)); + } + } +}; + +class Presentational extends React.Component { + constructor(props) { + super(props); + } + render() { + return

    This is a Presentational Component

    + } +}; + +const connect = ReactRedux.connect; +// change code below this line + +``` + +
    + + +### After Test +
    + +```js +console.info('after the test'); +``` + +
    + +
    + +## Solution +
    + + +```js +const addMessage = (message) => { + return { + type: 'ADD', + message: message + } +}; + +const mapStateToProps = (state) => { + return { + messages: state + } +}; + +const mapDispatchToProps = (dispatch) => { + return { + submitNewMessage: (message) => { + dispatch(addMessage(message)); + } + } +}; + +class Presentational extends React.Component { + constructor(props) { + super(props); + } + render() { + return

    This is a Presentational Component

    + } +}; + +const connect = ReactRedux.connect; +// change code below this line + +const ConnectedComponent = connect(mapStateToProps, mapDispatchToProps)(Presentational); + +``` + +
    diff --git a/curriculum/challenges/03-front-end-libraries/react-and-redux/Connect Redux to the Messages App.md b/curriculum/challenges/03-front-end-libraries/react-and-redux/Connect Redux to the Messages App.md new file mode 100644 index 0000000000..4bd18c735d --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/react-and-redux/Connect Redux to the Messages App.md @@ -0,0 +1,263 @@ +--- +id: 5a24c314108439a4d4036148 +title: Connect Redux to the Messages App +challengeType: 6 +isRequired: false +--- + +## Description +
    +Now that you understand how to use connect to connect React to Redux, you can apply what you've learned to your React component that handles messages. +In the last lesson, the component you connected to Redux was named Presentational, and this wasn't arbitrary. This term generally refers to React components that are not directly connected to Redux. They are simply responsible for the presentation of UI and do this as a function of the props they receive. By contrast, container components are connected to Redux. These are typically responsible for dispatching actions to the store and often pass store state to child components as props. +
    + +## Instructions +
    +The code editor has all the code you've written in this section so far. The only change is that the React component is renamed to Presentational. Create a new component held in a constant called Container that uses connect to connect the Presentational component to Redux. Then, in the AppWrapper, render the React Redux Provider component. Pass Provider the Redux store as a prop and render Container as a child. Once everything is setup, you will see the messages app rendered to the page again. +
    + +## Tests +
    + +```yml +- text: The AppWrapper should render to the page. + testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(AppWrapper)); return mockedComponent.find("AppWrapper").length === 1; })(), "The AppWrapper should render to the page.");' +- text: 'The Presentational component should render an h2, input, button, and ul elements.' + testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(AppWrapper)); return mockedComponent.find("Presentational").length === 1; })(), "The Presentational component should render an h2, input, button, and ul elements.");' +- text: 'The Presentational component should render an h2, input, button, and ul elements.' + testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(AppWrapper)); const PresentationalComponent = mockedComponent.find("Presentational"); return ( PresentationalComponent.find("div").length === 1 && PresentationalComponent.find("h2").length === 1 && PresentationalComponent.find("button").length === 1 && PresentationalComponent.find("ul").length === 1 ); })(), "The Presentational component should render an h2, input, button, and ul elements.");' +- text: The Presentational component should receive messages from the Redux store as a prop. + testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(AppWrapper)); const PresentationalComponent = mockedComponent.find("Presentational"); const props = PresentationalComponent.props(); return Array.isArray(props.messages); })(), "The Presentational component should receive messages from the Redux store as a prop.");' +- text: The Presentational component should receive the submitMessage action creator as a prop. + testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(AppWrapper)); const PresentationalComponent = mockedComponent.find("Presentational"); const props = PresentationalComponent.props(); return typeof props.submitNewMessage === "function"; })(), "The Presentational component should receive the submitMessage action creator as a prop.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```jsx +// Redux: +const ADD = 'ADD'; + +const addMessage = (message) => { + return { + type: ADD, + message: message + } +}; + +const messageReducer = (state = [], action) => { + switch (action.type) { + case ADD: + return [ + ...state, + action.message + ]; + default: + return state; + } +}; + +const store = Redux.createStore(messageReducer); + +// React: +class Presentational extends React.Component { + constructor(props) { + super(props); + this.state = { + input: ", + messages: [] + } + this.handleChange = this.handleChange.bind(this); + this.submitMessage = this.submitMessage.bind(this); + } + handleChange(event) { + this.setState({ + input: event.target.value + }); + } + submitMessage() { + const currentMessage = this.state.input; + this.setState({ + input: ", + messages: this.state.messages.concat(currentMessage) + }); + } + render() { + return ( +
    +

    Type in a new Message:

    +
    + +
      + {this.state.messages.map( (message, idx) => { + return ( +
    • {message}
    • + ) + }) + } +
    +
    + ); + } +}; + +// React-Redux: +const mapStateToProps = (state) => { + return { messages: state } +}; + +const mapDispatchToProps = (dispatch) => { + return { + submitNewMessage: (newMessage) => { + dispatch(addMessage(newMessage)) + } + } +}; + +const Provider = ReactRedux.Provider; +const connect = ReactRedux.connect; + +// define the Container component here: + + +class AppWrapper extends React.Component { + constructor(props) { + super(props); + } + render() { + // complete the return statement: + return (null); + } +}; +``` + +
    + + +### After Test +
    + +```js +console.info('after the test'); +``` + +
    + +
    + +## Solution +
    + + +```js +// Redux: +const ADD = 'ADD'; + +const addMessage = (message) => { + return { + type: ADD, + message: message + } +}; + +const messageReducer = (state = [], action) => { + switch (action.type) { + case ADD: + return [ + ...state, + action.message + ]; + default: + return state; + } +}; + +const store = Redux.createStore(messageReducer); + +// React: +class Presentational extends React.Component { + constructor(props) { + super(props); + this.state = { + input: ", + messages: [] + } + this.handleChange = this.handleChange.bind(this); + this.submitMessage = this.submitMessage.bind(this); + } + handleChange(event) { + this.setState({ + input: event.target.value + }); + } + submitMessage() { + const currentMessage = this.state.input; + this.setState({ + input: ", + messages: this.state.messages.concat(currentMessage) + }); + } + render() { + return ( +
    +

    Type in a new Message:

    +
    + +
      + {this.state.messages.map( (message, idx) => { + return ( +
    • {message}
    • + ) + }) + } +
    +
    + ); + } +}; + +// React-Redux: +const mapStateToProps = (state) => { + return { messages: state } +}; + +const mapDispatchToProps = (dispatch) => { + return { + submitNewMessage: (newMessage) => { + dispatch(addMessage(newMessage)) + } + } +}; + +const Provider = ReactRedux.Provider; +const connect = ReactRedux.connect; + +// define the Container component here: +const Container = connect(mapStateToProps, mapDispatchToProps)(Presentational); + +class AppWrapper extends React.Component { + constructor(props) { + super(props); + } + render() { + // complete the return statement: + return ( + + + + ); + } +}; +``` + +
    diff --git a/curriculum/challenges/03-front-end-libraries/react-and-redux/Extract Local State into Redux.md b/curriculum/challenges/03-front-end-libraries/react-and-redux/Extract Local State into Redux.md new file mode 100644 index 0000000000..8dfbb28630 --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/react-and-redux/Extract Local State into Redux.md @@ -0,0 +1,264 @@ +--- +id: 5a24c314108439a4d4036149 +title: Extract Local State into Redux +challengeType: 6 +isRequired: false +--- + +## Description +
    +You're almost done! Recall that you wrote all the Redux code so that Redux could control the state management of your React messages app. Now that Redux is connected, you need to extract the state management out of the Presentational component and into Redux. Currently, you have Redux connected, but you are handling the state locally within the Presentational component. +
    + +## Instructions +
    +In the Presentational component, first, remove the messages property in the local state. These messages will be managed by Redux. Next, modify the submitMessage() method so that it dispatches submitNewMessage() from this.props, and pass in the current message input from local state as an argument. Because you removed messages from local state, remove the messages property from the call to this.setState() here as well. Finally, modify the render() method so that it maps over the messages received from props rather than state. +Once these changes are made, the app will continue to function the same, except Redux manages the state. This example also illustrates how a component may have local state: your component still tracks user input locally in its own state. You can see how Redux provides a useful state management framework on top of React. You achieved the same result using only React's local state at first, and this is usually possible with simple apps. However, as your apps become larger and more complex, so does your state management, and this is the problem Redux solves. +
    + +## Tests +
    + +```yml +- text: The AppWrapper should render to the page. + testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(AppWrapper)); return mockedComponent.find("AppWrapper").length === 1; })(), "The AppWrapper should render to the page.");' +- text: 'The Presentational component should render an h2, input, button, and ul elements.' + testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(AppWrapper)); return mockedComponent.find("Presentational").length === 1; })(), "The Presentational component should render an h2, input, button, and ul elements.");' +- text: 'The Presentational component should render an h2, input, button, and ul elements.' + testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(AppWrapper)); const PresentationalComponent = mockedComponent.find("Presentational"); return ( PresentationalComponent.find("div").length === 1 && PresentationalComponent.find("h2").length === 1 && PresentationalComponent.find("button").length === 1 && PresentationalComponent.find("ul").length === 1 ); })(), "The Presentational component should render an h2, input, button, and ul elements.");' +- text: The Presentational component should receive messages from the Redux store as a prop. + testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(AppWrapper)); const PresentationalComponent = mockedComponent.find("Presentational"); const props = PresentationalComponent.props(); return Array.isArray(props.messages); })(), "The Presentational component should receive messages from the Redux store as a prop.");' +- text: The Presentational component should receive the submitMessage action creator as a prop. + testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(AppWrapper)); const PresentationalComponent = mockedComponent.find("Presentational"); const props = PresentationalComponent.props(); return typeof props.submitNewMessage === "function"; })(), "The Presentational component should receive the submitMessage action creator as a prop.");' +- text: 'The state of the Presentational component should contain one property, input, which is initialized to an empty string.' + testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(AppWrapper)); const PresentationalState = mockedComponent.find("Presentational").instance().state; return typeof PresentationalState.input === "string" && Object.keys(PresentationalState).length === 1; })(), "The state of the Presentational component should contain one property, input, which is initialized to an empty string.");' +- text: Typing in the input element should update the state of the Presentational component. + testString: 'async () => { const mockedComponent = Enzyme.mount(React.createElement(AppWrapper)); const testValue = "__MOCK__INPUT__"; const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 100)); const causeChange = (c, v) => c.find("input").simulate("change", { target: { value: v }}); let initialInput = mockedComponent.find("Presentational").find("input"); const changed = () => { causeChange(mockedComponent, testValue); return waitForIt(() => mockedComponent )}; const updated = await changed(); const updatedInput = updated.find("Presentational").find("input"); assert(initialInput.props().value === "" && updatedInput.props().value === "__MOCK__INPUT__", "Typing in the input element should update the state of the Presentational component."); }; ' +- text: Dispatching the submitMessage on the Presentational component should update Redux store and clear the input in local state. + testString: 'async () => { const mockedComponent = Enzyme.mount(React.createElement(AppWrapper)); const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 100)); let beforeProps = mockedComponent.find("Presentational").props(); const testValue = "__TEST__EVENT__INPUT__"; const causeChange = (c, v) => c.find("input").simulate("change", { target: { value: v }}); const changed = () => { causeChange(mockedComponent, testValue); return waitForIt(() => mockedComponent )}; const clickButton = () => { mockedComponent.find("button").simulate("click"); return waitForIt(() => mockedComponent )}; const afterChange = await changed(); const afterChangeInput = afterChange.find("input").props().value; const afterClick = await clickButton(); const afterProps = mockedComponent.find("Presentational").props(); assert(beforeProps.messages.length === 0 && afterChangeInput === testValue && afterProps.messages.pop() === testValue && afterClick.find("input").props().value === "", "Dispatching the submitMessage on the Presentational component should update Redux store and clear the input in local state."); }; ' +- text: The Presentational component should render the messages from the Redux store. + testString: 'async () => { const mockedComponent = Enzyme.mount(React.createElement(AppWrapper)); const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 100)); let beforeProps = mockedComponent.find("Presentational").props(); const testValue = "__TEST__EVENT__INPUT__"; const causeChange = (c, v) => c.find("input").simulate("change", { target: { value: v }}); const changed = () => { causeChange(mockedComponent, testValue); return waitForIt(() => mockedComponent )}; const clickButton = () => { mockedComponent.find("button").simulate("click"); return waitForIt(() => mockedComponent )}; const afterChange = await changed(); const afterChangeInput = afterChange.find("input").props().value; const afterClick = await clickButton(); const afterProps = mockedComponent.find("Presentational").props(); assert(beforeProps.messages.length === 0 && afterChangeInput === testValue && afterProps.messages.pop() === testValue && afterClick.find("input").props().value === "" && afterClick.find("ul").childAt(0).text() === testValue, "The Presentational component should render the messages from the Redux store."); }; ' + +``` + +
    + +## Challenge Seed +
    + +
    + +```jsx +// Redux: +const ADD = 'ADD'; + +const addMessage = (message) => { + return { + type: ADD, + message: message + } +}; + +const messageReducer = (state = [], action) => { + switch (action.type) { + case ADD: + return [ + ...state, + action.message + ]; + default: + return state; + } +}; + +const store = Redux.createStore(messageReducer); + +// React: +const Provider = ReactRedux.Provider; +const connect = ReactRedux.connect; + +// Change code below this line +class Presentational extends React.Component { + constructor(props) { + super(props); + this.state = { + input: ", + messages: [] + } + this.handleChange = this.handleChange.bind(this); + this.submitMessage = this.submitMessage.bind(this); + } + handleChange(event) { + this.setState({ + input: event.target.value + }); + } + submitMessage() { + this.setState({ + input: ", + messages: this.state.messages.concat(this.state.input) + }); + } + render() { + return ( +
    +

    Type in a new Message:

    +
    + +
      + {this.state.messages.map( (message, idx) => { + return ( +
    • {message}
    • + ) + }) + } +
    +
    + ); + } +}; +// Change code above this line + +const mapStateToProps = (state) => { + return {messages: state} +}; + +const mapDispatchToProps = (dispatch) => { + return { + submitNewMessage: (message) => { + dispatch(addMessage(message)) + } + } +}; + +const Container = connect(mapStateToProps, mapDispatchToProps)(Presentational); + +class AppWrapper extends React.Component { + render() { + return ( + + + + ); + } +}; +``` + +
    + + +### After Test +
    + +```js +console.info('after the test'); +``` + +
    + +
    + +## Solution +
    + + +```js +// Redux: +const ADD = 'ADD'; + +const addMessage = (message) => { + return { + type: ADD, + message: message + } +}; + +const messageReducer = (state = [], action) => { + switch (action.type) { + case ADD: + return [ + ...state, + action.message + ]; + default: + return state; + } +}; + +const store = Redux.createStore(messageReducer); + +// React: +const Provider = ReactRedux.Provider; +const connect = ReactRedux.connect; + +// Change code below this line +class Presentational extends React.Component { + constructor(props) { + super(props); + this.state = { + input: " + } + this.handleChange = this.handleChange.bind(this); + this.submitMessage = this.submitMessage.bind(this); + } + handleChange(event) { + this.setState({ + input: event.target.value + }); + } + submitMessage() { + this.props.submitNewMessage(this.state.input); + this.setState({ + input: " + }); + } + render() { + return ( +
    +

    Type in a new Message:

    +
    + +
      + {this.props.messages.map( (message, idx) => { + return ( +
    • {message}
    • + ) + }) + } +
    +
    + ); + } +}; +// Change code above this line + +const mapStateToProps = (state) => { + return {messages: state} +}; + +const mapDispatchToProps = (dispatch) => { + return { + submitNewMessage: (message) => { + dispatch(addMessage(message)) + } + } +}; + +const Container = connect(mapStateToProps, mapDispatchToProps)(Presentational); + +class AppWrapper extends React.Component { + render() { + return ( + + + + ); + } +}; +``` + +
    diff --git a/curriculum/challenges/03-front-end-libraries/react-and-redux/Extract State Logic to Redux.md b/curriculum/challenges/03-front-end-libraries/react-and-redux/Extract State Logic to Redux.md new file mode 100644 index 0000000000..816068bcf0 --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/react-and-redux/Extract State Logic to Redux.md @@ -0,0 +1,85 @@ +--- +id: 5a24c314108439a4d4036143 +title: Extract State Logic to Redux +challengeType: 6 +isRequired: false +--- + +## Description +
    +Now that you finished the React component, you need to move the logic it's performing locally in its state into Redux. This is the first step to connect the simple React app to Redux. The only functionality your app has is to add new messages from the user to an unordered list. The example is simple in order to demonstrate how React and Redux work together. +
    + +## Instructions +
    +First, define an action type 'ADD' and set it to a const ADD. Next, define an action creator addMessage() which creates the action to add a message. You'll need to pass a message to this action creator and include the message in the returned action. +Then create a reducer called messageReducer() that handles the state for the messages. The initial state should equal an empty array. This reducer should add a message to the array of messages held in state, or return the current state. Finally, create your Redux store and pass it the reducer. +
    + +## Tests +
    + +```yml +- text: The const ADD should exist and hold a value equal to the string ADD + testString: 'assert(ADD === "ADD", "The const ADD should exist and hold a value equal to the string ADD");' +- text: The action creator addMessage should return an object with type equal to ADD and message equal to the message that is passed in. + testString: 'assert((function() { const addAction = addMessage("__TEST__MESSAGE__"); return addAction.type === ADD && addAction.message === "__TEST__MESSAGE__"; })(), "The action creator addMessage should return an object with type equal to ADD and message equal to the message that is passed in.");' +- text: messageReducer should be a function. + testString: 'assert(typeof messageReducer === "function", "messageReducer should be a function.");' +- text: The store should exist and have an initial state set to an empty array. + testString: 'assert((function() { const initialState = store.getState(); return typeof store === "object" && initialState.length === 0; })(), "The store should exist and have an initial state set to an empty array.");' +- text: Dispatching addMessage against the store should immutably add a new message to the array of messages held in state. + testString: 'assert((function() { const initialState = store.getState(); const isFrozen = DeepFreeze(initialState); store.dispatch(addMessage("__A__TEST__MESSAGE")); const addState = store.getState(); return (isFrozen && addState[0] === "__A__TEST__MESSAGE"); })(), "Dispatching addMessage against the store should immutably add a new message to the array of messages held in state.");' +- text: The messageReducer should return the current state if called with any other actions. + testString: 'assert((function() { const addState = store.getState(); store.dispatch({type: "FAKE_ACTION"}); const testState = store.getState(); return (addState === testState); })(), "The messageReducer should return the current state if called with any other actions.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```jsx +// define ADD, addMessage(), messageReducer(), and store here: + +``` + +
    + + + +
    + +## Solution +
    + + +```js +const ADD = 'ADD'; + +const addMessage = (message) => { + return { + type: ADD, + message + } +}; + +const messageReducer = (state = [], action) => { + switch (action.type) { + case ADD: + return [ + ...state, + action.message + ]; + default: + return state; + } +}; + +const store = Redux.createStore(messageReducer); +``` + +
    diff --git a/curriculum/challenges/03-front-end-libraries/react-and-redux/Getting Started with React Redux.md b/curriculum/challenges/03-front-end-libraries/react-and-redux/Getting Started with React Redux.md new file mode 100644 index 0000000000..bb2920224f --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/react-and-redux/Getting Started with React Redux.md @@ -0,0 +1,84 @@ +--- +id: 5a24c314108439a4d4036141 +title: Getting Started with React Redux +challengeType: 6 +isRequired: false +--- + +## Description +
    +This series of challenges introduces how to use Redux with React. First, here's a review of some of the key principles of each technology. React is a view library that you provide with data, then it renders the view in an efficient, predictable way. Redux is a state management framework that you can use to simplify the management of your application's state. Typically, in a React Redux app, you create a single Redux store that manages the state of your entire app. Your React components subscribe to only the pieces of data in the store that are relevant to their role. Then, you dispatch actions directly from React components, which then trigger store updates. +Although React components can manage their own state locally, when you have a complex app, it's generally better to keep the app state in a single location with Redux. There are exceptions when individual components may have local state specific only to them. Finally, because Redux is not designed to work with React out of the box, you need to use the react-redux package. It provides a way for you to pass Redux state and dispatch to your React components as props. +Over the next few challenges, first, you'll create a simple React component which allows you to input new text messages. These are added to an array that's displayed in the view. This should be a nice review of what you learned in the React lessons. Next, you'll create a Redux store and actions that manage the state of the messages array. Finally, you'll use react-redux to connect the Redux store with your component, thereby extracting the local state into the Redux store. +
    + +## Instructions +
    +Start with a DisplayMessages component. Add a constructor to this component and initialize it with a state that has two properties: input, that's set to an empty string, and messages, that's set to an empty array. +
    + +## Tests +
    + +```yml +- text: The DisplayMessages component should render an empty div element. + testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(DisplayMessages)); return mockedComponent.find("div").text() === "" })(), "The DisplayMessages component should render an empty div element.");' +- text: 'The DisplayMessages constructor should be called properly with super, passing in props.' + testString: 'getUserInput => assert((function() { const noWhiteSpace = getUserInput("index").replace(/\s/g,""); return noWhiteSpace.includes("constructor(props)") && noWhiteSpace.includes("super(props"); })(), "The DisplayMessages constructor should be called properly with super, passing in props.");' +- text: 'The DisplayMessages component should have an initial state equal to {input: "", messages: []}.' + testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(DisplayMessages)); const initialState = mockedComponent.state(); return typeof initialState === "object" && initialState.input === "" && Array.isArray(initialState.messages) && initialState.messages.length === 0; })(), "The DisplayMessages component should have an initial state equal to {input: "", messages: []}.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```jsx +class DisplayMessages extends React.Component { + // change code below this line + + // change code above this line + render() { + return
    + } +}; +``` + +
    + + +### After Test +
    + +```js +console.info('after the test'); +``` + +
    + +
    + +## Solution +
    + + +```js +class DisplayMessages extends React.Component { + constructor(props) { + super(props); + this.state = { + input: ", + messages: [] + } + } + render() { + return
    + } +}; +``` + +
    diff --git a/curriculum/challenges/03-front-end-libraries/react-and-redux/Manage State Locally First.md b/curriculum/challenges/03-front-end-libraries/react-and-redux/Manage State Locally First.md new file mode 100644 index 0000000000..8fd2de3992 --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/react-and-redux/Manage State Locally First.md @@ -0,0 +1,133 @@ +--- +id: 5a24c314108439a4d4036142 +title: Manage State Locally First +challengeType: 6 +isRequired: false +--- + +## Description +
    +Here you'll finish creating the DisplayMessages component. +
    + +## Instructions +
    +First, in the render() method, have the component render an input element, button element, and ul element. When the input element changes, it should trigger a handleChange() method. Also, the input element should render the value of input that's in the component's state. The button element should trigger a submitMessage() method when it's clicked. +Second, write these two methods. The handleChange() method should update the input with what the user is typing. The submitMessage() method should concatenate the current message (stored in input) to the messages array in local state, and clear the value of the input. +Finally, use the ul to map over the array of messages and render it to the screen as a list of li elements. +
    + +## Tests +
    + +```yml +- text: 'The DisplayMessages component should initialize with a state equal to { input: "", messages: [] }.' + testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(DisplayMessages)); const initialState = mockedComponent.state(); return ( typeof initialState === "object" && initialState.input === "" && initialState.messages.length === 0); })(), "The DisplayMessages component should initialize with a state equal to { input: "", messages: [] }.");' +- text: 'The DisplayMessages component should render a div containing an h2 element, a button element, a ul element, and li elements as children.' + testString: 'async () => { const mockedComponent = Enzyme.mount(React.createElement(DisplayMessages)); const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 100)); const state = () => { mockedComponent.setState({messages: ["__TEST__MESSAGE"]}); return waitForIt(() => mockedComponent )}; const updated = await state(); assert(updated.find("div").length === 1 && updated.find("h2").length === 1 && updated.find("button").length === 1 && updated.find("ul").length === 1, "The DisplayMessages component should render a div containing an h2 element, a button element, a ul element, and li elements as children."); }; ' +- text: The input element should render the value of input in local state. + testString: 'async () => { const mockedComponent = Enzyme.mount(React.createElement(DisplayMessages)); const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 100)); const causeChange = (c, v) => c.find("input").simulate("change", { target: { value: v }}); const testValue = "__TEST__EVENT__INPUT"; const changed = () => { causeChange(mockedComponent, testValue); return waitForIt(() => mockedComponent )}; const updated = await changed(); assert(updated.find("input").props().value === testValue, "The input element should render the value of input in local state."); }; ' +- text: Calling the method handleChange should update the input value in state to the current input. + testString: 'async () => { const mockedComponent = Enzyme.mount(React.createElement(DisplayMessages)); const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 100)); const causeChange = (c, v) => c.find("input").simulate("change", { target: { value: v }}); const initialState = mockedComponent.state(); const testMessage = "__TEST__EVENT__MESSAGE__"; const changed = () => { causeChange(mockedComponent, testMessage); return waitForIt(() => mockedComponent )}; const afterInput = await changed(); assert(initialState.input === "" && afterInput.state().input === "__TEST__EVENT__MESSAGE__", "Calling the method handleChange should update the input value in state to the current input."); }; ' +- text: Clicking the Add message button should call the method submitMessage which should add the current input to the messages array in state. + testString: 'async () => { const mockedComponent = Enzyme.mount(React.createElement(DisplayMessages)); const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 100)); const causeChange = (c, v) => c.find("input").simulate("change", { target: { value: v }}); const initialState = mockedComponent.state(); const testMessage_1 = "__FIRST__MESSAGE__"; const firstChange = () => { causeChange(mockedComponent, testMessage_1); return waitForIt(() => mockedComponent )}; const firstResult = await firstChange(); const firstSubmit = () => { mockedComponent.find("button").simulate("click"); return waitForIt(() => mockedComponent )}; const afterSubmit_1 = await firstSubmit(); const submitState_1 = afterSubmit_1.state(); const testMessage_2 = "__SECOND__MESSAGE__"; const secondChange = () => { causeChange(mockedComponent, testMessage_2); return waitForIt(() => mockedComponent )}; const secondResult = await secondChange(); const secondSubmit = () => { mockedComponent.find("button").simulate("click"); return waitForIt(() => mockedComponent )}; const afterSubmit_2 = await secondSubmit(); const submitState_2 = afterSubmit_2.state(); assert(initialState.messages.length === 0 && submitState_1.messages.length === 1 && submitState_2.messages.length === 2 && submitState_2.messages[1] === testMessage_2, "Clicking the Add message button should call the method submitMessage which should add the current input to the messages array in state."); }; ' +- text: The submitMessage method should clear the current input. + testString: 'async () => { const mockedComponent = Enzyme.mount(React.createElement(DisplayMessages)); const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 100)); const causeChange = (c, v) => c.find("input").simulate("change", { target: { value: v }}); const initialState = mockedComponent.state(); const testMessage = "__FIRST__MESSAGE__"; const firstChange = () => { causeChange(mockedComponent, testMessage); return waitForIt(() => mockedComponent )}; const firstResult = await firstChange(); const firstState = firstResult.state(); const firstSubmit = () => { mockedComponent.find("button").simulate("click"); return waitForIt(() => mockedComponent )}; const afterSubmit = await firstSubmit(); const submitState = afterSubmit.state(); assert(firstState.input === testMessage && submitState.input === "", "The submitMessage method should clear the current input."); }; ' + +``` + +
    + +## Challenge Seed +
    + +
    + +```jsx +class DisplayMessages extends React.Component { + constructor(props) { + super(props); + this.state = { + input: ", + messages: [] + } + } + // add handleChange() and submitMessage() methods here + + render() { + return ( +
    +

    Type in a new Message:

    + { /* render an input, button, and ul here */ } + + { /* change code above this line */ } +
    + ); + } +}; +``` + +
    + + +### After Test +
    + +```js +console.info('after the test'); +``` + +
    + +
    + +## Solution +
    + + +```js +class DisplayMessages extends React.Component { + constructor(props) { + super(props); + this.state = { + input: ", + messages: [] + } + this.handleChange = this.handleChange.bind(this); + this.submitMessage = this.submitMessage.bind(this); + } + handleChange(event) { + this.setState({ + input: event.target.value + }); + } + submitMessage() { + const currentMessage = this.state.input; + this.setState({ + input: ", + messages: this.state.messages.concat(currentMessage) + }); + } + render() { + return ( +
    +

    Type in a new Message:

    +
    + +
      + {this.state.messages.map( (message, idx) => { + return ( +
    • {message}
    • + ) + }) + } +
    +
    + ); + } +}; +``` + +
    diff --git a/curriculum/challenges/03-front-end-libraries/react-and-redux/Map Dispatch to Props.md b/curriculum/challenges/03-front-end-libraries/react-and-redux/Map Dispatch to Props.md new file mode 100644 index 0000000000..0f7c8c8457 --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/react-and-redux/Map Dispatch to Props.md @@ -0,0 +1,83 @@ +--- +id: 5a24c314108439a4d4036146 +title: Map Dispatch to Props +challengeType: 6 +isRequired: false +--- + +## Description +
    +The mapDispatchToProps() function is used to provide specific action creators to your React components so they can dispatch actions against the Redux store. It's similar in structure to the mapStateToProps() function you wrote in the last challenge. It returns an object that maps dispatch actions to property names, which become component props. However, instead of returning a piece of state, each property returns a function that calls dispatch with an action creator and any relevant action data. You have access to this dispatch because it's passed in to mapDispatchToProps() as a parameter when you define the function, just like you passed state to mapStateToProps(). Behind the scenes, React Redux is using Redux's store.dispatch() to conduct these dispatches with mapDispatchToProps(). This is similar to how it uses store.subscribe() for components that are mapped to state. +For example, you have a loginUser() action creator that takes a username as an action payload. The object returned from mapDispatchToProps() for this action creator would look something like: +
    {
      submitLoginUser: function(username) {
        dispatch(loginUser(username));
      }
    }
    +
    + +## Instructions +
    +The code editor provides an action creator called addMessage(). Write the function mapDispatchToProps() that takes dispatch as an argument, then returns an object. The object should have a property submitNewMessage set to the dispatch function, which takes a parameter for the new message to add when it dispatches addMessage(). +
    + +## Tests +
    + +```yml +- text: addMessage should return an object with keys type and message. + testString: 'assert((function() { const addMessageTest = addMessage(); return ( addMessageTest.hasOwnProperty("type") && addMessageTest.hasOwnProperty("message")); })(), "addMessage should return an object with keys type and message.");' +- text: mapDispatchToProps should be a function. + testString: 'assert(typeof mapDispatchToProps === "function", "mapDispatchToProps should be a function.");' +- text: mapDispatchToProps should return an object. + testString: 'assert(typeof mapDispatchToProps() === "object", "mapDispatchToProps should return an object.");' +- text: Dispatching addMessage with submitNewMessage from mapDispatchToProps should return a message to the dispatch function. + testString: 'assert((function() { let testAction; const dispatch = (fn) => { testAction = fn; }; let dispatchFn = mapDispatchToProps(dispatch); dispatchFn.submitNewMessage("__TEST__MESSAGE__"); return (testAction.type === "ADD" && testAction.message === "__TEST__MESSAGE__"); })(), "Dispatching addMessage with submitNewMessage from mapDispatchToProps should return a message to the dispatch function.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```jsx +const addMessage = (message) => { + return { + type: 'ADD', + message: message + } +}; + +// change code below this line + +``` + +
    + + + +
    + +## Solution +
    + + +```js +const addMessage = (message) => { + return { + type: 'ADD', + message: message + } +}; + +// change code below this line + +const mapDispatchToProps = (dispatch) => { + return { + submitNewMessage: function(message) { + dispatch(addMessage(message)); + } + } +}; +``` + +
    diff --git a/curriculum/challenges/03-front-end-libraries/react-and-redux/Map State to Props.md b/curriculum/challenges/03-front-end-libraries/react-and-redux/Map State to Props.md new file mode 100644 index 0000000000..cfb6355443 --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/react-and-redux/Map State to Props.md @@ -0,0 +1,71 @@ +--- +id: 5a24c314108439a4d4036145 +title: Map State to Props +challengeType: 6 +isRequired: false +--- + +## Description +
    +The Provider component allows you to provide state and dispatch to your React components, but you must specify exactly what state and actions you want. This way, you make sure that each component only has access to the state it needs. You accomplish this by creating two functions: mapStateToProps() and mapDispatchToProps(). +In these functions, you declare what pieces of state you want to have access to and which action creators you need to be able to dispatch. Once these functions are in place, you'll see how to use the React Redux connect method to connect them to your components in another challenge. +Note: Behind the scenes, React Redux uses the store.subscribe() method to implement mapStateToProps(). +
    + +## Instructions +
    +Create a function mapStateToProps(). This function should take state as an argument, then return an object which maps that state to specific property names. These properties will become accessible to your component via props. Since this example keeps the entire state of the app in a single array, you can pass that entire state to your component. Create a property messages in the object that's being returned, and set it to state. +
    + +## Tests +
    + +```yml +- text: The const state should be an empty array. + testString: 'assert(Array.isArray(state) && state.length === 0, "The const state should be an empty array.");' +- text: mapStateToProps should be a function. + testString: 'assert(typeof mapStateToProps === "function", "mapStateToProps should be a function.");' +- text: mapStateToProps should return an object. + testString: 'assert(typeof mapStateToProps() === "object", "mapStateToProps should return an object.");' +- text: Passing an array as state to mapStateToProps should return this array assigned to a key of messages. + testString: 'assert(mapStateToProps(["messages"]).messages.pop() === "messages", "Passing an array as state to mapStateToProps should return this array assigned to a key of messages.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```jsx +const state = []; + +// change code below this line + +``` + +
    + + + +
    + +## Solution +
    + + +```js +const state = []; + +// change code below this line + +const mapStateToProps = (state) => { + return { + messages: state + } +}; +``` + +
    diff --git a/curriculum/challenges/03-front-end-libraries/react-and-redux/Moving Forward From Here.md b/curriculum/challenges/03-front-end-libraries/react-and-redux/Moving Forward From Here.md new file mode 100644 index 0000000000..1142f920b9 --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/react-and-redux/Moving Forward From Here.md @@ -0,0 +1,77 @@ +--- +id: 5a24c314108439a4d403614a +title: Moving Forward From Here +challengeType: 6 +isRequired: false +--- + +## Description +
    +Congratulations! You finished the lessons on React and Redux. There's one last item worth pointing out before you move on. Typically, you won't write React apps in a code editor like this. This challenge gives you a glimpse of what the syntax looks like if you're working with npm and a file system on your own machine. The code should look similar, except for the use of import statements (these pull in all of the dependencies that have been provided for you in the challenges). The "Managing Packages with npm" section covers npm in more detail. +Finally, writing React and Redux code generally requires some configuration. This can get complicated quickly. If you are interested in experimenting on your own machine, the +Create React App comes configured and ready to go. +Alternatively, you can enable Babel as a JavaScript Preprocessor in CodePen, add React and ReactDOM as external JavaScript resources, and work there as well. +
    + +## Instructions +
    +Log the message 'Now I know React and Redux!' to the console. +
    + +## Tests +
    + +```yml +- text: The message Now I know React and Redux! should be logged to the console. + testString: 'assert(editor.getValue().includes("console.log("Now I know React and Redux!")") || editor.getValue().includes("console.log(\"Now I know React and Redux!\")"), "The message Now I know React and Redux! should be logged to the console.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```jsx +// import React from 'react' +// import ReactDOM from 'react-dom' +// import { Provider, connect } from 'react-redux' +// import { createStore, combineReducers, applyMiddleware } from 'redux' +// import thunk from 'redux-thunk' + +// import rootReducer from './redux/reducers' +// import App from './components/App' + +// const store = createStore( +// rootReducer, +// applyMiddleware(thunk) +// ); + +// ReactDOM.render( +// +// +// , +// document.getElementById('root') +// ); + +// change code below this line + +``` + +
    + + + +
    + +## Solution +
    + + +```js +console.log('Now I know React and Redux!'); +``` + +
    diff --git a/curriculum/challenges/03-front-end-libraries/react-and-redux/Use Provider to Connect Redux to React.md b/curriculum/challenges/03-front-end-libraries/react-and-redux/Use Provider to Connect Redux to React.md new file mode 100644 index 0000000000..9c0a4618c3 --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/react-and-redux/Use Provider to Connect Redux to React.md @@ -0,0 +1,227 @@ +--- +id: 5a24c314108439a4d4036144 +title: Use Provider to Connect Redux to React +challengeType: 6 +isRequired: false +--- + +## Description +
    +In the last challenge, you created a Redux store to handle the messages array and created an action for adding new messages. The next step is to provide React access to the Redux store and the actions it needs to dispatch updates. React Redux provides its react-redux package to help accomplish these tasks. +React Redux provides a small API with two key features: Provider and connect. Another challenge covers connect. The Provider is a wrapper component from React Redux that wraps your React app. This wrapper then allows you to access the Redux store and dispatch functions throughout your component tree. Provider takes two props, the Redux store and the child components of your app. Defining the Provider for an App component might look like this: +
    <Provider store={store}>
      <App/>
    </Provider>
    +
    + +## Instructions +
    +The code editor now shows all your Redux and React code from the past several challenges. It includes the Redux store, actions, and the DisplayMessages component. The only new piece is the AppWrapper component at the bottom. Use this top level component to render the Provider from ReactRedux, and pass the Redux store as a prop. Then render the DisplayMessages component as a child. Once you are finished, you should see your React component rendered to the page. +Note: React Redux is available as a global variable here, so you can access the Provider with dot notation. The code in the editor takes advantage of this and sets it to a constant Provider for you to use in the AppWrapper render method. +
    + +## Tests +
    + +```yml +- text: The AppWrapper should render. + testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(AppWrapper)); return mockedComponent.find("AppWrapper").length === 1; })(), "The AppWrapper should render.");' +- text: 'The Provider wrapper component should have a prop of store passed to it, equal to the Redux store.' + testString: 'getUserInput => assert((function() { const mockedComponent = Enzyme.mount(React.createElement(AppWrapper)); return getUserInput("index").replace(/\s/g,"").includes(""); })(), "The Provider wrapper component should have a prop of store passed to it, equal to the Redux store.");' +- text: DisplayMessages should render as a child of AppWrapper. + testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(AppWrapper)); return mockedComponent.find("AppWrapper").find("DisplayMessages").length === 1; })(), "DisplayMessages should render as a child of AppWrapper.");' +- text: 'The DisplayMessages component should render an h2, input, button, and ul element.' + testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(AppWrapper)); return mockedComponent.find("div").length === 1 && mockedComponent.find("h2").length === 1 && mockedComponent.find("button").length === 1 && mockedComponent.find("ul").length === 1; })(), "The DisplayMessages component should render an h2, input, button, and ul element.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```jsx +// Redux Code: +const ADD = 'ADD'; + +const addMessage = (message) => { + return { + type: ADD, + message + } +}; + +const messageReducer = (state = [], action) => { + switch (action.type) { + case ADD: + return [ + ...state, + action.message + ]; + default: + return state; + } +}; + + + +const store = Redux.createStore(messageReducer); + +// React Code: + +class DisplayMessages extends React.Component { + constructor(props) { + super(props); + this.state = { + input: ", + messages: [] + } + this.handleChange = this.handleChange.bind(this); + this.submitMessage = this.submitMessage.bind(this); + } + handleChange(event) { + this.setState({ + input: event.target.value + }); + } + submitMessage() { + const currentMessage = this.state.input; + this.setState({ + input: ", + messages: this.state.messages.concat(currentMessage) + }); + } + render() { + return ( +
    +

    Type in a new Message:

    +
    + +
      + {this.state.messages.map( (message, idx) => { + return ( +
    • {message}
    • + ) + }) + } +
    +
    + ); + } +}; + +const Provider = ReactRedux.Provider; + +class AppWrapper extends React.Component { + // render the Provider here + + // change code above this line +}; +``` + +
    + + +### After Test +
    + +```js +console.info('after the test'); +``` + +
    + +
    + +## Solution +
    + + +```js +// Redux Code: +const ADD = 'ADD'; + +const addMessage = (message) => { + return { + type: ADD, + message + } +}; + +const messageReducer = (state = [], action) => { + switch (action.type) { + case ADD: + return [ + ...state, + action.message + ]; + default: + return state; + } +}; + +const store = Redux.createStore(messageReducer); + +// React Code: + +class DisplayMessages extends React.Component { + constructor(props) { + super(props); + this.state = { + input: ", + messages: [] + } + this.handleChange = this.handleChange.bind(this); + this.submitMessage = this.submitMessage.bind(this); + } + handleChange(event) { + this.setState({ + input: event.target.value + }); + } + submitMessage() { + const currentMessage = this.state.input; + this.setState({ + input: ", + messages: this.state.messages.concat(currentMessage) + }); + } + render() { + return ( +
    +

    Type in a new Message:

    +
    + +
      + {this.state.messages.map( (message, idx) => { + return ( +
    • {message}
    • + ) + }) + } +
    +
    + ); + } +}; + +const Provider = ReactRedux.Provider; + +class AppWrapper extends React.Component { + // change code below this line + render() { + return ( + + + + ); + } + // change code above this line +}; +``` + +
    diff --git a/curriculum/challenges/03-front-end-libraries/react-and-redux/meta.json b/curriculum/challenges/03-front-end-libraries/react-and-redux/meta.json new file mode 100644 index 0000000000..37c047f482 --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/react-and-redux/meta.json @@ -0,0 +1,8 @@ +{ + "name": "React and Redux", + "dashedName": "react-and-redux", + "order": 7, + "time": "5 hours", + "superBlock": "front-end-libraries", + "superOrder": 3 +} \ No newline at end of file diff --git a/curriculum/challenges/03-front-end-libraries/react.json b/curriculum/challenges/03-front-end-libraries/react.json index 33ae46eda9..6b27194bdc 100644 --- a/curriculum/challenges/03-front-end-libraries/react.json +++ b/curriculum/challenges/03-front-end-libraries/react.json @@ -3165,7 +3165,7 @@ }, { "id": "5a24c314108439a4d4036184", - "title": "Render with an If/Else Condition", + "title": "Render with an If-Else Condition", "releasedOn": "December 25, 2017", "description": [ "Another application of using JavaScript to control your rendered view is to tie the elements that are rendered to a condition. When the condition is true, one view renders. When it's false, it's a different view. You can do this with a standard if/else statement in the render() method of a React component.", diff --git a/curriculum/challenges/03-front-end-libraries/react/Access Props Using this.props.md b/curriculum/challenges/03-front-end-libraries/react/Access Props Using this.props.md new file mode 100644 index 0000000000..b7b6a8c0cc --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/react/Access Props Using this.props.md @@ -0,0 +1,133 @@ +--- +id: 5a24c314108439a4d403616e +title: Access Props Using this.props +challengeType: 6 +isRequired: false +--- + +## Description +
    +The last several challenges covered the basic ways to pass props to child components. But what if the child component that you're passing a prop to is an ES6 class component, rather than a stateless functional component? The ES6 class component uses a slightly different convention to access props. +Anytime you refer to a class component within itself, you use the this keyword. To access props within a class component, you preface the code that you use to access it with this. For example, if an ES6 class component has a prop called data, you write {this.props.data} in JSX. +
    + +## Instructions +
    +Render an instance of the ReturnTempPassword component in the parent component ResetPassword. Here, give ReturnTempPassword a prop of tempPassword and assign it a value of a string that is at least 8 characters long. Within the child, ReturnTempPassword, access the tempPassword prop within the strong tags to make sure the user sees the temporary password. +
    + +## Tests +
    + +```yml +- text: The ResetPassword component should return a single div element. + testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(ResetPassword)); return mockedComponent.children().type() === "div"; })(), "The ResetPassword component should return a single div element.");' +- text: The fourth child of ResetPassword should be the ReturnTempPassword component. + testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(ResetPassword)); return mockedComponent.children().childAt(3).name() === "ReturnTempPassword"; })(), "The fourth child of ResetPassword should be the ReturnTempPassword component.");' +- text: The ReturnTempPassword component should have a prop called tempPassword. + testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(ResetPassword)); return mockedComponent.find("ReturnTempPassword").props().tempPassword; })(), "The ReturnTempPassword component should have a prop called tempPassword.");' +- text: The tempPassword prop of ReturnTempPassword should be equal to a string of at least 8 characters. + testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(ResetPassword)); const temp = mockedComponent.find("ReturnTempPassword").props().tempPassword; return typeof temp === "string" && temp.length >= 8; })(), "The tempPassword prop of ReturnTempPassword should be equal to a string of at least 8 characters.");' +- text: The ReturnTempPassword component should display the password you create as the tempPassword prop within strong tags. + testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(ResetPassword)); return mockedComponent.find("strong").text() === mockedComponent.find("ReturnTempPassword").props().tempPassword; })(), "The ReturnTempPassword component should display the password you create as the tempPassword prop within strong tags.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```jsx +class ReturnTempPassword extends React.Component { + constructor(props) { + super(props); + + } + render() { + return ( +
    + { /* change code below this line */ } +

    Your temporary password is:

    + { /* change code above this line */ } +
    + ); + } +}; + +class ResetPassword extends React.Component { + constructor(props) { + super(props); + + } + render() { + return ( +
    +

    Reset Password

    +

    We've generated a new temporary password for you.

    +

    Please reset this password from your account settings ASAP.

    + { /* change code below this line */ } + + { /* change code above this line */ } +
    + ); + } +}; +``` + +
    + + +### After Test +
    + +```js +console.info('after the test'); +``` + +
    + +
    + +## Solution +
    + + +```js +class ReturnTempPassword extends React.Component { + constructor(props) { + super(props); + + } + render() { + return ( +
    +

    Your temporary password is: {this.props.tempPassword}

    +
    + ); + } +}; + +class ResetPassword extends React.Component { + constructor(props) { + super(props); + + } + render() { + return ( +
    +

    Reset Password

    +

    We've generated a new temporary password for you.

    +

    Please reset this password from your account settings ASAP.

    + { /* change code below this line */ } + + { /* change code above this line */ } +
    + ); + } +}; +``` + +
    diff --git a/curriculum/challenges/03-front-end-libraries/react/Add Comments in JSX.md b/curriculum/challenges/03-front-end-libraries/react/Add Comments in JSX.md new file mode 100644 index 0000000000..139947b445 --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/react/Add Comments in JSX.md @@ -0,0 +1,77 @@ +--- +id: 5a24bbe0dba28a8d3cbd4c5e +title: Add Comments in JSX +challengeType: 6 +isRequired: false +--- + +## Description +
    +JSX is a syntax that gets compiled into valid JavaScript. Sometimes, for readability, you might need to add comments to your code. Like most programming languages, JSX has its own way to do this. +To put comments inside JSX, you use the syntax {/* */} to wrap around the comment text. +
    + +## Instructions +
    +The code editor has a JSX element similar to what you created in the last challenge. Add a comment somewhere within the provided div element, without modifying the existing h1 or p elements. +
    + +## Tests +
    + +```yml +- text: The constant JSX should return a div element. + testString: 'assert(JSX.type === "div", "The constant JSX should return a div element.");' +- text: The div should contain an h1 tag as the first element. + testString: 'assert(JSX.props.children[0].type === "h1", "The div should contain an h1 tag as the first element.");' +- text: The div should contain a p tag as the second element. + testString: 'assert(JSX.props.children[1].type === "p", "The div should contain a p tag as the second element.");' +- text: The JSX should include a comment. + testString: 'getUserInput => assert(getUserInput("index").includes("/*") && getUserInput("index").includes("*/"), "The JSX should include a comment.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```jsx +const JSX = ( +
    +

    This is a block of JSX

    +

    Here's a subtitle

    +
    +); +``` + +
    + + +### After Test +
    + +```js +console.info('after the test'); +``` + +
    + +
    + +## Solution +
    + + +```js +const JSX = ( +
    +

    This is a block of JSX

    + { /* this is a JSX comment */ } +

    Here's a subtitle

    +
    ); +``` + +
    diff --git a/curriculum/challenges/03-front-end-libraries/react/Add Event Listeners.md b/curriculum/challenges/03-front-end-libraries/react/Add Event Listeners.md new file mode 100644 index 0000000000..27d0a03d45 --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/react/Add Event Listeners.md @@ -0,0 +1,137 @@ +--- +id: 5a24c314108439a4d403617e +title: Add Event Listeners +challengeType: 6 +isRequired: false +--- + +## Description +
    +The componentDidMount() method is also the best place to attach any event listeners you need to add for specific functionality. React provides a synthetic event system which wraps the native event system present in browsers. This means that the synthetic event system behaves exactly the same regardless of the user's browser - even if the native events may behave differently between different browsers. +You've already been using some of these synthetic event handlers such as onClick(). React's synthetic event system is great to use for most interactions you'll manage on DOM elements. However, if you want to attach an event handler to the document or window objects, you have to do this directly. +
    + +## Instructions +
    +Attach an event listener in the componentDidMount() method for keydown events and have these events trigger the callback handleKeyPress(). You can use document.addEventListener() which takes the event (in quotes) as the first argument and the callback as the second argument. +Then, in componentWillUnmount(), remove this same event listener. You can pass the same arguments to document.removeEventListener(). It's good practice to use this lifecycle method to do any clean up on React components before they are unmounted and destroyed. Removing event listeners is an example of one such clean up action. +
    + +## Tests +
    + +```yml +- text: MyComponent should render a div element which wraps an h1 tag. + testString: 'assert((() => { const mockedComponent = Enzyme.mount(React.createElement(MyComponent)); return mockedComponent.find("div").children().find("h1").length === 1; })(), "MyComponent should render a div element which wraps an h1 tag.");' +- text: A keydown listener should be attached to the document in componentDidMount. + testString: 'assert((() => { const mockedComponent = Enzyme.mount(React.createElement(MyComponent)); const didMountString = mockedComponent.instance().componentDidMount.toString(); return new RegExp("document\.addEventListener(.|\n|\r)+keydown(.|\n|\r)+this\.handleKeyPress").test(didMountString); })(), "A keydown listener should be attached to the document in componentDidMount.");' +- text: The keydown listener should be removed from the document in componentWillUnmount. + testString: 'assert((() => { const mockedComponent = Enzyme.mount(React.createElement(MyComponent)); const willUnmountString = mockedComponent.instance().componentWillUnmount.toString(); return new RegExp("document\.removeEventListener(.|\n|\r)+keydown(.|\n|\r)+this\.handleKeyPress").test(willUnmountString); })(), "The keydown listener should be removed from the document in componentWillUnmount.");' +- text: 'Once the component has mounted, pressing enter should update its state and the rendered h1 tag.' + testString: 'async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(MyComponent)); const beforeState = mockedComponent.state("message"); const beforeText = mockedComponent.find("h1").text(); const pressEnterKey = () => { mockedComponent.instance().handleKeyPress({ keyCode: 13 }); return waitForIt(() => { mockedComponent.update(); return { state: mockedComponent.state("message"), text: mockedComponent.find("h1").text()}; });}; const afterKeyPress = await pressEnterKey(); assert(beforeState !== afterKeyPress.state && beforeText !== afterKeyPress.text, "Once the component has mounted, pressing enter should update its state and the rendered h1 tag."); }; ' + +``` + +
    + +## Challenge Seed +
    + +
    + +```jsx +class MyComponent extends React.Component { + constructor(props) { + super(props); + this.state = { + message: " + }; + this.handleEnter = this.handleEnter.bind(this); + this.handleKeyPress = this.handleKeyPress.bind(this); + } + // change code below this line + componentDidMount() { + + } + componentWillUnmount() { + + } + // change code above this line + handleEnter() { + this.setState({ + message: this.state.message + 'You pressed the enter key! ' + }); + } + handleKeyPress(event) { + if (event.keyCode === 13) { + this.handleEnter(); + } + } + render() { + return ( +
    +

    {this.state.message}

    +
    + ); + } +}; +``` + +
    + + +### After Test +
    + +```js +console.info('after the test'); +``` + +
    + +
    + +## Solution +
    + + +```js +class MyComponent extends React.Component { + constructor(props) { + super(props); + this.state = { + message: " + }; + this.handleKeyPress = this.handleKeyPress.bind(this); + this.handleEnter = this.handleEnter.bind(this); } + componentDidMount() { + // change code below this line + document.addEventListener('keydown', this.handleKeyPress); + // change code above this line + } + componentWillUnmount() { + // change code below this line + document.removeEventListener('keydown', this.handleKeyPress); + // change code above this line + } + handleEnter() { + this.setState({ + message: this.state.message + 'You pressed the enter key! ' + }); + } + handleKeyPress(event) { + if (event.keyCode === 13) { + this.handleEnter(); + } + } + render() { + return ( +
    +

    {this.state.message}

    +
    + ); + } +}; +``` + +
    diff --git a/curriculum/challenges/03-front-end-libraries/react/Add Inline Styles in React.md b/curriculum/challenges/03-front-end-libraries/react/Add Inline Styles in React.md new file mode 100644 index 0000000000..2e625a0660 --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/react/Add Inline Styles in React.md @@ -0,0 +1,98 @@ +--- +id: 5a24c314108439a4d4036182 +title: Add Inline Styles in React +challengeType: 6 +isRequired: false +--- + +## Description +
    +You may have noticed in the last challenge that there were several other syntax differences from HTML inline styles in addition to the style attribute set to a JavaScript object. First, the names of certain CSS style properties use camel case. For example, the last challenge set the size of the font with fontSize instead of font-size. Hyphenated words like font-size are invalid syntax for JavaScript object properties, so React uses camel case. As a rule, any hyphenated style properties are written using camel case in JSX. +All property value length units (like height, width, and fontSize) are assumed to be in px unless otherwise specified. If you want to use em, for example, you wrap the value and the units in quotes, like {fontSize: "4em"}. Other than the length values that default to px, all other property values should be wrapped in quotes. +
    + +## Instructions +
    +If you have a large set of styles, you can assign a style object to a constant to keep your code organized. Uncomment the styles constant and declare an object with three style properties and their values. Give the div a color of "purple", a font-size of 40, and a border of "2px solid purple". Then set the style attribute equal to the styles constant. +
    + +## Tests +
    + +```yml +- text: The styles variable should be an object with three properties. + testString: 'assert(Object.keys(styles).length === 3, "The styles variable should be an object with three properties.");' +- text: The styles variable should have a color property set to a value of purple. + testString: 'assert(styles.color === "purple", "The styles variable should have a color property set to a value of purple.");' +- text: The styles variable should have a fontSize property set to a value of 40. + testString: 'assert(styles.fontSize === 40, "The styles variable should have a fontSize property set to a value of 40.");' +- text: The styles variable should have a border property set to a value of 2px solid purple. + testString: 'assert(styles.border === "2px solid purple", "The styles variable should have a border property set to a value of 2px solid purple.");' +- text: The component should render a div element. + testString: 'assert((function() { const mockedComponent = Enzyme.shallow(React.createElement(Colorful)); return mockedComponent.type() === "div"; })(), "The component should render a div element.");' +- text: The div element should have its styles defined by the styles object. + testString: 'assert((function() { const mockedComponent = Enzyme.shallow(React.createElement(Colorful)); return (mockedComponent.props().style.color === "purple" && mockedComponent.props().style.fontSize === 40 && mockedComponent.props().style.border === "2px solid purple"); })(), "The div element should have its styles defined by the styles object.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```jsx + +// const styles = +// change code above this line +class Colorful extends React.Component { + render() { + // change code below this line + return ( +
    Style Me!
    + ); + // change code above this line + } +}; + +``` + +
    + + +### After Test +
    + +```js +console.info('after the test'); +``` + +
    + +
    + +## Solution +
    + + +```js +const styles = { + color: "purple", + fontSize: 40, + border: "2px solid purple" +}; +// change code above this line +class Colorful extends React.Component { + render() { + // change code below this line + return ( +
    Style Me!
    + // change code above this line + ); + } +}; + +``` + +
    diff --git a/curriculum/challenges/03-front-end-libraries/react/Bind 'this' to a Class Method.md b/curriculum/challenges/03-front-end-libraries/react/Bind 'this' to a Class Method.md new file mode 100644 index 0000000000..15a7ac404d --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/react/Bind 'this' to a Class Method.md @@ -0,0 +1,114 @@ +--- +id: 5a24c314108439a4d4036174 +title: Bind 'this' to a Class Method +challengeType: 6 +isRequired: false +--- + +## Description +
    +In addition to setting and updating state, you can also define methods for your component class. A class method typically needs to use the this keyword so it can access properties on the class (such as state and props) inside the scope of the method. There are a few ways to allow your class methods to access this. +One common way is to explicitly bind this in the constructor so this becomes bound to the class methods when the component is initialized. You may have noticed the last challenge used this.handleClick = this.handleClick.bind(this) for its handleClick method in the constructor. Then, when you call a function like this.setState() within your class method, this refers to the class and will not be undefined. +Note: The this keyword is one of the most confusing aspects of JavaScript but it plays an important role in React. Although its behavior here is totally normal, these lessons aren't the place for an in-depth review of this so please refer to other lessons if the above is confusing! +
    + +## Instructions +
    +The code editor has a component with a state that keeps track of an item count. It also has a method which allows you to increment this item count. However, the method doesn't work because it's using the this keyword that is undefined. Fix it by explicitly binding this to the addItem() method in the component's constructor. +Next, add a click handler to the button element in the render method. It should trigger the addItem() method when the button receives a click event. Remember that the method you pass to the onClick handler needs curly braces because it should be interpreted directly as JavaScript. +Once you complete the above steps you should be able to click the button and see the item count increment in the HTML. +
    + +## Tests +
    + +```yml +- text: 'MyComponent should return a div element which wraps two elements, a button and an h1 element, in that order.' + testString: 'assert(Enzyme.mount(React.createElement(MyComponent)).find("div").length === 1 && Enzyme.mount(React.createElement(MyComponent)).find("div").childAt(0).type() === "button" && Enzyme.mount(React.createElement(MyComponent)).find("div").childAt(1).type() === "h1", "MyComponent should return a div element which wraps two elements, a button and an h1 element, in that order.");' +- text: 'The state of MyComponent should initialize with the key value pair { itemCount: 0 }.' + testString: 'assert(Enzyme.mount(React.createElement(MyComponent)).state("itemCount") === 0, "The state of MyComponent should initialize with the key value pair { itemCount: 0 }.");' +- text: Clicking the button element should run the addItem method and increment the state itemCount by 1. + testString: 'async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(MyComponent)); const first = () => { mockedComponent.setState({ itemCount: 0 }); return waitForIt(() => mockedComponent.state("itemCount")); }; const second = () => { mockedComponent.find("button").simulate("click"); return waitForIt(() => mockedComponent.state("itemCount")); }; const firstValue = await first(); const secondValue = await second(); assert(firstValue === 0 && secondValue === 1, "Clicking the button element should run the addItem method and increment the state itemCount by 1."); };' + +``` + +
    + +## Challenge Seed +
    + +
    + +```jsx +class MyComponent extends React.Component { + constructor(props) { + super(props); + this.state = { + itemCount: 0 + }; + // change code below this line + + // change code above this line + } + addItem() { + this.setState({ + itemCount: this.state.itemCount + 1 + }); + } + render() { + return ( +
    + { /* change code below this line */ } + + { /* change code above this line */ } +

    Current Item Count: {this.state.itemCount}

    +
    + ); + } +}; +``` + +
    + + +### After Test +
    + +```js +console.info('after the test'); +``` + +
    + +
    + +## Solution +
    + + +```js +class MyComponent extends React.Component { + constructor(props) { + super(props); + this.state = { + itemCount: 0 + }; + this.addItem = this.addItem.bind(this); + } + addItem() { + this.setState({ + itemCount: this.state.itemCount + 1 + }); + } + render() { + return ( +
    + +

    Current Item Count: {this.state.itemCount}

    +
    + ); + } +}; +``` + +
    diff --git a/curriculum/challenges/03-front-end-libraries/react/Change Inline CSS Conditionally Based on Component State.md b/curriculum/challenges/03-front-end-libraries/react/Change Inline CSS Conditionally Based on Component State.md new file mode 100644 index 0000000000..06a44866eb --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/react/Change Inline CSS Conditionally Based on Component State.md @@ -0,0 +1,128 @@ +--- +id: 5a24c314108439a4d4036189 +title: Change Inline CSS Conditionally Based on Component State +challengeType: 6 +isRequired: false +--- + +## Description +
    +At this point, you've seen several applications of conditional rendering and the use of inline styles. Here's one more example that combines both of these topics. You can also render CSS conditionally based on the state of a React component. To do this, you check for a condition, and if that condition is met, you modify the styles object that's assigned to the JSX elements in the render method. +This paradigm is important to understand because it is a dramatic shift from the more traditional approach of applying styles by modifying DOM elements directly (which is very common with jQuery, for example). In that approach, you must keep track of when elements change and also handle the actual manipulation directly. It can become difficult to keep track of changes, potentially making your UI unpredictable. When you set a style object based on a condition, you describe how the UI should look as a function of the application's state. There is a clear flow of information that only moves in one direction. This is the preferred method when writing applications with React. +
    + +## Instructions +
    +The code editor has a simple controlled input component with a styled border. You want to style this border red if the user types more than 15 characters of text in the input box. Add a condition to check for this and, if the condition is valid, set the input border style to 3px solid red. You can try it out by entering text in the input. +
    + +## Tests +
    + +```yml +- text: The GateKeeper component should render a div element. + testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(GateKeeper)); return mockedComponent.find("div").length === 1; })(), "The GateKeeper component should render a div element.");' +- text: The GateKeeper component should be initialized with a state key input set to an empty string. + testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(GateKeeper)); return mockedComponent.state().input === ""; })(), "The GateKeeper component should be initialized with a state key input set to an empty string.");' +- text: The GateKeeper component should render an h3 tag and an input tag. + testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(GateKeeper)); return mockedComponent.find("h3").length === 1 && mockedComponent.find("input").length === 1; })(), "The GateKeeper component should render an h3 tag and an input tag.");' +- text: The input tag should initially have a style of 1px solid black for the border property. + testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(GateKeeper)); return mockedComponent.find("input").props().style.border === "1px solid black"; })(), "The input tag should initially have a style of 1px solid black for the border property.");' +- text: The input tag should be styled with a border of 3px solid red if the input value in state is longer than 15 characters. + testString: 'async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 100)); const mockedComponent = Enzyme.mount(React.createElement(GateKeeper)); const simulateChange = (el, value) => el.simulate("change", {target: {value}}); let initialStyle = mockedComponent.find("input").props().style.border; const state_1 = () => { mockedComponent.setState({input: "this is 15 char" }); return waitForIt(() => mockedComponent.find("input").props().style.border )}; const state_2 = () => { mockedComponent.setState({input: "A very long string longer than 15 characters." }); return waitForIt(() => mockedComponent.find("input").props().style.border )}; const style_1 = await state_1(); const style_2 = await state_2(); assert(initialStyle === "1px solid black" && style_1 === "1px solid black" && style_2 === "3px solid red", "The input tag should be styled with a border of 3px solid red if the input value in state is longer than 15 characters."); }; ' + +``` + +
    + +## Challenge Seed +
    + +
    + +```jsx + +class GateKeeper extends React.Component { + constructor(props) { + super(props); + this.state = { + input: " + }; + this.handleChange = this.handleChange.bind(this); + } + handleChange(event) { + this.setState({ input: event.target.value }) + } + render() { + let inputStyle = { + border: '1px solid black' + }; + // change code below this line + + // change code above this line + return ( +
    +

    Don't Type Too Much:

    + +
    + ); + } +}; +``` + +
    + + +### After Test +
    + +```js +console.info('after the test'); +``` + +
    + +
    + +## Solution +
    + + +```js +class GateKeeper extends React.Component { + constructor(props) { + super(props); + this.state = { + input: " + }; + this.handleChange = this.handleChange.bind(this); + } + handleChange(event) { + this.setState({ input: event.target.value }) + } + render() { + let inputStyle = { + border: '1px solid black' + }; + if (this.state.input.length > 15) { + inputStyle.border = '3px solid red'; + }; + return ( +
    +

    Don't Type Too Much:

    + +
    + ); + } +}; +``` + +
    diff --git a/curriculum/challenges/03-front-end-libraries/react/Compose React Components.md b/curriculum/challenges/03-front-end-libraries/react/Compose React Components.md new file mode 100644 index 0000000000..86b7a92a77 --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/react/Compose React Components.md @@ -0,0 +1,181 @@ +--- +id: 5a24c314108439a4d4036166 +title: Compose React Components +challengeType: 6 +isRequired: false +--- + +## Description +
    +As the challenges continue to use more complex compositions with React components and JSX, there is one important point to note. Rendering ES6 style class components within other components is no different than rendering the simple components you used in the last few challenges. You can render JSX elements, stateless functional components, and ES6 class components within other components. +
    + +## Instructions +
    +In the code editor, the TypesOfFood component is already rendering a component called Vegetables. Also, there is the Fruits component from the last challenge. +Nest two components inside of Fruits — first NonCitrus, and then Citrus. Both of these components are provided for you in the background. Next, nest the Fruits class component into the TypesOfFood component, below the h1 header and above Vegetables. The result should be a series of nested components, which uses two different component types. +
    + +## Tests +
    + +```yml +- text: The TypesOfFood component should return a single div element. + testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(TypesOfFood)); return mockedComponent.children().type() === "div"; })(), "The TypesOfFood component should return a single div element.");' +- text: The TypesOfFood component should return the Fruits component. + testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(TypesOfFood)); return mockedComponent.children().childAt(1).name() === "Fruits"; })(), "The TypesOfFood component should return the Fruits component.");' +- text: The Fruits component should return the NonCitrus component and the Citrus component. + testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(TypesOfFood)); return (mockedComponent.find("Fruits").children().find("NonCitrus").length === 1 && mockedComponent.find("Fruits").children().find("Citrus").length === 1); })(), "The Fruits component should return the NonCitrus component and the Citrus component.");' +- text: The TypesOfFood component should return the Vegetables component below the Fruits component. + testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(TypesOfFood)); return mockedComponent.children().childAt(2).name() === "Vegetables"; })(), "The TypesOfFood component should return the Vegetables component below the Fruits component.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```jsx +class Fruits extends React.Component { + constructor(props) { + super(props); + } + render() { + return ( +
    +

    Fruits:

    + { /* change code below this line */ } + + { /* change code above this line */ } +
    + ); + } +}; + +class TypesOfFood extends React.Component { + constructor(props) { + super(props); + } + render() { + return ( +
    +

    Types of Food:

    + { /* change code below this line */ } + + { /* change code above this line */ } + +
    + ); + } +}; +``` + +
    + +### Before Test +
    + +```jsx +class NonCitrus extends React.Component { + render() { + return ( +
    +

    Non-Citrus:

    +
      +
    • Apples
    • +
    • Blueberries
    • +
    • Strawberries
    • +
    • Bananas
    • +
    +
    + ); + } +}; +class Citrus extends React.Component { + render() { + return ( +
    +

    Citrus:

    +
      +
    • Lemon
    • +
    • Lime
    • +
    • Orange
    • +
    • Grapefruit
    • +
    +
    + ); + } +}; +class Vegetables extends React.Component { + render() { + return ( +
    +

    Vegetables:

    +
      +
    • Brussel Sprouts
    • +
    • Broccoli
    • +
    • Squash
    • +
    +
    + ); + } +}; +``` + +
    + +### After Test +
    + +```js +console.info('after the test'); +``` + +
    + +
    + +## Solution +
    + + +```js +class Fruits extends React.Component { + constructor(props) { + super(props); + } + render() { + return ( +
    +

    Fruits:

    + { /* change code below this line */ } + + + { /* change code above this line */ } +
    + ) + } +} + +class TypesOfFood extends React.Component { + constructor(props) { + super(props); + } + render() { + return ( +
    +

    Types of Food:

    + { /* change code below this line */ } + + { /* change code above this line */ } + +
    + ); + } +}; +``` + +
    diff --git a/curriculum/challenges/03-front-end-libraries/react/Create a Complex JSX Element.md b/curriculum/challenges/03-front-end-libraries/react/Create a Complex JSX Element.md new file mode 100644 index 0000000000..22cb09be5b --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/react/Create a Complex JSX Element.md @@ -0,0 +1,88 @@ +--- +id: 5a24bbe0dba28a8d3cbd4c5d +title: Create a Complex JSX Element +challengeType: 6 +isRequired: false +--- + +## Description +
    +The last challenge was a simple example of JSX, but JSX can represent more complex HTML as well. +One important thing to know about nested JSX is that it must return a single element. +This one parent element would wrap all of the other levels of nested elements. +For instance, several JSX elements written as siblings with no parent wrapper element will not transpile. +Here's an example: +Valid JSX: +
    <div>
      <p>Paragraph One</p>
      <p>Paragraph Two</p>
      <p>Paragraph Three</p>
    </div>
    +Invalid JSX: +
    <p>Paragraph One</p>
    <p>Paragraph Two</p>
    <p>Paragraph Three</p>
    +
    + +## Instructions +
    +Define a new constant JSX that renders a div which contains the following elements in order: +An h1, a p, and an unordered list that contains three li items. You can include any text you want within each element. +Note: When rendering multiple elements like this, you can wrap them all in parentheses, but it's not strictly required. Also notice this challenge uses a div tag to wrap all the child elements within a single parent element. If you remove the div, the JSX will no longer transpile. Keep this in mind, since it will also apply when you return JSX elements in React components. +
    + +## Tests +
    + +```yml +- text: The constant JSX should return a div element. + testString: 'assert(JSX.type === "div", "The constant JSX should return a div element.");' +- text: The div should contain a p tag as the second element. + testString: 'assert(JSX.props.children[1].type === "p", "The div should contain a p tag as the second element.");' +- text: The div should contain a ul tag as the third element. + testString: 'assert(JSX.props.children[2].type === "ul", "The div should contain a ul tag as the third element.");' +- text: The div should contain an h1 tag as the first element. + testString: 'assert(JSX.props.children[0].type === "h1", "The div should contain an h1 tag as the first element.");' +- text: The ul should contain three li elements. + testString: 'assert(JSX.props.children[2].props.children.length === 3, "The ul should contain three li elements.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```jsx +// write your code here + +``` + +
    + + +### After Test +
    + +```js +console.info('after the test'); +``` + +
    + +
    + +## Solution +
    + + +```js +const JSX = ( +
    +

    Hello JSX!

    +

    Some info

    +
      +
    • An item
    • +
    • Another item
    • +
    • A third item
    • +
    +
    ); +``` + +
    diff --git a/curriculum/challenges/03-front-end-libraries/react/Create a Component with Composition.md b/curriculum/challenges/03-front-end-libraries/react/Create a Component with Composition.md new file mode 100644 index 0000000000..bfe976a689 --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/react/Create a Component with Composition.md @@ -0,0 +1,113 @@ +--- +id: 5a24c314108439a4d4036164 +title: Create a Component with Composition +challengeType: 6 +isRequired: false +--- + +## Description +
    +Now we will look at how we can compose multiple React components together. Imagine you are building an App and have created three components, a Navbar, Dashboard, and Footer. +To compose these components together, you could create an App parent component which renders each of these three components as children. To render a component as a child in a React component, you include the component name written as a custom HTML tag in the JSX. For example, in the render method you could write: +
    return (
    <App>
      <Navbar />
      <Dashboard />
      <Footer />
    </App>
    )
    +When React encounters a custom HTML tag that references another component (a component name wrapped in < /> like in this example), it renders the markup for that component in the location of the tag. This should illustrate the parent/child relationship between the App component and the Navbar, Dashboard, and Footer. +
    + +## Instructions +
    +In the code editor, there is a simple functional component called ChildComponent and a React component called ParentComponent. Compose the two together by rendering the ChildComponent within the ParentComponent. Make sure to close the ChildComponent tag with a forward slash. +Note: ChildComponent is defined with an ES6 arrow function because this is a very common practice when using React. However, know that this is just a function. If you aren't familiar with the arrow function syntax, please refer to the JavaScript section. +
    + +## Tests +
    + +```yml +- text: The React component should return a single div element. + testString: 'assert((function() { var shallowRender = Enzyme.shallow(React.createElement(ParentComponent)); return shallowRender.type() === "div"; })(), "The React component should return a single div element.");' +- text: The component should return two nested elements. + testString: 'assert((function() { var shallowRender = Enzyme.shallow(React.createElement(ParentComponent)); return shallowRender.children().length === 2; })(), "The component should return two nested elements.");' +- text: The component should return the ChildComponent as its second child. + testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(ParentComponent)); return mockedComponent.find("ParentComponent").find("ChildComponent").length === 1; })(), "The component should return the ChildComponent as its second child.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```jsx +const ChildComponent = () => { + return ( +
    +

    I am the child

    +
    + ); +}; + +class ParentComponent extends React.Component { + constructor(props) { + super(props); + } + render() { + return ( +
    +

    I am the parent

    + { /* change code below this line */ } + + + { /* change code above this line */ } +
    + ); + } +}; +``` + +
    + + +### After Test +
    + +```js +console.info('after the test'); +``` + +
    + +
    + +## Solution +
    + + +```js +const ChildComponent = () => { + return ( +
    +

    I am the child

    +
    + ); +}; + +class ParentComponent extends React.Component { + constructor(props) { + super(props); + } + render() { + return ( +
    +

    I am the parent

    + { /* change code below this line */ } + + { /* change code above this line */ } +
    + ); + } +}; +``` + +
    diff --git a/curriculum/challenges/03-front-end-libraries/react/Create a Controlled Form.md b/curriculum/challenges/03-front-end-libraries/react/Create a Controlled Form.md new file mode 100644 index 0000000000..aa7cb6b226 --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/react/Create a Controlled Form.md @@ -0,0 +1,140 @@ +--- +id: 5a24c314108439a4d4036179 +title: Create a Controlled Form +challengeType: 6 +isRequired: false +--- + +## Description +
    +The last challenge showed that React can control the internal state for certain elements like input and textarea, which makes them controlled components. This applies to other form elements as well, including the regular HTML form element. +
    + +## Instructions +
    +The MyForm component is set up with an empty form with a submit handler. The submit handler will be called when the form is submitted. +We've added a button which submits the form. You can see it has the type set to submit indicating it is the button controlling the form. Add the input element in the form and set its value and onChange() attributes like the last challenge. You should then complete the handleSubmit method so that it sets the component state property submit to the current input value in the local state. +Note:  You also must call event.preventDefault() in the submit handler, to prevent the default form submit behavior which will refresh the web page. +Finally, create an h1 tag after the form which renders the submit value from the component's state. You can then type in the form and click the button (or press enter), and you should see your input rendered to the page. +
    + +## Tests +
    + +```yml +- text: MyForm should return a div element which contains a form and an h1 tag. The form should include an input and a button. + testString: 'assert((() => { const mockedComponent = Enzyme.mount(React.createElement(MyForm)); return (mockedComponent.find("div").children().find("form").length === 1 && mockedComponent.find("div").children().find("h1").length === 1 && mockedComponent.find("form").children().find("input").length === 1 && mockedComponent.find("form").children().find("button").length === 1) })(), "MyForm should return a div element which contains a form and an h1 tag. The form should include an input and a button.");' +- text: 'The state of MyForm should initialize with input and submit properties, both set to empty strings.' + testString: 'assert(Enzyme.mount(React.createElement(MyForm)).state("input") === "" && Enzyme.mount(React.createElement(MyForm)).state("submit") === "", "The state of MyForm should initialize with input and submit properties, both set to empty strings.");' +- text: Typing in the input element should update the input property of the component's state. + testString: 'async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(MyForm)); const _1 = () => { mockedComponent.setState({ input: "" }); return waitForIt(() => mockedComponent.state("input"))}; const _2 = () => { mockedComponent.find("input").simulate("change", { target: { value: "TestInput" }}); return waitForIt(() => ({ state: mockedComponent.state("input"), inputVal: mockedComponent.find("input").props().value }))}; const before = await _1(); const after = await _2(); assert(before === "" && after.state === "TestInput" && after.inputVal === "TestInput", "Typing in the input element should update the input property of the component's state."); }; ' +- text: Submitting the form should run handleSubmit which should set the submit property in state equal to the current input. + testString: 'async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(MyForm)); const _1 = () => { mockedComponent.setState({ input: "" }); mockedComponent.setState({submit: ""}); mockedComponent.find("input").simulate("change", {target: {value: "SubmitInput"}}); return waitForIt(() => mockedComponent.state("submit"))}; const _2 = () => { mockedComponent.find("form").simulate("submit"); return waitForIt(() => mockedComponent.state("submit"))}; const before = await _1(); const after = await _2(); assert(before === "" && after === "SubmitInput", "Submitting the form should run handleSubmit which should set the submit property in state equal to the current input."); };' +- text: The h1 header should render the value of the submit field from the component's state. + testString: 'async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(MyForm)); const _1 = () => { mockedComponent.setState({ input: "" }); mockedComponent.setState({submit: ""}); mockedComponent.find("input").simulate("change", {target: {value: "TestInput"}}); return waitForIt(() => mockedComponent.find("h1").text())}; const _2 = () => { mockedComponent.find("form").simulate("submit"); return waitForIt(() => mockedComponent.find("h1").text())}; const before = await _1(); const after = await _2(); assert(before === "" && after === "TestInput", "The h1 header should render the value of the submit field from the component's state."); }; ' + +``` + +
    + +## Challenge Seed +
    + +
    + +```jsx +class MyForm extends React.Component { + constructor(props) { + super(props); + this.state = { + input: ", + submit: " + }; + this.handleChange = this.handleChange.bind(this); + this.handleSubmit = this.handleSubmit.bind(this); + } + handleChange(event) { + this.setState({ + input: event.target.value + }); + } + handleSubmit(event) { + // change code below this line + + // change code above this line + } + render() { + return ( +
    +
    + { /* change code below this line */ } + + { /* change code above this line */ } + +
    + { /* change code below this line */ } + + { /* change code above this line */ } +
    + ); + } +}; +``` + +
    + + +### After Test +
    + +```js +console.info('after the test'); +``` + +
    + +
    + +## Solution +
    + + +```js +class MyForm extends React.Component { + constructor(props) { + super(props); + this.state = { + input: ", + submit: " + }; + this.handleChange = this.handleChange.bind(this); + this.handleSubmit = this.handleSubmit.bind(this); + } + handleChange(event) { + this.setState({ + input: event.target.value + }); + } + handleSubmit(event) { + event.preventDefault() + this.setState({ + submit: this.state.input + }); + } + render() { + return ( +
    +
    + + +
    +

    {this.state.submit}

    +
    + ); + } +}; +``` + +
    diff --git a/curriculum/challenges/03-front-end-libraries/react/Create a Controlled Input.md b/curriculum/challenges/03-front-end-libraries/react/Create a Controlled Input.md new file mode 100644 index 0000000000..a667e9585c --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/react/Create a Controlled Input.md @@ -0,0 +1,117 @@ +--- +id: 5a24c314108439a4d4036178 +title: Create a Controlled Input +challengeType: 6 +isRequired: false +--- + +## Description +
    +Your application may have more complex interactions between state and the rendered UI. For example, form control elements for text input, such as input and textarea, maintain their own state in the DOM as the user types. With React, you can move this mutable state into a React component's state. The user's input becomes part of the application state, so React controls the value of that input field. Typically, if you have React components with input fields the user can type into, it will be a controlled input form. +
    + +## Instructions +
    +The code editor has the skeleton of a component called ControlledInput to create a controlled input element. The component's state is already initialized with an input property that holds an empty string. This value represents the text a user types into the input field. +First, create a method called handleChange() that has a parameter called event. When the method is called, it receives an event object that contains a string of text from the input element. You can access this string with event.target.value inside the method. Update the input property of the component's state with this new string. +In the render method, create the input element above the h4 tag. Add a value attribute which is equal to the input property of the component's state. Then add an onChange() event handler set to the handleChange() method. +When you type in the input box, that text is processed by the handleChange() method, set as the input property in the local state, and rendered as the value in the input box on the page. The component state is the single source of truth regarding the input data. +Last but not least, don't forget to add the necessary bindings in the constructor. +
    + +## Tests +
    + +```yml +- text: ControlledInput should return a div element which contains an input and a p tag. + testString: 'assert(Enzyme.mount(React.createElement(ControlledInput)).find("div").children().find("input").length === 1 && Enzyme.mount(React.createElement(ControlledInput)).find("div").children().find("p").length === 1, "ControlledInput should return a div element which contains an input and a p tag.");' +- text: The state of ControlledInput should initialize with an input property set to an empty string. + testString: 'assert.strictEqual(Enzyme.mount(React.createElement(ControlledInput)).state("input"), "", "The state of ControlledInput should initialize with an input property set to an empty string.");' +- text: 'Typing in the input element should update the state and the value of the input, and the p element should render this state as you type.' + testString: 'async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(ControlledInput)); const _1 = () => { mockedComponent.setState({ input: "" }); return waitForIt(() => mockedComponent.state("input"))}; const _2 = () => { mockedComponent.find("input").simulate("change", { target: { value: "TestInput" }}); return waitForIt(() => ({ state: mockedComponent.state("input"), text: mockedComponent.find("p").text(), inputVal: mockedComponent.find("input").props().value }))}; const before = await _1(); const after = await _2(); assert(before === "" && after.state === "TestInput" && after.text === "TestInput" && after.inputVal === "TestInput", "Typing in the input element should update the state and the value of the input, and the p element should render this state as you type."); }; ' + +``` + +
    + +## Challenge Seed +
    + +
    + +```jsx +class ControlledInput extends React.Component { + constructor(props) { + super(props); + this.state = { + input: " + }; + // change code below this line + + // change code above this line + } + // change code below this line + + // change code above this line + render() { + return ( +
    + { /* change code below this line */} + + { /* change code above this line */} +

    Controlled Input:

    +

    {this.state.input}

    +
    + ); + } +}; +``` + +
    + + +### After Test +
    + +```js +console.info('after the test'); +``` + +
    + +
    + +## Solution +
    + + +```js +class ControlledInput extends React.Component { + constructor(props) { + super(props); + this.state = { + input: " + }; + this.handleChange = this.handleChange.bind(this); + } + handleChange(event) { + this.setState({ + input: event.target.value + }); + } + render() { + return ( +
    + +

    Controlled Input:

    + +

    {this.state.input}

    +
    + ); + } +}; +``` + +
    diff --git a/curriculum/challenges/03-front-end-libraries/react/Create a React Component.md b/curriculum/challenges/03-front-end-libraries/react/Create a React Component.md new file mode 100644 index 0000000000..799b2adce8 --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/react/Create a React Component.md @@ -0,0 +1,92 @@ +--- +id: 5a24c314108439a4d4036163 +title: Create a React Component +challengeType: 6 +isRequired: false +--- + +## Description +
    +The other way to define a React component is with the ES6 class syntax. In the following example, Kitten extends React.Component: +
    class Kitten extends React.Component {
      constructor(props) {
        super(props);
      }

      render() {
        return (
          <h1>Hi</h1>
        );
      }
    }
    +This creates an ES6 class Kitten which extends the React.Component class. So the Kitten class now has access to many useful React features, such as local state and lifecycle hooks. Don't worry if you aren't familiar with these terms yet, they will be covered in greater detail in later challenges. +Also notice the Kitten class has a constructor defined within it that calls super(). It uses super() to call the constructor of the parent class, in this case React.Component. The constructor is a special method used during the initialization of objects that are created with the class keyword. It is best practice to call a component's constructor with super, and pass props to both. This makes sure the component is initialized properly. For now, know that it is standard for this code to be included. Soon you will see other uses for the constructor as well as props. +
    + +## Instructions +
    +MyComponent is defined in the code editor using class syntax. Finish writing the render method so it returns a div element that contains an h1 with the text Hello React!. +
    + +## Tests +
    + +```yml +- text: The React component should return a div element. + testString: 'assert(Enzyme.shallow(React.createElement(MyComponent)).type() === "div", "The React component should return a div element.");' +- text: The returned div should render an h1 header within it. + testString: 'assert(/

    .*<\/h1><\/div>/.test(Enzyme.shallow(React.createElement(MyComponent)).html()), "The returned div should render an h1 header within it.");' +- text: The h1 header should contain the string Hello React!. + testString: 'assert(Enzyme.shallow(React.createElement(MyComponent)).html() === "

    Hello React!

    ", "The h1 header should contain the string Hello React!.");' + +``` + +

    + +## Challenge Seed +
    + +
    + +```jsx + +class MyComponent extends React.Component { + constructor(props) { + super(props); + } + render() { + // change code below this line + + + + // change code above this line + } +}; +``` + +
    + + +### After Test +
    + +```js +console.info('after the test'); +``` + +
    + +
    + +## Solution +
    + + +```js +class MyComponent extends React.Component { + constructor(props) { + super(props); + } + render() { + // change code below this line + return ( +
    +

    Hello React!

    +
    + ); + // change code above this line + } +}; +``` + +
    diff --git a/curriculum/challenges/03-front-end-libraries/react/Create a Simple JSX Element.md b/curriculum/challenges/03-front-end-libraries/react/Create a Simple JSX Element.md new file mode 100644 index 0000000000..b0b04540d0 --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/react/Create a Simple JSX Element.md @@ -0,0 +1,68 @@ +--- +id: 587d7dbc367417b2b2512bb1 +title: Create a Simple JSX Element +challengeType: 6 +isRequired: false +--- + +## Description +
    +Intro: React is an Open Source view library created and maintained by Facebook. It's a great tool to render the User Interface (UI) of modern web applications. +React uses a syntax extension of JavaScript called JSX that allows you to write HTML directly within JavaScript. This has several benefits. It lets you use the full programmatic power of JavaScript within HTML, and helps to keep your code readable. For the most part, JSX is similar to the HTML that you have already learned, however there are a few key differences that will be covered throughout these challenges. +For instance, because JSX is a syntactic extension of JavaScript, you can actually write JavaScript directly within JSX. To do this, you simply include the code you want to be treated as JavaScript within curly braces: { 'this is treated as JavaScript code' }. Keep this in mind, since it's used in several future challenges. +However, because JSX is not valid JavaScript, JSX code must be compiled into JavaScript. The transpiler Babel is a popular tool for this process. For your convenience, it's already added behind the scenes for these challenges. If you happen to write syntactically invalid JSX, you will see the first test in these challenges fail. +It's worth noting that under the hood the challenges are calling ReactDOM.render(JSX, document.getElementById('root')). This function call is what places your JSX into React's own lightweight representation of the DOM. React then uses snapshots of its own DOM to optimize updating only specific parts of the actual DOM. +
    + +## Instructions +
    +Instructions: The current code uses JSX to assign a div element to the constant JSX. Replace the div with an h1 element and add the text Hello JSX! inside it. +
    + +## Tests +
    + +```yml +- text: The constant JSX should return an h1 element. + testString: 'assert(JSX.type === "h1", "The constant JSX should return an h1 element.");' +- text: The h1 tag should include the text Hello JSX! + testString: 'assert(Enzyme.shallow(JSX).contains("Hello JSX!"), "The h1 tag should include the text Hello JSX!");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```jsx + +const JSX =
    ; + +``` + +
    + + +### After Test +
    + +```js +console.info('after the test'); +``` + +
    + +
    + +## Solution +
    + + +```js +const JSX =

    Hello JSX!

    ; +``` + +
    diff --git a/curriculum/challenges/03-front-end-libraries/react/Create a Stateful Component.md b/curriculum/challenges/03-front-end-libraries/react/Create a Stateful Component.md new file mode 100644 index 0000000000..e6fdfe96b5 --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/react/Create a Stateful Component.md @@ -0,0 +1,97 @@ +--- +id: 5a24c314108439a4d4036170 +title: Create a Stateful Component +challengeType: 6 +isRequired: false +--- + +## Description +
    +One of the most important topics in React is state. State consists of any data your application needs to know about, that can change over time. You want your apps to respond to state changes and present an updated UI when necessary. React offers a nice solution for the state management of modern web applications. +You create state in a React component by declaring a state property on the component class in its constructor. This initializes the component with state when it is created. The state property must be set to a JavaScript object. Declaring it looks like this: +
    this.state = {
      // describe your state here
    } +You have access to the state object throughout the life of your component. You can update it, render it in your UI, and pass it as props to child components. The state object can be as complex or as simple as you need it to be. Note that you must create a class component by extending React.Component in order to create state like this. +
    + +## Instructions +
    +There is a component in the code editor that is trying to render a name property from its state. However, there is no state defined. Initialize the component with state in the constructor and assign your name to a property of name. +
    + +## Tests +
    + +```yml +- text: StatefulComponent should exist and render. + testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(StatefulComponent)); return mockedComponent.find("StatefulComponent").length === 1; })(), "StatefulComponent should exist and render.");' +- text: StatefulComponent should render a div and an h1 element. + testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(StatefulComponent)); return mockedComponent.find("div").length === 1 && mockedComponent.find("h1").length === 1; })(), "StatefulComponent should render a div and an h1 element.");' +- text: The state of StatefulComponent should be initialized with a property name set to a string. + testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(StatefulComponent)); const initialState = mockedComponent.state(); return ( typeof initialState === "object" && typeof initialState.name === "string"); })(), "The state of StatefulComponent should be initialized with a property name set to a string.");' +- text: The property name in the state of StatefulComponent should render in the h1 element. + testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(StatefulComponent)); const initialState = mockedComponent.state(); return mockedComponent.find("h1").text() === initialState.name; })(), "The property name in the state of StatefulComponent should render in the h1 element.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```jsx + +class StatefulComponent extends React.Component { + constructor(props) { + super(props); + // initialize state here + + } + render() { + return ( +
    +

    {this.state.name}

    +
    + ); + } +}; +``` + +
    + + +### After Test +
    + +```js +console.info('after the test'); +``` + +
    + +
    + +## Solution +
    + + +```js +class StatefulComponent extends React.Component { + constructor(props) { + super(props); + this.state = { + name: 'freeCodeCamp!' + } + } + render() { + return ( +
    +

    {this.state.name}

    +
    + ); + } +}; +``` + +
    diff --git a/curriculum/challenges/03-front-end-libraries/react/Create a Stateless Functional Component.md b/curriculum/challenges/03-front-end-libraries/react/Create a Stateless Functional Component.md new file mode 100644 index 0000000000..67a9029ab8 --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/react/Create a Stateless Functional Component.md @@ -0,0 +1,83 @@ +--- +id: 5a24c314108439a4d4036162 +title: Create a Stateless Functional Component +challengeType: 6 +isRequired: false +--- + +## Description +
    +Components are the core of React. Everything in React is a component and here you will learn how to create one. +There are two ways to create a React component. The first way is to use a JavaScript function. Defining a component in this way creates a stateless functional component. The concept of state in an application will be covered in later challenges. For now, think of a stateless component as one that can receive data and render it, but does not manage or track changes to that data. (We'll cover the second way to create a React component in the next challenge.) +To create a component with a function, you simply write a JavaScript function that returns either JSX or null. One important thing to note is that React requires your function name to begin with a capital letter. Here's an example of a stateless functional component that assigns an HTML class in JSX: +
    // After being transpiled, the <div> will have a CSS class of 'customClass'
    const DemoComponent = function() {
      return (
        <div className='customClass' />
      );
    };
    +Because a JSX component represents HTML, you could put several components together to create a more complex HTML page. This is one of the key advantages of the component architecture React provides. It allows you to compose your UI from many separate, isolated components. This makes it easier to build and maintain complex user interfaces. +
    + +## Instructions +
    +The code editor has a function called MyComponent. Complete this function so it returns a single div element which contains some string of text. +Note: The text is considered a child of the div element, so you will not be able to use a self-closing tag. +
    + +## Tests +
    + +```yml +- text: MyComponent should return JSX. + testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(MyComponent)); return mockedComponent.length === 1; })(), "MyComponent should return JSX.");' +- text: MyComponent should return a div element. + testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(MyComponent)); return mockedComponent.children().type() === "div" })(), "MyComponent should return a div element.");' +- text: The div element should contain a string of text. + testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(MyComponent)); return mockedComponent.find("div").text() !== ""; })(), "The div element should contain a string of text.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```jsx +const MyComponent = function() { + // change code below this line + + + + // change code above this line +} +``` + +
    + + +### After Test +
    + +```js +console.info('after the test'); +``` + +
    + +
    + +## Solution +
    + + +```js +const MyComponent = function() { + // change code below this line + return ( +
    + Demo Solution +
    + ); + // change code above this line +} +``` + +
    diff --git a/curriculum/challenges/03-front-end-libraries/react/Define an HTML Class in JSX.md b/curriculum/challenges/03-front-end-libraries/react/Define an HTML Class in JSX.md new file mode 100644 index 0000000000..f682c6a754 --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/react/Define an HTML Class in JSX.md @@ -0,0 +1,72 @@ +--- +id: 5a24c314108439a4d4036160 +title: Define an HTML Class in JSX +challengeType: 6 +isRequired: false +--- + +## Description +
    +Now that you're getting comfortable writing JSX, you may be wondering how it differs from HTML. +So far, it may seem that HTML and JSX are exactly the same. +One key difference in JSX is that you can no longer use the word class to define HTML classes. This is because class is a reserved word in JavaScript. Instead, JSX uses className. +In fact, the naming convention for all HTML attributes and event references in JSX become camelCase. For example, a click event in JSX is onClick, instead of onclick. Likewise, onchange becomes onChange. While this is a subtle difference, it is an important one to keep in mind moving forward. +
    + +## Instructions +
    +Apply a class of myDiv to the div provided in the JSX code. +
    + +## Tests +
    + +```yml +- text: The constant JSX should return a div element. + testString: 'assert.strictEqual(JSX.type, "div", "The constant JSX should return a div element.");' +- text: The div has a class of myDiv. + testString: 'assert.strictEqual(JSX.props.className, "myDiv", "The div has a class of myDiv.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```jsx +const JSX = ( +
    +

    Add a class to this div

    +
    +); +``` + +
    + + +### After Test +
    + +```js +console.info('after the test'); +``` + +
    + +
    + +## Solution +
    + + +```js +const JSX = ( +
    +

    Add a class to this div

    +
    ); +``` + +
    diff --git a/curriculum/challenges/03-front-end-libraries/react/Give Sibling Elements a Unique Key Attribute.md b/curriculum/challenges/03-front-end-libraries/react/Give Sibling Elements a Unique Key Attribute.md new file mode 100644 index 0000000000..5e4886a066 --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/react/Give Sibling Elements a Unique Key Attribute.md @@ -0,0 +1,110 @@ +--- +id: 5a24c314108439a4d403618b +title: Give Sibling Elements a Unique Key Attribute +challengeType: 6 +isRequired: false +--- + +## Description +
    +The last challenge showed how the map method is used to dynamically render a number of elements based on user input. However, there was an important piece missing from that example. When you create an array of elements, each one needs a key attribute set to a unique value. React uses these keys to keep track of which items are added, changed, or removed. This helps make the re-rendering process more efficient when the list is modified in any way. Note that keys only need to be unique between sibling elements, they don't need to be globally unique in your application. +
    + +## Instructions +
    +The code editor has an array with some front end frameworks and a stateless functional component named Frameworks(). Frameworks() needs to map the array to an unordered list, much like in the last challenge. Finish writing the map callback to return an li element for each framework in the frontEndFrameworks array. This time, make sure to give each li a key attribute, set to a unique value. +Normally, you want to make the key something that uniquely identifies the element being rendered. As a last resort the array index may be used, but typically you should try to use a unique identification. +
    + +## Tests +
    + +```yml +- text: The Frameworks component should exist and render to the page. + testString: 'assert(Enzyme.mount(React.createElement(Frameworks)).find("Frameworks").length === 1, "The Frameworks component should exist and render to the page.");' +- text: Frameworks should render an h1 element. + testString: 'assert(Enzyme.mount(React.createElement(Frameworks)).find("h1").length === 1, "Frameworks should render an h1 element.");' +- text: Frameworks should render a ul element. + testString: 'assert(Enzyme.mount(React.createElement(Frameworks)).find("ul").length === 1, "Frameworks should render a ul element.");' +- text: The ul tag should render 6 child li elements. + testString: 'assert(Enzyme.mount(React.createElement(Frameworks)).find("ul").children().length === 6 && Enzyme.mount(React.createElement(Frameworks)).find("ul").childAt(0).name() === "li" && Enzyme.mount(React.createElement(Frameworks)).find("li").length === 6, "The ul tag should render 6 child li elements.");' +- text: Each list item element should have a unique key attribute. + testString: 'assert((() => { const ul = Enzyme.mount(React.createElement(Frameworks)).find("ul"); const keys = new Set([ ul.childAt(0).key(), ul.childAt(1).key(), ul.childAt(2).key(), ul.childAt(3).key(), ul.childAt(4).key(), ul.childAt(5).key(), ]); return keys.size === 6; })(), "Each list item element should have a unique key attribute.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```jsx + +const frontEndFrameworks = [ + 'React', + 'Angular', + 'Ember', + 'Knockout', + 'Backbone', + 'Vue' +]; + +function Frameworks() { + const renderFrameworks = null; // change code here + return ( +
    +

    Popular Front End JavaScript Frameworks

    +
      + {renderFrameworks} +
    +
    + ); +}; +``` + +
    + + +### After Test +
    + +```js +console.info('after the test'); +``` + +
    + +
    + +## Solution +
    + + +```js +const frontEndFrameworks = [ + 'React', + 'Angular', + 'Ember', + 'Knockout', + 'Backbone', + 'Vue' +]; + +function Frameworks() { + const renderFrameworks = frontEndFrameworks.map((fw, i) => { + return
  • {fw}
  • + }) + return ( +
    +

    Popular Front End JavaScript Frameworks

    +
      + {renderFrameworks} +
    +
    + ); +}; +``` + +
    diff --git a/curriculum/challenges/03-front-end-libraries/react/Introducing Inline Styles.md b/curriculum/challenges/03-front-end-libraries/react/Introducing Inline Styles.md new file mode 100644 index 0000000000..7bf3e8cbd1 --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/react/Introducing Inline Styles.md @@ -0,0 +1,86 @@ +--- +id: 5a24c314108439a4d4036181 +title: Introducing Inline Styles +challengeType: 6 +isRequired: false +--- + +## Description +
    +There are other complex concepts that add powerful capabilities to your React code. But you may be wondering about the more simple problem of how to style those JSX elements you create in React. You likely know that it won't be exactly the same as working with HTML because of the way you apply classes to JSX elements. +If you import styles from a stylesheet, it isn't much different at all. You apply a class to your JSX element using the className attribute, and apply styles to the class in your stylesheet. Another option is to apply inline styles, which are very common in ReactJS development. +You apply inline styles to JSX elements similar to how you do it in HTML, but with a few JSX differences. Here's an example of an inline style in HTML: +<div style="color: yellow; font-size: 16px">Mellow Yellow</div> +JSX elements use the style attribute, but because of the way JSX is transpiled, you can't set the value to a string. Instead, you set it equal to a JavaScript object. Here's an example: +<div style={{color: "yellow", fontSize: 16}}>Mellow Yellow</div> +Notice how we camelCase the "fontSize" property? This is because React will not accept kebab-case keys in the style object. React will apply the correct property name for us in the HTML. +
    + +## Instructions +
    +Add a style attribute to the div in the code editor to give the text a color of red and font size of 72px. +Note that you can optionally set the font size to be a number, omitting the units "px", or write it as "72px". +
    + +## Tests +
    + +```yml +- text: The component should render a div element. + testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(Colorful)); return mockedComponent.children().type() === "div"; })(), "The component should render a div element.");' +- text: The div element should have a color of red. + testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(Colorful)); return mockedComponent.children().props().style.color === "red"; })(), "The div element should have a color of red.");' +- text: The div element should have a font size of 72px. + testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(Colorful)); return (mockedComponent.children().props().style.fontSize === 72 || mockedComponent.children().props().style.fontSize === "72" || mockedComponent.children().props().style.fontSize === "72px"); })(), "The div element should have a font size of 72px.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```jsx + +class Colorful extends React.Component { + render() { + return ( +
    Big Red
    + ); + } +}; + +``` + +
    + + +### After Test +
    + +```js +console.info('after the test'); +``` + +
    + +
    + +## Solution +
    + + +```js +class Colorful extends React.Component { + render() { + return ( +
    Big Red
    + ); + } +}; + +``` + +
    diff --git a/curriculum/challenges/03-front-end-libraries/react/Learn About Self-Closing JSX Tags.md b/curriculum/challenges/03-front-end-libraries/react/Learn About Self-Closing JSX Tags.md new file mode 100644 index 0000000000..24cc69b5be --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/react/Learn About Self-Closing JSX Tags.md @@ -0,0 +1,85 @@ +--- +id: 5a24c314108439a4d4036161 +title: Learn About Self-Closing JSX Tags +challengeType: 6 +isRequired: false +--- + +## Description +
    +So far, you’ve seen how JSX differs from HTML in a key way with the use of className vs. class for defining HTML classes. +Another important way in which JSX differs from HTML is in the idea of the self-closing tag. +In HTML, almost all tags have both an opening and closing tag: <div></div>; the closing tag always has a forward slash before the tag name that you are closing. However, there are special instances in HTML called “self-closing tags”, or tags that don’t require both an opening and closing tag before another tag can start. +For example the line-break tag can be written as <br> or as <br />, but should never be written as <br></br>, since it doesn't contain any content. +In JSX, the rules are a little different. Any JSX element can be written with a self-closing tag, and every element must be closed. The line-break tag, for example, must always be written as <br /> in order to be valid JSX that can be transpiled. A <div>, on the other hand, can be written as <div /> or <div></div>. The difference is that in the first syntax version there is no way to include anything in the <div />. You will see in later challenges that this syntax is useful when rendering React components. +
    + +## Instructions +
    +Fix the errors in the code editor so that it is valid JSX and successfully transpiles. Make sure you don't change any of the content - you only need to close tags where they are needed. +
    + +## Tests +
    + +```yml +- text: The constant JSX should return a div element. + testString: 'assert.strictEqual(JSX.type, "div", "The constant JSX should return a div element.");' +- text: The div should contain a br tag. + testString: 'assert(Enzyme.shallow(JSX).find("br").length === 1, "The div should contain a br tag.");' +- text: The div should contain an hr tag. + testString: 'assert(Enzyme.shallow(JSX).find("hr").length === 1, "The div should contain an hr tag.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```jsx +const JSX = ( +
    + {/* remove comment and change code below this line +

    Welcome to React!


    +

    Be sure to close all tags!

    +
    + remove comment and change code above this line */} +
    +); + +``` + +
    + + +### After Test +
    + +```js +console.info('after the test'); +``` + +
    + +
    + +## Solution +
    + + +```js +const JSX = ( +
    + {/* change code below this line */} +

    Welcome to React!


    +

    Be sure to close all tags!

    +
    + {/* change code above this line */} +
    +); +``` + +
    diff --git a/curriculum/challenges/03-front-end-libraries/react/Manage Updates with Lifecycle Methods.md b/curriculum/challenges/03-front-end-libraries/react/Manage Updates with Lifecycle Methods.md new file mode 100644 index 0000000000..44c8280e07 --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/react/Manage Updates with Lifecycle Methods.md @@ -0,0 +1,146 @@ +--- +id: 5a24c314108439a4d403617f +title: Manage Updates with Lifecycle Methods +challengeType: 6 +isRequired: false +--- + +## Description +
    +Another lifecycle method is componentWillReceiveProps() which is called whenever a component is receiving new props. This method receives the new props as an argument, which is usually written as nextProps. You can use this argument and compare with this.props and perform actions before the component updates. For example, you may call setState() locally before the update is processed. +Another method is componentDidUpdate(), and is called immediately after a component re-renders. Note that rendering and mounting are considered different things in the component lifecycle. When a page first loads, all components are mounted and this is where methods like componentWillMount() and componentDidMount() are called. After this, as state changes, components re-render themselves. The next challenge covers this in more detail. +
    + +## Instructions +
    +The child component Dialog receives message props from its parent, the Controller component. Write the componentWillReceiveProps() method in the Dialog component and have it log this.props and nextProps to the console. You'll need to pass nextProps as an argument to this method and although it's possible to name it anything, name it nextProps here. +Next, add componentDidUpdate() in the Dialog component, and log a statement that says the component has updated. This method works similar to componentWillUpdate(), which is provided for you. Now click the button to change the message and watch your browser console. The order of the console statements show the order the methods are called. +Note: You'll need to write the lifecycle methods as normal functions and not as arrow functions to pass the tests (there is also no advantage to writing lifecycle methods as arrow functions). +
    + +## Tests +
    + +```yml +- text: The Controller component should render the Dialog component as a child. + testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(Controller)); return mockedComponent.find("Controller").length === 1 && mockedComponent.find("Dialog").length === 1; })(), "The Controller component should render the Dialog component as a child.");' +- text: The componentWillReceiveProps method in the Dialog component should log this.props to the console. + testString: 'assert((function() { const lifecycleChild = React.createElement(Dialog).type.prototype.componentWillReceiveProps.toString().replace(/ /g,""); return lifecycleChild.includes("console.log") && lifecycleChild.includes("this.props") })(), "The componentWillReceiveProps method in the Dialog component should log this.props to the console.");' +- text: The componentWillReceiveProps method in the Dialog component should log nextProps to the console. + testString: 'assert((function() { const lifecycleChild = React.createElement(Dialog).type.prototype.componentWillReceiveProps.toString().replace(/ /g,""); const nextPropsAsParameterTest = /componentWillReceiveProps(| *?= *?)(\(|)nextProps(\)|)( *?=> *?{| *?{|{)/; const nextPropsInConsoleLogTest = /console\.log\(.*?nextProps\b.*?\)/; return ( lifecycleChild.includes("console.log") && nextPropsInConsoleLogTest.test(lifecycleChild) && nextPropsAsParameterTest.test(lifecycleChild) ); })(), "The componentWillReceiveProps method in the Dialog component should log nextProps to the console.");' +- text: The Dialog component should call the componentDidUpdate method and log a message to the console. + testString: 'assert((function() { const lifecycleChild = React.createElement(Dialog).type.prototype.componentDidUpdate.toString().replace(/ /g,""); return lifecycleChild.length !== "undefined" && lifecycleChild.includes("console.log"); })(), "The Dialog component should call the componentDidUpdate method and log a message to the console.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```jsx +class Dialog extends React.Component { + constructor(props) { + super(props); + } + componentWillUpdate() { + console.log('Component is about to update...'); + } + // change code below this line + + // change code above this line + render() { + return

    {this.props.message}

    + } +}; + +class Controller extends React.Component { + constructor(props) { + super(props); + this.state = { + message: 'First Message' + }; + this.changeMessage = this.changeMessage.bind(this); + } + changeMessage() { + this.setState({ + message: 'Second Message' + }); + } + render() { + return ( +
    + + +
    + ); + } +}; +``` + +
    + + +### After Test +
    + +```js +console.info('after the test'); +``` + +
    + +
    + +## Solution +
    + + +```js +class Dialog extends React.Component { + constructor(props) { + super(props); + } + componentWillUpdate() { + console.log('Component is about to update...'); + } + // change code below this line + componentWillReceiveProps(nextProps) { + console.log(this.props, nextProps); + } + componentDidUpdate() { + console.log('Component re-rendered'); + } + // change code above this line + render() { + return

    {this.props.message}

    + } +}; + +class Controller extends React.Component { + constructor(props) { + super(props); + this.state = { + message: 'First Message' + }; + this.changeMessage = this.changeMessage.bind(this); + } + changeMessage() { + this.setState({ + message: 'Second Message' + }); + } + render() { + return ( +
    + + +
    + ); + } +}; +``` + +
    diff --git a/curriculum/challenges/03-front-end-libraries/react/Optimize Re-Renders with shouldComponentUpdate.md b/curriculum/challenges/03-front-end-libraries/react/Optimize Re-Renders with shouldComponentUpdate.md new file mode 100644 index 0000000000..d0be15a48e --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/react/Optimize Re-Renders with shouldComponentUpdate.md @@ -0,0 +1,151 @@ +--- +id: 5a24c314108439a4d4036180 +title: Optimize Re-Renders with shouldComponentUpdate +challengeType: 6 +isRequired: false +--- + +## Description +
    +So far, if any component receives new state or new props, it re-renders itself and all its children. This is usually okay. But React provides a lifecycle method you can call when child components receive new state or props, and declare specifically if the components should update or not. The method is shouldComponentUpdate(), and it takes nextProps and nextState as parameters. +This method is a useful way to optimize performance. For example, the default behavior is that your component re-renders when it receives new props, even if the props haven't changed. You can use shouldComponentUpdate() to prevent this by comparing the props. The method must return a boolean value that tells React whether or not to update the component. You can compare the current props (this.props) to the next props (nextProps) to determine if you need to update or not, and return true or false accordingly. +
    + +## Instructions +
    +The shouldComponentUpdate() method is added in a component called OnlyEvens. Currently, this method returns true so OnlyEvens re-renders every time it receives new props. Modify the method so OnlyEvens updates only if the value of its new props is even. Click the Add button and watch the order of events in your browser's console as the other lifecycle hooks are triggered. +
    + +## Tests +
    + +```yml +- text: The Controller component should render the OnlyEvens component as a child. + testString: 'assert((() => { const mockedComponent = Enzyme.mount(React.createElement(Controller)); return mockedComponent.find("Controller").length === 1 && mockedComponent.find("OnlyEvens").length === 1; })(), "The Controller component should render the OnlyEvens component as a child.");' +- text: The shouldComponentUpdate method should be defined on the OnlyEvens component. + testString: 'assert((() => { const child = React.createElement(OnlyEvens).type.prototype.shouldComponentUpdate.toString().replace(/s/g,""); return child !== "undefined"; })(), "The shouldComponentUpdate method should be defined on the OnlyEvens component.");' +- text: The OnlyEvens component should return an h1 tag which renders the value of this.props.value. + testString: 'async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(Controller)); const first = () => { mockedComponent.setState({ value: 1000 }); return waitForIt(() => mockedComponent.find("h1").html()); }; const second = () => { mockedComponent.setState({ value: 10 }); return waitForIt(() => mockedComponent.find("h1").html()); }; const firstValue = await first(); const secondValue = await second(); assert(firstValue === "

    1000

    " && secondValue === "

    10

    ", "The OnlyEvens component should return an h1 tag which renders the value of this.props.value."); }; ' +- text: OnlyEvens should re-render only when nextProps.value is even. + testString: 'async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(Controller)); const first = () => { mockedComponent.setState({ value: 8 }); return waitForIt(() => mockedComponent.find("h1").text()); }; const second = () => { mockedComponent.setState({ value: 7 }); return waitForIt(() => mockedComponent.find("h1").text()); }; const third = () => { mockedComponent.setState({ value: 42 }); return waitForIt(() => mockedComponent.find("h1").text()); }; const firstValue = await first(); const secondValue = await second(); const thirdValue = await third(); assert(firstValue === "8" && secondValue === "8" && thirdValue === "42", "OnlyEvens should re-render only when nextProps.value is even."); }; ' + +``` + +
    + +## Challenge Seed +
    + +
    + +```jsx +class OnlyEvens extends React.Component { + constructor(props) { + super(props); + } + shouldComponentUpdate(nextProps, nextState) { + console.log('Should I update?'); + // change code below this line + return true; + // change code above this line + } + componentWillReceiveProps(nextProps) { + console.log('Receiving new props...'); + } + componentDidUpdate() { + console.log('Component re-rendered.'); + } + render() { + return

    {this.props.value}

    + } +}; + +class Controller extends React.Component { + constructor(props) { + super(props); + this.state = { + value: 0 + }; + this.addValue = this.addValue.bind(this); + } + addValue() { + this.setState({ + value: this.state.value + 1 + }); + } + render() { + return ( +
    + + +
    + ); + } +}; +``` + +
    + + +### After Test +
    + +```js +console.info('after the test'); +``` + +
    + +
    + +## Solution +
    + + +```js +class OnlyEvens extends React.Component { + constructor(props) { + super(props); + } + shouldComponentUpdate(nextProps, nextState) { + console.log('Should I update?'); + // change code below this line + return nextProps.value % 2 === 0; + // change code above this line + } + componentWillReceiveProps(nextProps) { + console.log('Receiving new props...'); + } + componentDidUpdate() { + console.log('Component re-rendered.'); + } + render() { + return

    {this.props.value}

    + } +}; + +class Controller extends React.Component { + constructor(props) { + super(props); + this.state = { + value: 0 + }; + this.addValue = this.addValue.bind(this); + } + addValue() { + this.setState({ + value: this.state.value + 1 + }); + } + render() { + return ( +
    + + +
    + ); + } +}; +``` + +
    diff --git a/curriculum/challenges/03-front-end-libraries/react/Override Default Props.md b/curriculum/challenges/03-front-end-libraries/react/Override Default Props.md new file mode 100644 index 0000000000..f2e9678d5e --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/react/Override Default Props.md @@ -0,0 +1,99 @@ +--- +id: 5a24c314108439a4d403616c +title: Override Default Props +challengeType: 6 +isRequired: false +--- + +## Description +
    +The ability to set default props is a useful feature in React. The way to override the default props is to explicitly set the prop values for a component. +
    + +## Instructions +
    +The ShoppingCart component now renders a child component Items. This Items component has a default prop quantity set to the integer 0. Override the default prop by passing in a value of 10 for quantity. +Note: Remember that the syntax to add a prop to a component looks similar to how you add HTML attributes. However, since the value for quantity is an integer, it won't go in quotes but it should be wrapped in curly braces. For example, {100}. This syntax tells JSX to interpret the value within the braces directly as JavaScript. +
    + +## Tests +
    + +```yml +- text: The component ShoppingCart should render. + testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(ShoppingCart)); return mockedComponent.find("ShoppingCart").length === 1; })(), "The component ShoppingCart should render.");' +- text: The component Items should render. + testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(ShoppingCart)); return mockedComponent.find("Items").length === 1; })(), "The component Items should render.");' +- text: 'The Items component should have a prop of { quantity: 10 } passed from the ShoppingCart component.' + testString: 'getUserInput => assert((function() { const mockedComponent = Enzyme.mount(React.createElement(ShoppingCart)); return mockedComponent.find("Items").props().quantity == 10 && getUserInput("index").replace(/ /g,"").includes(""); })(), "The Items component should have a prop of { quantity: 10 } passed from the ShoppingCart component.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```jsx +const Items = (props) => { + return

    Current Quantity of Items in Cart: {props.quantity}

    +} + +Items.defaultProps = { + quantity: 0 +} + +class ShoppingCart extends React.Component { + constructor(props) { + super(props); + } + render() { + { /* change code below this line */ } + return + { /* change code above this line */ } + } +}; +``` + +
    + + +### After Test +
    + +```js +console.info('after the test'); +``` + +
    + +
    + +## Solution +
    + + +```js +const Items = (props) => { + return

    Current Quantity of Items in Cart: {props.quantity}

    +} + +Items.defaultProps = { + quantity: 0 +} + +class ShoppingCart extends React.Component { + constructor(props) { + super(props); + } + render() { + { /* change code below this line */ } + return + { /* change code above this line */ } + } +}; +``` + +
    diff --git a/curriculum/challenges/03-front-end-libraries/react/Pass Props to a Stateless Functional Component.md b/curriculum/challenges/03-front-end-libraries/react/Pass Props to a Stateless Functional Component.md new file mode 100644 index 0000000000..d196adb9c4 --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/react/Pass Props to a Stateless Functional Component.md @@ -0,0 +1,121 @@ +--- +id: 5a24c314108439a4d4036169 +title: Pass Props to a Stateless Functional Component +challengeType: 6 +isRequired: false +--- + +## Description +
    +The previous challenges covered a lot about creating and composing JSX elements, functional components, and ES6 style class components in React. With this foundation, it's time to look at another feature very common in React: props. In React, you can pass props, or properties, to child components. Say you have an App component which renders a child component called Welcome that is a stateless functional component. You can pass Welcome a user property by writing: +
    <App>
      <Welcome user='Mark' />
    </App>
    +You use custom HTML attributes that React provides support for to pass the property user to the component Welcome. Since Welcome is a stateless functional component, it has access to this value like so: +
    const Welcome = (props) => <h1>Hello, {props.user}!</h1>
    +It is standard to call this value props and when dealing with stateless functional components, you basically consider it as an argument to a function which returns JSX. You can access the value of the argument in the function body. With class components, you will see this is a little different. +
    + +## Instructions +
    +There are Calendar and CurrentDate components in the code editor. When rendering CurrentDate from the Calendar component, pass in a property of date assigned to the current date from JavaScript's Date object. Then access this prop in the CurrentDate component, showing its value within the p tags. Note that for prop values to be evaluated as JavaScript, they must be enclosed in curly brackets, for instance date={Date()}. +
    + +## Tests +
    + +```yml +- text: The Calendar component should return a single div element. + testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(Calendar)); return mockedComponent.children().type() === "div"; })(), "The Calendar component should return a single div element.");' +- text: The second child of the Calendar component should be the CurrentDate component. + testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(Calendar)); return mockedComponent.children().childAt(1).name() === "CurrentDate"; })(), "The second child of the Calendar component should be the CurrentDate component.");' +- text: The CurrentDate component should have a prop called date. + testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(Calendar)); return mockedComponent.children().childAt(1).props().date })(), "The CurrentDate component should have a prop called date.");' +- text: The date prop of the CurrentDate should contain a string of text. + testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(Calendar)); const prop = mockedComponent.children().childAt(1).props().date; return( typeof prop === "string" && prop.length > 0 ); })(), "The date prop of the CurrentDate should contain a string of text.");' +- text: The CurrentDate component should render the value from the date prop in the p tag. + testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(Calendar)); return mockedComponent.find("p").html().includes(Date().substr(3)); })(), "The CurrentDate component should render the value from the date prop in the p tag.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```jsx + +const CurrentDate = (props) => { + return ( +
    + { /* change code below this line */ } +

    The current date is:

    + { /* change code above this line */ } +
    + ); +}; + +class Calendar extends React.Component { + constructor(props) { + super(props); + } + render() { + return ( +
    +

    What date is it?

    + { /* change code below this line */ } + + { /* change code above this line */ } +
    + ); + } +}; +``` + +
    + + +### After Test +
    + +```js +console.info('after the test'); +``` + +
    + +
    + +## Solution +
    + + +```js +const CurrentDate = (props) => { + return ( +
    + { /* change code below this line */ } +

    The current date is: {props.date}

    + { /* change code above this line */ } +
    + ); +}; + +class Calendar extends React.Component { + constructor(props) { + super(props); + } + render() { + return ( +
    +

    What date is it?

    + { /* change code below this line */ } + + { /* change code above this line */ } +
    + ); + } +}; +``` + +
    diff --git a/curriculum/challenges/03-front-end-libraries/react/Pass State as Props to Child Components.md b/curriculum/challenges/03-front-end-libraries/react/Pass State as Props to Child Components.md new file mode 100644 index 0000000000..6e35ee1d3b --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/react/Pass State as Props to Child Components.md @@ -0,0 +1,119 @@ +--- +id: 5a24c314108439a4d403617a +title: Pass State as Props to Child Components +challengeType: 6 +isRequired: false +--- + +## Description +
    +You saw a lot of examples that passed props to child JSX elements and child React components in previous challenges. You may be wondering where those props come from. A common pattern is to have a stateful component containing the state important to your app, that then renders child components. You want these components to have access to some pieces of that state, which are passed in as props. +For example, maybe you have an App component that renders a Navbar, among other components. In your App, you have state that contains a lot of user information, but the Navbar only needs access to the user's username so it can display it. You pass that piece of state to the Navbar component as a prop. +This pattern illustrates some important paradigms in React. The first is unidirectional data flow. State flows in one direction down the tree of your application's components, from the stateful parent component to child components. The child components only receive the state data they need. The second is that complex stateful apps can be broken down into just a few, or maybe a single, stateful component. The rest of your components simply receive state from the parent as props, and render a UI from that state. It begins to create a separation where state management is handled in one part of code and UI rendering in another. This principle of separating state logic from UI logic is one of React's key principles. When it's used correctly, it makes the design of complex, stateful applications much easier to manage. +
    + +## Instructions +
    +The MyApp component is stateful and renders a Navbar component as a child. Pass the name property in its state down to the child component, then show the name in the h1 tag that's part of the Navbar render method. +
    + +## Tests +
    + +```yml +- text: The MyApp component should render with a Navbar component inside. + testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(MyApp)); return mockedComponent.find("MyApp").length === 1 && mockedComponent.find("Navbar").length === 1; })(), "The MyApp component should render with a Navbar component inside.");' +- text: The Navbar component should receive the MyApp state property name as props. + testString: 'async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(MyApp)); const setState = () => { mockedComponent.setState({name: "TestName"}); return waitForIt(() => mockedComponent.find("Navbar").props() )}; const navProps = await setState(); assert(navProps.name === "TestName", "The Navbar component should receive the MyApp state property name as props."); }; ' +- text: The h1 element in Navbar should render the name prop. + testString: 'async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(MyApp)); const navH1Before = mockedComponent.find("Navbar").find("h1").text(); const setState = () => { mockedComponent.setState({name: "TestName"}); return waitForIt(() => mockedComponent.find("Navbar").find("h1").text() )}; const navH1After = await setState(); assert(new RegExp("TestName").test(navH1After) && navH1After !== navH1Before, "The h1 element in Navbar should render the name prop."); }; ' + +``` + +
    + +## Challenge Seed +
    + +
    + +```jsx +class MyApp extends React.Component { + constructor(props) { + super(props); + this.state = { + name: 'CamperBot' + } + } + render() { + return ( +
    + +
    + ); + } +}; + +class Navbar extends React.Component { + constructor(props) { + super(props); + } + render() { + return ( +
    +

    Hello, my name is: /* your code here */

    +
    + ); + } +}; +``` + +
    + + +### After Test +
    + +```js +console.info('after the test'); +``` + +
    + +
    + +## Solution +
    + + +```js +class MyApp extends React.Component { + constructor(props) { + super(props); + this.state = { + name: 'CamperBot' + } + } + render() { + return ( +
    + +
    + ); + } +}; +class Navbar extends React.Component { + constructor(props) { + super(props); + } + render() { + return ( +
    +

    Hello, my name is: {this.props.name}

    +
    + ); + } +}; +``` + +
    diff --git a/curriculum/challenges/03-front-end-libraries/react/Pass a Callback as Props.md b/curriculum/challenges/03-front-end-libraries/react/Pass a Callback as Props.md new file mode 100644 index 0000000000..9222cafbd7 --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/react/Pass a Callback as Props.md @@ -0,0 +1,175 @@ +--- +id: 5a24c314108439a4d403617b +title: Pass a Callback as Props +challengeType: 6 +isRequired: false +--- + +## Description +
    +You can pass state as props to child components, but you're not limited to passing data. You can also pass handler functions or any method that's defined on a React component to a child component. This is how you allow child components to interact with their parent components. You pass methods to a child just like a regular prop. It's assigned a name and you have access to that method name under this.props in the child component. +
    + +## Instructions +
    +There are three components outlined in the code editor. The MyApp component is the parent that will render the GetInput and RenderInput child components. Add the GetInput component to the render method in MyApp, then pass it a prop called input assigned to inputValue from MyApp's state. Also create a prop called handleChange and pass the input handler handleChange to it. +Next, add RenderInput to the render method in MyApp, then create a prop called input and pass the inputValue from state to it. Once you are finished you will be able to type in the input field in the GetInput component, which then calls the handler method in its parent via props. This updates the input in the state of the parent, which is passed as props to both children. Observe how the data flows between the components and how the single source of truth remains the state of the parent component. Admittedly, this example is a bit contrived, but should serve to illustrate how data and callbacks can be passed between React components. +
    + +## Tests +
    + +```yml +- text: The MyApp component should render. + testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(MyApp)); return mockedComponent.find("MyApp").length === 1; })(), "The MyApp component should render.");' +- text: The GetInput component should render. + testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(MyApp)); return mockedComponent.find("GetInput").length === 1; })(), "The GetInput component should render.");' +- text: The RenderInput component should render. + testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(MyApp)); return mockedComponent.find("RenderInput").length === 1; })(), "The RenderInput component should render.");' +- text: The GetInput component should receive the MyApp state property inputValue as props and contain an input element which modifies MyApp state. + testString: 'async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(MyApp)); const state_1 = () => { mockedComponent.setState({inputValue: ""}); return waitForIt(() => mockedComponent.state() )}; const state_2 = () => { mockedComponent.find("input").simulate("change", {target: {value: "TestInput"}}); return waitForIt(() => mockedComponent.state() )}; const updated_1 = await state_1(); const updated_2 = await state_2(); assert(updated_1.inputValue === "" && updated_2.inputValue === "TestInput", "The GetInput component should receive the MyApp state property inputValue as props and contain an input element which modifies MyApp state."); }; ' +- text: The RenderInput component should receive the MyApp state property inputValue as props. + testString: 'async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(MyApp)); const state_1 = () => { mockedComponent.setState({inputValue: "TestName"}); return waitForIt(() => mockedComponent )}; const updated_1 = await state_1(); assert(updated_1.find("p").text().includes("TestName"), "The RenderInput component should receive the MyApp state property inputValue as props."); }; ' + +``` + +
    + +## Challenge Seed +
    + +
    + +```jsx +class MyApp extends React.Component { + constructor(props) { + super(props); + this.state = { + inputValue: " + } + this.handleChange = this.handleChange.bind(this); + } + handleChange(event) { + this.setState({ + inputValue: event.target.value + }); + } + render() { + return ( +
    + { /* change code below this line */ } + + { /* change code above this line */ } +
    + ); + } +}; + +class GetInput extends React.Component { + constructor(props) { + super(props); + } + render() { + return ( +
    +

    Get Input:

    + +
    + ); + } +}; + +class RenderInput extends React.Component { + constructor(props) { + super(props); + } + render() { + return ( +
    +

    Input Render:

    +

    {this.props.input}

    +
    + ); + } +}; +``` + +
    + + +### After Test +
    + +```js +console.info('after the test'); +``` + +
    + +
    + +## Solution +
    + + +```js +class MyApp extends React.Component { + constructor(props) { + super(props); + this.state = { + inputValue: " + } + this.handleChange = this.handleChange.bind(this); + } + handleChange(event) { + this.setState({ + inputValue: event.target.value + }); + } + render() { + return ( +
    + + +
    + ); + } +}; + +class GetInput extends React.Component { + constructor(props) { + super(props); + } + render() { + return ( +
    +

    Get Input:

    + +
    + ); + } +}; + +class RenderInput extends React.Component { + constructor(props) { + super(props); + } + render() { + return ( +
    +

    Input Render:

    +

    {this.props.input}

    +
    + ); + } +}; +``` + +
    diff --git a/curriculum/challenges/03-front-end-libraries/react/Pass an Array as Props.md b/curriculum/challenges/03-front-end-libraries/react/Pass an Array as Props.md new file mode 100644 index 0000000000..d560170795 --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/react/Pass an Array as Props.md @@ -0,0 +1,120 @@ +--- +id: 5a24c314108439a4d403616a +title: Pass an Array as Props +challengeType: 6 +isRequired: false +--- + +## Description +
    +The last challenge demonstrated how to pass information from a parent component to a child component as props or properties. This challenge looks at how arrays can be passed as props. To pass an array to a JSX element, it must be treated as JavaScript and wrapped in curly braces. +
    <ParentComponent>
      <ChildComponent colors={["green", "blue", "red"]} />
    </ParentComponent>
    +The child component then has access to the array property colors. Array methods such as join() can be used when accessing the property. +const ChildComponent = (props) => <p>{props.colors.join(', ')}</p> +This will join all colors array items into a comma separated string and produce: + <p>green, blue, red</p> +Later, we will learn about other common methods to render arrays of data in React. +
    + +## Instructions +
    +There are List and ToDo components in the code editor. When rendering each List from the ToDo component, pass in a tasks property assigned to an array of to-do tasks, for example ["walk dog", "workout"]. Then access this tasks array in the List component, showing its value within the p element. Use join(", ") to display the props.tasksarray in the p element as a comma separated list. Today's list should have at least 2 tasks and tomorrow's should have at least 3 tasks. +
    + +## Tests +
    + +```yml +- text: The ToDo component should return a single outer div. + testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(ToDo)); return mockedComponent.children().first().type() === "div"; })(), "The ToDo component should return a single outer div.");' +- text: The third child of the ToDo component should be an instance of the List component. + testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(ToDo)); return mockedComponent.children().first().childAt(2).name() === "List"; })(), "The third child of the ToDo component should be an instance of the List component.");' +- text: The fifth child of the ToDo component should be an instance of the List component. + testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(ToDo)); return mockedComponent.children().first().childAt(4).name() === "List"; })(), "The fifth child of the ToDo component should be an instance of the List component.");' +- text: Both instances of the List component should have a property called tasks and tasks should be of type array. + testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(ToDo)); return Array.isArray(mockedComponent.find("List").get(0).props.tasks) && Array.isArray(mockedComponent.find("List").get(1).props.tasks); })(), "Both instances of the List component should have a property called tasks and tasks should be of type array.");' +- text: The first List component representing the tasks for today should have 2 or more items. + testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(ToDo)); return mockedComponent.find("List").get(0).props.tasks.length >= 2; })(), "The first List component representing the tasks for today should have 2 or more items.");' +- text: The second List component representing the tasks for tomorrow should have 3 or more items. + testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(ToDo)); return mockedComponent.find("List").get(1).props.tasks.length >= 3; })(), "The second List component representing the tasks for tomorrow should have 3 or more items.");' +- text: The List component should render the value from the tasks prop in the p tag. + testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(ToDo)); return mockedComponent.find("p").get(0).props.children === mockedComponent.find("List").get(0).props.tasks.join(", ") && mockedComponent.find("p").get(1).props.children === mockedComponent.find("List").get(1).props.tasks.join(", "); })(), "The List component should render the value from the tasks prop in the p tag.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```jsx +const List= (props) => { + { /* change code below this line */ } + return

    {}

    + { /* change code above this line */ } +}; + +class ToDo extends React.Component { + constructor(props) { + super(props); + } + render() { + return ( +
    +

    To Do Lists

    +

    Today

    + { /* change code below this line */ } + +

    Tomorrow

    + + { /* change code above this line */ } +
    + ); + } +}; +``` + +
    + + +### After Test +
    + +```js +console.info('after the test'); +``` + +
    + +
    + +## Solution +
    + + +```js +const List= (props) => { + return

    {props.tasks.join(', ')}

    +}; + +class ToDo extends React.Component { + constructor(props) { + super(props); + } + render() { + return ( +
    +

    To Do Lists

    +

    Today

    + +

    Tomorrow

    + +
    + ); + } +}; +``` + +
    diff --git a/curriculum/challenges/03-front-end-libraries/react/Render Conditionally from Props.md b/curriculum/challenges/03-front-end-libraries/react/Render Conditionally from Props.md new file mode 100644 index 0000000000..3787e2b497 --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/react/Render Conditionally from Props.md @@ -0,0 +1,155 @@ +--- +id: 5a24c314108439a4d4036188 +title: Render Conditionally from Props +challengeType: 6 +isRequired: false +--- + +## Description +
    +So far, you've seen how to use if/else, &&, null and the ternary operator (condition ? expressionIfTrue : expressionIfFalse) to make conditional decisions about what to render and when. However, there's one important topic left to discuss that lets you combine any or all of these concepts with another powerful React feature: props. Using props to conditionally render code is very common with React developers — that is, they use the value of a given prop to automatically make decisions about what to render. +In this challenge, you'll set up a child component to make rendering decisions based on props. You'll also use the ternary operator, but you can see how several of the other concepts that were covered in the last few challenges might be just as useful in this context. +
    + +## Instructions +
    +The code editor has two components that are partially defined for you: a parent called GameOfChance, and a child called Results. They are used to create a simple game where the user presses a button to see if they win or lose. +First, you'll need a simple expression that randomly returns a different value every time it is run. You can use Math.random(). This method returns a value between 0 (inclusive) and 1 (exclusive) each time it is called. So for 50/50 odds, use Math.random() > .5 in your expression. Statistically speaking, this expression will return true 50% of the time, and false the other 50%. On line 30, replace the comment with this expression to complete the variable declaration. +Now you have an expression that you can use to make a randomized decision in the code. Next you need to implement this. Render the Results component as a child of GameOfChance, and pass in expression as a prop called fiftyFifty. In the Results component, write a ternary expression to render the text "You win!" or "You lose!" based on the fiftyFifty prop that's being passed in from GameOfChance. Finally, make sure the handleClick() method is correctly counting each turn so the user knows how many times they've played. This also serves to let the user know the component has actually updated in case they win or lose twice in a row. +
    + +## Tests +
    + +```yml +- text: The GameOfChance component should exist and render to the page. + testString: 'assert.strictEqual(Enzyme.mount(React.createElement(GameOfChance)).find("GameOfChance").length, 1, "The GameOfChance component should exist and render to the page.");' +- text: GameOfChance should return a single button element. + testString: 'assert.strictEqual(Enzyme.mount(React.createElement(GameOfChance)).find("button").length, 1, "GameOfChance should return a single button element.");' +- text: 'GameOfChance should return a single instance of the Results component, which has a prop called fiftyFifty.' + testString: 'assert(Enzyme.mount(React.createElement(GameOfChance)).find("Results").length === 1 && Enzyme.mount(React.createElement(GameOfChance)).find("Results").props().hasOwnProperty("fiftyFifty") === true, "GameOfChance should return a single instance of the Results component, which has a prop called fiftyFifty.");' +- text: GameOfChance state should be initialized with a property of counter set to a value of 1. + testString: 'assert.strictEqual(Enzyme.mount(React.createElement(GameOfChance)).state().counter, 1, "GameOfChance state should be initialized with a property of counter set to a value of 1.");' +- text: 'When the GameOfChance component is first rendered to the DOM, a p element should be returned with the inner text of Turn: 1.' + testString: 'assert.strictEqual(Enzyme.mount(React.createElement(GameOfChance)).find("p").text(), "Turn: 1", "When the GameOfChance component is first rendered to the DOM, a p element should be returned with the inner text of Turn: 1.");' +- text: 'Each time the button is clicked, the counter state should be incremented by a value of 1, and a single p element should be rendered to the DOM that contains the text "Turn: N", where N is the value of the counter state.' + testString: 'async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const comp = Enzyme.mount(React.createElement(GameOfChance)); const simulate = () => { comp.find("button").simulate("click"); };const result = () => ({ count: comp.state("counter"), text: comp.find("p").text() });const _1 = () => { simulate(); return waitForIt(() => result())}; const _2 = () => { simulate(); return waitForIt(() => result())}; const _3 = () => { simulate(); return waitForIt(() => result())}; const _4 = () => { simulate(); return waitForIt(() => result())}; const _5 = () => { simulate(); return waitForIt(() => result())}; const _1_val = await _1(); const _2_val = await _2(); const _3_val = await _3(); const _4_val = await _4(); const _5_val = await _5(); assert(_1_val.count === 2 && _1_val.text === "Turn: 2" && _2_val.count === 3 && _2_val.text === "Turn: 3" && _3_val.count === 4 && _3_val.text === "Turn: 4" && _4_val.count === 5 && _4_val.text === "Turn: 5" && _5_val.count === 6 && _5_val.text === "Turn: 6", "Each time the button is clicked, the counter state should be incremented by a value of 1, and a single p element should be rendered to the DOM that contains the text "Turn: N", where N is the value of the counter state."); }; ' +- text: 'When the GameOfChance component is first mounted to the DOM and each time the button is clicked thereafter, a single h1 element should be returned that randomly renders either You Win! or You Lose!.' + testString: 'async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const comp = Enzyme.mount(React.createElement(GameOfChance)); const simulate = () => { comp.find("button").simulate("click"); };const result = () => ({ h1: comp.find("h1").length, text: comp.find("h1").text() });const _1 = result(); const _2 = () => { simulate(); return waitForIt(() => result())}; const _3 = () => { simulate(); return waitForIt(() => result())}; const _4 = () => { simulate(); return waitForIt(() => result())}; const _5 = () => { simulate(); return waitForIt(() => result())}; const _6 = () => { simulate(); return waitForIt(() => result())}; const _7 = () => { simulate(); return waitForIt(() => result())}; const _8 = () => { simulate(); return waitForIt(() => result())}; const _9 = () => { simulate(); return waitForIt(() => result())}; const _10 = () => { simulate(); return waitForIt(() => result())}; const _2_val = await _2(); const _3_val = await _3(); const _4_val = await _4(); const _5_val = await _5(); const _6_val = await _6(); const _7_val = await _7(); const _8_val = await _8(); const _9_val = await _9(); const _10_val = await _10(); const __text = new Set([_1.text, _2_val.text, _3_val.text, _4_val.text, _5_val.text, _6_val.text, _7_val.text, _8_val.text, _9_val.text, _10_val.text]); const __h1 = new Set([_1.h1, _2_val.h1, _3_val.h1, _4_val.h1, _5_val.h1, _6_val.h1, _7_val.h1, _8_val.h1, _9_val.h1, _10_val.h1]); assert(__text.size === 2 && __h1.size === 1, "When the GameOfChance component is first mounted to the DOM and each time the button is clicked thereafter, a single h1 element should be returned that randomly renders either You Win! or You Lose!."); }; ' + +``` + +
    + +## Challenge Seed +
    + +
    + +```jsx +class Results extends React.Component { + constructor(props) { + super(props); + } + render() { + return ( +

    + { + /* change code here */ + } +

    + ) + }; +}; + +class GameOfChance extends React.Component { + constructor(props) { + super(props); + this.state = { + counter: 1 + } + this.handleClick = this.handleClick.bind(this); + } + handleClick() { + this.setState({ + counter: 0 // change code here + }); + } + render() { + let expression = null; // change code here + return ( +
    + + { /* change code below this line */ } + + { /* change code above this line */ } +

    {'Turn: ' + this.state.counter}

    +
    + ); + } +}; +``` + +
    + + +### After Test +
    + +```js +console.info('after the test'); +``` + +
    + +
    + +## Solution +
    + + +```js +class Results extends React.Component { + constructor(props) { + super(props); + } + render() { + return ( +

    + { + this.props.fiftyFifty ? + 'You Win!' : + 'You Lose!' + } +

    + ) + }; +}; + +class GameOfChance extends React.Component { + constructor(props) { + super(props); + this.state = { + counter: 1 + } + this.handleClick = this.handleClick.bind(this); + } + handleClick() { + this.setState({ + counter: this.state.counter + 1 + }); + } + render() { + const expression = Math.random() > .5; + return ( +
    + + +

    {'Turn: ' + this.state.counter}

    +
    + ); + } +}; +``` + +
    diff --git a/curriculum/challenges/03-front-end-libraries/react/Render HTML Elements to the DOM.md b/curriculum/challenges/03-front-end-libraries/react/Render HTML Elements to the DOM.md new file mode 100644 index 0000000000..c41d9de5a3 --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/react/Render HTML Elements to the DOM.md @@ -0,0 +1,74 @@ +--- +id: 5a24bbe0dba28a8d3cbd4c5f +title: Render HTML Elements to the DOM +challengeType: 6 +isRequired: false +--- + +## Description +
    +So far, you've learned that JSX is a convenient tool to write readable HTML within JavaScript. With React, we can render this JSX directly to the HTML DOM using React's rendering API known as ReactDOM. +ReactDOM offers a simple method to render React elements to the DOM which looks like this: ReactDOM.render(componentToRender, targetNode), where the first argument is the React element or component that you want to render, and the second argument is the DOM node that you want to render the component to. +As you would expect, ReactDOM.render() must be called after the JSX element declarations, just like how you must declare variables before using them. +
    + +## Instructions +
    +The code editor has a simple JSX component. Use the ReactDOM.render() method to render this component to the page. You can pass defined JSX elements directly in as the first argument and use document.getElementById() to select the DOM node to render them to. There is a div with id='challenge-node' available for you to use. Make sure you don't change the JSX constant. +
    + +## Tests +
    + +```yml +- text: The constant JSX should return a div element. + testString: 'assert(JSX.type === "div", "The constant JSX should return a div element.");' +- text: The div should contain an h1 tag as the first element. + testString: 'assert(JSX.props.children[0].type === "h1", "The div should contain an h1 tag as the first element.");' +- text: The div should contain a p tag as the second element. + testString: 'assert(JSX.props.children[1].type === "p", "The div should contain a p tag as the second element.");' +- text: The provided JSX element should render to the DOM node with id challenge-node. + testString: 'assert(document.getElementById("challenge-node").childNodes[0].innerHTML === "

    Hello World

    Lets render this to the DOM

    ", "The provided JSX element should render to the DOM node with id challenge-node.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```jsx +const JSX = ( +
    +

    Hello World

    +

    Lets render this to the DOM

    +
    +); +// change code below this line + +``` + +
    + + + +
    + +## Solution +
    + + +```js +const JSX = ( +
    +

    Hello World

    +

    Lets render this to the DOM

    +
    +); +// change code below this line +ReactDOM.render(JSX, document.getElementById('challenge-node')); +``` + +
    diff --git a/curriculum/challenges/03-front-end-libraries/react/Render React on the Server with renderToString.md b/curriculum/challenges/03-front-end-libraries/react/Render React on the Server with renderToString.md new file mode 100644 index 0000000000..a63fba95c0 --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/react/Render React on the Server with renderToString.md @@ -0,0 +1,90 @@ +--- +id: 5a24c314108439a4d403618d +title: Render React on the Server with renderToString +challengeType: 6 +isRequired: false +--- + +## Description +
    +So far, you have been rendering React components on the client. Normally, this is what you will always do. However, there are some use cases where it makes sense to render a React component on the server. Since React is a JavaScript view library and you can run JavaScript on the server with Node, this is possible. In fact, React provides a renderToString() method you can use for this purpose. +There are two key reasons why rendering on the server may be used in a real world app. First, without doing this, your React apps would consist of a relatively empty HTML file and a large bundle of JavaScript when it's initially loaded to the browser. This may not be ideal for search engines that are trying to index the content of your pages so people can find you. If you render the initial HTML markup on the server and send this to the client, the initial page load contains all of the page's markup which can be crawled by search engines. Second, this creates a faster initial page load experience because the rendered HTML is smaller than the JavaScript code of the entire app. React will still be able to recognize your app and manage it after the initial load. +
    + +## Instructions +
    +The renderToString() method is provided on ReactDOMServer, which is available here as a global object. The method takes one argument which is a React element. Use this to render App to a string. +
    + +## Tests +
    + +```yml +- text: The App component should render to a string using ReactDOMServer.renderToString. + testString: 'getUserInput => assert(getUserInput("index").replace(/ /g,"").includes("ReactDOMServer.renderToString()") && Enzyme.mount(React.createElement(App)).children().name() === "div", "The App component should render to a string using ReactDOMServer.renderToString.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```jsx + +class App extends React.Component { + constructor(props) { + super(props); + } + render() { + return
    + } +}; + +// change code below this line + +``` + +
    + +### Before Test +
    + +```jsx +var ReactDOMServer = { renderToString(x) { return null; } }; +``` + +
    + +### After Test +
    + +```js +console.info('after the test'); +``` + +
    + +
    + +## Solution +
    + + +```js +class App extends React.Component { + constructor(props) { + super(props); + } + render() { + return
    + } +}; + +// change code below this line +ReactDOMServer.renderToString(); +``` + +
    diff --git a/curriculum/challenges/03-front-end-libraries/react/Render State in the User Interface Another Way.md b/curriculum/challenges/03-front-end-libraries/react/Render State in the User Interface Another Way.md new file mode 100644 index 0000000000..f6991be7a3 --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/react/Render State in the User Interface Another Way.md @@ -0,0 +1,105 @@ +--- +id: 5a24c314108439a4d4036172 +title: Render State in the User Interface Another Way +challengeType: 6 +isRequired: false +--- + +## Description +
    +There is another way to access state in a component. In the render() method, before the return statement, you can write JavaScript directly. For example, you could declare functions, access data from state or props, perform computations on this data, and so on. Then, you can assign any data to variables, which you have access to in the return statement. +
    + +## Instructions +
    +In the MyComponent render method, define a const called name and set it equal to the name value in the component's state. Because you can write JavaScript directly in this part of the code, you don't have to enclose this reference in curly braces. +Next, in the return statement, render this value in an h1 tag using the variable name. Remember, you need to use the JSX syntax (curly braces for JavaScript) in the return statement. +
    + +## Tests +
    + +```yml +- text: MyComponent should have a key name with value freeCodeCamp stored in its state. + testString: 'assert(Enzyme.mount(React.createElement(MyComponent)).state("name") === "freeCodeCamp", "MyComponent should have a key name with value freeCodeCamp stored in its state.");' +- text: MyComponent should render an h1 header enclosed in a single div. + testString: 'assert(/

    .*<\/h1><\/div>/.test(Enzyme.mount(React.createElement(MyComponent)).html()), "MyComponent should render an h1 header enclosed in a single div.");' +- text: 'The rendered h1 tag should include a reference to {name}.' + testString: 'getUserInput => assert(/

    \n*\s*\{\s*name\s*\}\s*\n*<\/h1>/.test(getUserInput("index")), "The rendered h1 tag should include a reference to {name}.");' +- text: The rendered h1 header should contain text rendered from the component's state. + testString: 'async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(MyComponent)); const first = () => { mockedComponent.setState({ name: "TestName" }); return waitForIt(() => mockedComponent.html()) }; const firstValue = await first(); assert(firstValue === "

    TestName

    ", "The rendered h1 header should contain text rendered from the component's state."); };' + +``` + +

    + +## Challenge Seed +
    + +
    + +```jsx +class MyComponent extends React.Component { + constructor(props) { + super(props); + this.state = { + name: 'freeCodeCamp' + } + } + render() { + // change code below this line + + // change code above this line + return ( +
    + { /* change code below this line */ } + + { /* change code above this line */ } +
    + ); + } +}; +``` + +
    + + +### After Test +
    + +```js +console.info('after the test'); +``` + +
    + +
    + +## Solution +
    + + +```js +class MyComponent extends React.Component { + constructor(props) { + super(props); + this.state = { + name: 'freeCodeCamp' + } + } + render() { + // change code below this line + const name = this.state.name; + // change code above this line + return ( +
    + { /* change code below this line */ } +

    {name}

    + { /* change code above this line */ } +
    + ); + } +}; +``` + +
    diff --git a/curriculum/challenges/03-front-end-libraries/react/Render State in the User Interface.md b/curriculum/challenges/03-front-end-libraries/react/Render State in the User Interface.md new file mode 100644 index 0000000000..5379febb4f --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/react/Render State in the User Interface.md @@ -0,0 +1,100 @@ +--- +id: 5a24c314108439a4d4036171 +title: Render State in the User Interface +challengeType: 6 +isRequired: false +--- + +## Description +
    +Once you define a component's initial state, you can display any part of it in the UI that is rendered. If a component is stateful, it will always have access to the data in state in its render() method. You can access the data with this.state. +If you want to access a state value within the return of the render method, you have to enclose the value in curly braces. +State is one of the most powerful features of components in React. It allows you to track important data in your app and render a UI in response to changes in this data. If your data changes, your UI will change. React uses what is called a virtual DOM, to keep track of changes behind the scenes. When state data updates, it triggers a re-render of the components using that data - including child components that received the data as a prop. React updates the actual DOM, but only where necessary. This means you don't have to worry about changing the DOM. You simply declare what the UI should look like. +Note that if you make a component stateful, no other components are aware of its state. Its state is completely encapsulated, or local to that component, unless you pass state data to a child component as props. This notion of encapsulated state is very important because it allows you to write certain logic, then have that logic contained and isolated in one place in your code. +
    + +## Instructions +
    +In the code editor, MyComponent is already stateful. Define an h1 tag in the component's render method which renders the value of name from the component's state. +Note: The h1 should only render the value from state and nothing else. In JSX, any code you write with curly braces { } will be treated as JavaScript. So to access the value from state just enclose the reference in curly braces. +
    + +## Tests +
    + +```yml +- text: MyComponent should have a key name with value freeCodeCamp stored in its state. + testString: 'assert(Enzyme.mount(React.createElement(MyComponent)).state("name") === "freeCodeCamp", "MyComponent should have a key name with value freeCodeCamp stored in its state.");' +- text: MyComponent should render an h1 header enclosed in a single div. + testString: 'assert(/

    .*<\/h1><\/div>/.test(Enzyme.mount(React.createElement(MyComponent)).html()), "MyComponent should render an h1 header enclosed in a single div.");' +- text: The rendered h1 header should contain text rendered from the component's state. + testString: 'async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(MyComponent)); const first = () => { mockedComponent.setState({ name: "TestName" }); return waitForIt(() => mockedComponent.html()) }; const firstValue = await first(); assert(firstValue === "

    TestName

    ", "The rendered h1 header should contain text rendered from the component's state.");};' + +``` + +

    + +## Challenge Seed +
    + +
    + +```jsx +class MyComponent extends React.Component { + constructor(props) { + super(props); + this.state = { + name: 'freeCodeCamp' + } + } + render() { + return ( +
    + { /* change code below this line */ } + + { /* change code above this line */ } +
    + ); + } +}; +``` + +
    + + +### After Test +
    + +```js +console.info('after the test'); +``` + +
    + +
    + +## Solution +
    + + +```js +class MyComponent extends React.Component { + constructor(props) { + super(props); + this.state = { + name: 'freeCodeCamp' + } + } + render() { + return ( +
    + { /* change code below this line */ } +

    {this.state.name}

    + { /* change code above this line */ } +
    + ); + } +}; +``` + +
    diff --git a/curriculum/challenges/03-front-end-libraries/react/Render a Class Component to the DOM.md b/curriculum/challenges/03-front-end-libraries/react/Render a Class Component to the DOM.md new file mode 100644 index 0000000000..6db7c5fdd5 --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/react/Render a Class Component to the DOM.md @@ -0,0 +1,138 @@ +--- +id: 5a24c314108439a4d4036167 +title: Render a Class Component to the DOM +challengeType: 6 +isRequired: false +--- + +## Description +
    +You may remember using the ReactDOM API in an earlier challenge to render JSX elements to the DOM. The process for rendering React components will look very similar. The past few challenges focused on components and composition, so the rendering was done for you behind the scenes. However, none of the React code you write will render to the DOM without making a call to the ReactDOM API. +Here's a refresher on the syntax: ReactDOM.render(componentToRender, targetNode). The first argument is the React component that you want to render. The second argument is the DOM node that you want to render that component within. +React components are passed into ReactDOM.render() a little differently than JSX elements. For JSX elements, you pass in the name of the element that you want to render. However, for React components, you need to use the same syntax as if you were rendering a nested component, for example ReactDOM.render(<ComponentToRender />, targetNode). You use this syntax for both ES6 class components and functional components. +
    + +## Instructions +
    +Both the Fruits and Vegetables components are defined for you behind the scenes. Render both components as children of the TypesOfFood component, then render TypesOfFood to the DOM. There is a div with id='challenge-node' available for you to use. +
    + +## Tests +
    + +```yml +- text: The TypesOfFood component should return a single div element. + testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(TypesOfFood)); return mockedComponent.children().type() === "div"; })(), "The TypesOfFood component should return a single div element.");' +- text: The TypesOfFood component should render the Fruits component after the h1 element. + testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(TypesOfFood)); return mockedComponent.children().childAt(1).name() === "Fruits"; })(), "The TypesOfFood component should render the Fruits component after the h1 element.");' +- text: The TypesOfFood component should render the Vegetables component after Fruits. + testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(TypesOfFood)); return mockedComponent.children().childAt(2).name() === "Vegetables"; })(), "The TypesOfFood component should render the Vegetables component after Fruits.");' +- text: The TypesOfFood component should render to the DOM within the div with the id challenge-node. + testString: 'assert((function() { const html = document.getElementById("challenge-node").childNodes[0].innerHTML; return (html === "

    Types of Food:

    Fruits:

    Non-Citrus:

    • Apples
    • Blueberries
    • Strawberries
    • Bananas

    Citrus:

    • Lemon
    • Lime
    • Orange
    • Grapefruit

    Vegetables:

    • Brussel Sprouts
    • Broccoli
    • Squash
    "); })(), "The TypesOfFood component should render to the DOM within the div with the id challenge-node.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```jsx + +class TypesOfFood extends React.Component { + constructor(props) { + super(props); + } + render() { + return ( +
    +

    Types of Food:

    + {/* change code below this line */} + + {/* change code above this line */} +
    + ); + } +}; + +// change code below this line + +``` + +
    + +### Before Test +
    + +```jsx + +const Fruits = () => { + return ( +
    +

    Fruits:

    +

    Non-Citrus:

    +
      +
    • Apples
    • +
    • Blueberries
    • +
    • Strawberries
    • +
    • Bananas
    • +
    +

    Citrus:

    +
      +
    • Lemon
    • +
    • Lime
    • +
    • Orange
    • +
    • Grapefruit
    • +
    +
    + ); +}; +const Vegetables = () => { + return ( +
    +

    Vegetables:

    +
      +
    • Brussel Sprouts
    • +
    • Broccoli
    • +
    • Squash
    • +
    +
    + ); +}; + +``` + +
    + + +
    + +## Solution +
    + + +```js +class TypesOfFood extends React.Component { + constructor(props) { + super(props); + } + render() { + return ( +
    +

    Types of Food:

    + {/* change code below this line */} + + + {/* change code above this line */} +
    + ); + } +}; + +// change code below this line +ReactDOM.render(, document.getElementById('challenge-node')); +``` + +
    diff --git a/curriculum/challenges/03-front-end-libraries/react/Render with an If-Else Condition.md b/curriculum/challenges/03-front-end-libraries/react/Render with an If-Else Condition.md new file mode 100644 index 0000000000..868344563a --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/react/Render with an If-Else Condition.md @@ -0,0 +1,120 @@ +--- +id: 5a24c314108439a4d4036184 +title: Render with an If-Else Condition +challengeType: 6 +isRequired: false +--- + +## Description +
    +Another application of using JavaScript to control your rendered view is to tie the elements that are rendered to a condition. When the condition is true, one view renders. When it's false, it's a different view. You can do this with a standard if/else statement in the render() method of a React component. +
    + +## Instructions +
    +MyComponent contains a boolean in its state which tracks whether you want to display some element in the UI or not. The button toggles the state of this value. Currently, it renders the same UI every time. Rewrite the render() method with an if/else statement so that if display is true, you return the current markup. Otherwise, return the markup without the h1 element. +Note: You must write an if/else to pass the tests. Use of the ternary operator will not pass here. +
    + +## Tests +
    + +```yml +- text: MyComponent should exist and render. + testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(MyComponent)); return mockedComponent.find("MyComponent").length === 1; })(), "MyComponent should exist and render.");' +- text: 'When display is set to true, a div, button, and h1 should render.' + testString: 'async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(MyComponent)); const state_1 = () => { mockedComponent.setState({display: true}); return waitForIt(() => mockedComponent )}; const updated = await state_1(); assert(mockedComponent.find("div").length === 1 && mockedComponent.find("div").children().length === 2 && mockedComponent.find("button").length === 1 && mockedComponent.find("h1").length === 1, "When display is set to true, a div, button, and h1 should render."); }; ' +- text: 'When display is set to false, only a div and button should render.' + testString: 'async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(MyComponent)); const state_1 = () => { mockedComponent.setState({display: false}); return waitForIt(() => mockedComponent )}; const updated = await state_1(); assert(mockedComponent.find("div").length === 1 && mockedComponent.find("div").children().length === 1 && mockedComponent.find("button").length === 1 && mockedComponent.find("h1").length === 0, "When display is set to false, only a div and button should render."); }; ' +- text: The render method should use an if/else statement to check the condition of this.state.display. + testString: 'getUserInput => assert(getUserInput("index").includes("if") && getUserInput("index").includes("else"), "The render method should use an if/else statement to check the condition of this.state.display.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```jsx +class MyComponent extends React.Component { + constructor(props) { + super(props); + this.state = { + display: true + } + this.toggleDisplay = this.toggleDisplay.bind(this); + } + toggleDisplay() { + this.setState({ + display: !this.state.display + }); + } + render() { + // change code below this line + + return ( +
    + +

    Displayed!

    +
    + ); + } +}; +``` + +
    + + +### After Test +
    + +```js +console.info('after the test'); +``` + +
    + +
    + +## Solution +
    + + +```js +class MyComponent extends React.Component { + constructor(props) { + super(props); + this.state = { + display: true + } + this.toggleDisplay = this.toggleDisplay.bind(this); + } + toggleDisplay() { + this.setState({ + display: !this.state.display + }); + } + render() { + // change code below this line + if (this.state.display) { + return ( +
    + +

    Displayed!

    +
    + ); + } else { + return ( +
    + +
    + ); + } + } +}; +``` + +
    diff --git a/curriculum/challenges/03-front-end-libraries/react/Review Using Props with Stateless Functional Components.md b/curriculum/challenges/03-front-end-libraries/react/Review Using Props with Stateless Functional Components.md new file mode 100644 index 0000000000..2e9d34d979 --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/react/Review Using Props with Stateless Functional Components.md @@ -0,0 +1,122 @@ +--- +id: 5a24c314108439a4d403616f +title: Review Using Props with Stateless Functional Components +challengeType: 6 +isRequired: false +--- + +## Description +
    +Except for the last challenge, you've been passing props to stateless functional components. These components act like pure functions. They accept props as input and return the same view every time they are passed the same props. You may be wondering what state is, and the next challenge will cover it in more detail. Before that, here's a review of the terminology for components. +A stateless functional component is any function you write which accepts props and returns JSX. A stateless component, on the other hand, is a class that extends React.Component, but does not use internal state (covered in the next challenge). Finally, a stateful component is any component that does maintain its own internal state. You may see stateful components referred to simply as components or React components. +A common pattern is to try to minimize statefulness and to create stateless functional components wherever possible. This helps contain your state management to a specific area of your application. In turn, this improves development and maintenance of your app by making it easier to follow how changes to state affect its behavior. +
    + +## Instructions +
    +The code editor has a CampSite component that renders a Camper component as a child. Define the Camper component and assign it default props of { name: 'CamperBot' }. Inside the Camper component, render any code that you want, but make sure to have one p element that includes only the name value that is passed in as a prop. Finally, define propTypes on the Camper component to require name to be provided as a prop and verify that it is of type string. +
    + +## Tests +
    + +```yml +- text: The CampSite component should render. + testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(CampSite)); return mockedComponent.find("CampSite").length === 1; })(), "The CampSite component should render.");' +- text: The Camper component should render. + testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(CampSite)); return mockedComponent.find("Camper").length === 1; })(), "The Camper component should render.");' +- text: The Camper component should include default props which assign the string CamperBot to the key name. + testString: 'getUserInput => assert((function() { const noWhiteSpace = getUserInput("index").replace(/\s/g, ""); const verify1 = "Camper.defaultProps={name:\"CamperBot\"}"; const verify2 = "Camper.defaultProps={name:"CamperBot"}"; return (noWhiteSpace.includes(verify1) || noWhiteSpace.includes(verify2)); })(), "The Camper component should include default props which assign the string CamperBot to the key name.");' +- text: The Camper component should include prop types which require the name prop to be of type string. + testString: 'getUserInput => assert((function() { const mockedComponent = Enzyme.mount(React.createElement(CampSite)); const noWhiteSpace = getUserInput("index").replace(/\s/g, ""); const verifyDefaultProps = "Camper.propTypes={name:PropTypes.string.isRequired}"; return noWhiteSpace.includes(verifyDefaultProps); })(), "The Camper component should include prop types which require the name prop to be of type string.");' +- text: The Camper component should contain a p element with only the text from the name prop. + testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(CampSite)); return mockedComponent.find("p").text() === mockedComponent.find("Camper").props().name; })(), "The Camper component should contain a p element with only the text from the name prop.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```jsx +class CampSite extends React.Component { + constructor(props) { + super(props); + } + render() { + return ( +
    + +
    + ); + } +}; +// change code below this line + +``` + +
    + +### Before Test +
    + +```jsx +var PropTypes = { + string: { isRequired: true } +}; +``` + +
    + +### After Test +
    + +```js +console.info('after the test'); +``` + +
    + +
    + +## Solution +
    + + +```js +class CampSite extends React.Component { + constructor(props) { + super(props); + } + render() { + return ( +
    + +
    + ); + } +}; +// change code below this line + +const Camper = (props) => { + return ( +
    +

    {props.name}

    +
    + ); +}; + +Camper.propTypes = { + name: PropTypes.string.isRequired +}; + +Camper.defaultProps = { + name: 'CamperBot' +}; + +``` + +
    diff --git a/curriculum/challenges/03-front-end-libraries/react/Set State with this.setState.md b/curriculum/challenges/03-front-end-libraries/react/Set State with this.setState.md new file mode 100644 index 0000000000..0e40183fcf --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/react/Set State with this.setState.md @@ -0,0 +1,113 @@ +--- +id: 5a24c314108439a4d4036173 +title: Set State with this.setState +challengeType: 6 +isRequired: false +--- + +## Description +
    +The previous challenges covered component state and how to initialize state in the constructor. There is also a way to change the component's state. React provides a method for updating component state called setState. You call the setState method within your component class like so: this.setState(), passing in an object with key-value pairs. The keys are your state properties and the values are the updated state data. For instance, if we were storing a username in state and wanted to update it, it would look like this: +
    this.setState({
      username: 'Lewis'
    });
    +React expects you to never modify state directly, instead always use this.setState() when state changes occur. Also, you should note that React may batch multiple state updates in order to improve performance. What this means is that state updates through the setState method can be asynchronous. There is an alternative syntax for the setState method which provides a way around this problem. This is rarely needed but it's good to keep it in mind! Please consult the React documentation for further details. +
    + +## Instructions +
    +There is a button element in the code editor which has an onClick() handler. This handler is triggered when the button receives a click event in the browser, and runs the handleClick method defined on MyComponent. Within the handleClick method, update the component state using this.setState(). Set the name property in state to equal the string React Rocks!. +Click the button and watch the rendered state update. Don't worry if you don't fully understand how the click handler code works at this point. It's covered in upcoming challenges. +
    + +## Tests +
    + +```yml +- text: 'The state of MyComponent should initialize with the key value pair { name: Initial State }.' + testString: 'assert(Enzyme.mount(React.createElement(MyComponent)).state("name") === "Initial State", "The state of MyComponent should initialize with the key value pair { name: Initial State }.");' +- text: MyComponent should render an h1 header. + testString: 'assert(Enzyme.mount(React.createElement(MyComponent)).find("h1").length === 1, "MyComponent should render an h1 header.");' +- text: The rendered h1 header should contain text rendered from the component's state. + testString: 'async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(MyComponent)); const first = () => { mockedComponent.setState({ name: "TestName" }); return waitForIt(() => mockedComponent.html()); }; const firstValue = await first(); assert(/

    TestName<\/h1>/.test(firstValue), "The rendered h1 header should contain text rendered from the component's state."); };' +- text: Calling the handleClick method on MyComponent should set the name property in state to equal React Rocks!. + testString: 'async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(MyComponent)); const first = () => { mockedComponent.setState({ name: "Before" }); return waitForIt(() => mockedComponent.state("name")); }; const second = () => { mockedComponent.instance().handleClick(); return waitForIt(() => mockedComponent.state("name")); }; const firstValue = await first(); const secondValue = await second(); assert(firstValue === "Before" && secondValue === "React Rocks!", "Calling the handleClick method on MyComponent should set the name property in state to equal React Rocks!."); };' + +``` + +

    + +## Challenge Seed +
    + +
    + +```jsx +class MyComponent extends React.Component { + constructor(props) { + super(props); + this.state = { + name: 'Initial State' + }; + this.handleClick = this.handleClick.bind(this); + } + handleClick() { + // change code below this line + + // change code above this line + } + render() { + return ( +
    + +

    {this.state.name}

    +
    + ); + } +}; +``` + +
    + + +### After Test +
    + +```js +console.info('after the test'); +``` + +
    + +
    + +## Solution +
    + + +```js +class MyComponent extends React.Component { + constructor(props) { + super(props); + this.state = { + name: 'Initial State' + }; + this.handleClick = this.handleClick.bind(this); + } + handleClick() { + // change code below this line + this.setState({ + name: 'React Rocks!' + }); + // change code above this line + } + render() { + return ( +
    + +

    {this.state.name}

    +
    + ); + } +}; +``` + +
    diff --git a/curriculum/challenges/03-front-end-libraries/react/Use && for a More Concise Conditional.md b/curriculum/challenges/03-front-end-libraries/react/Use && for a More Concise Conditional.md new file mode 100644 index 0000000000..d748b9d859 --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/react/Use && for a More Concise Conditional.md @@ -0,0 +1,112 @@ +--- +id: 5a24c314108439a4d4036185 +title: Use && for a More Concise Conditional +challengeType: 6 +isRequired: false +--- + +## Description +
    +The if/else statements worked in the last challenge, but there's a more concise way to achieve the same result. Imagine that you are tracking several conditions in a component and you want different elements to render depending on each of these conditions. If you write a lot of else if statements to return slightly different UIs, you may repeat code which leaves room for error. Instead, you can use the && logical operator to perform conditional logic in a more concise way. This is possible because you want to check if a condition is true, and if it is, return some markup. Here's an example: +{condition && <p>markup</p>} +If the condition is true, the markup will be returned. If the condition is false, the operation will immediately return false after evaluating the condition and return nothing. You can include these statements directly in your JSX and string multiple conditions together by writing && after each one. This allows you to handle more complex conditional logic in your render() method without repeating a lot of code. +
    + +## Instructions +
    +Solve the previous example again, so the h1 only renders if display is true, but use the && logical operator instead of an if/else statement. +
    + +## Tests +
    + +```yml +- text: MyComponent should exist and render. + testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(MyComponent)); return mockedComponent.find("MyComponent").length; })(), "MyComponent should exist and render.");' +- text: 'When display is set to true, a div, button, and h1 should render.' + testString: 'async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(MyComponent)); const state_1 = () => { mockedComponent.setState({display: true}); return waitForIt(() => mockedComponent )}; const updated = await state_1(); assert(updated.find("div").length === 1 && updated.find("div").children().length === 2 && updated.find("button").length === 1 && updated.find("h1").length === 1, "When display is set to true, a div, button, and h1 should render."); }; ' +- text: 'When display is set to false, only a div and button should render.' + testString: 'async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const mockedComponent = Enzyme.mount(React.createElement(MyComponent)); const state_1 = () => { mockedComponent.setState({display: false}); return waitForIt(() => mockedComponent )}; const updated = await state_1(); assert(updated.find("div").length === 1 && updated.find("div").children().length === 1 && updated.find("button").length === 1 && updated.find("h1").length === 0, "When display is set to false, only a div and button should render."); }; ' +- text: The render method should use the && logical operator to check the condition of this.state.display. + testString: 'getUserInput => assert(getUserInput("index").includes("&&"), "The render method should use the && logical operator to check the condition of this.state.display.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```jsx +class MyComponent extends React.Component { + constructor(props) { + super(props); + this.state = { + display: true + } + this.toggleDisplay = this.toggleDisplay.bind(this); + } + toggleDisplay() { + this.setState({ + display: !this.state.display + }); + } + render() { + // change code below this line + return ( +
    + +

    Displayed!

    +
    + ); + } +}; +``` + +
    + + +### After Test +
    + +```js +console.info('after the test'); +``` + +
    + +
    + +## Solution +
    + + +```js +class MyComponent extends React.Component { + constructor(props) { + super(props); + this.state = { + display: true + } + this.toggleDisplay = this.toggleDisplay.bind(this); + } + toggleDisplay() { + this.setState({ + display: !this.state.display + }); + } + render() { + // change code below this line + return ( +
    + + {this.state.display &&

    Displayed!

    } +
    + ); + } +}; +``` + +
    diff --git a/curriculum/challenges/03-front-end-libraries/react/Use Advanced JavaScript in React Render Method.md b/curriculum/challenges/03-front-end-libraries/react/Use Advanced JavaScript in React Render Method.md new file mode 100644 index 0000000000..2f115add9e --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/react/Use Advanced JavaScript in React Render Method.md @@ -0,0 +1,195 @@ +--- +id: 5a24c314108439a4d4036183 +title: Use Advanced JavaScript in React Render Method +challengeType: 6 +isRequired: false +--- + +## Description +
    +In previous challenges, you learned how to inject JavaScript code into JSX code using curly braces, { }, for tasks like accessing props, passing props, accessing state, inserting comments into your code, and most recently, styling your components. These are all common use cases to put JavaScript in JSX, but they aren't the only way that you can utilize JavaScript code in your React components. +You can also write JavaScript directly in your render methods, before the return statement, without inserting it inside of curly braces. This is because it is not yet within the JSX code. When you want to use a variable later in the JSX code inside the return statement, you place the variable name inside curly braces. +
    + +## Instructions +
    +In the code provided, the render method has an array that contains 20 phrases to represent the answers found in the classic 1980's Magic Eight Ball toy. The button click event is bound to the ask method, so each time the button is clicked a random number will be generated and stored as the randomIndex in state. On line 52, delete the string "change me!" and reassign the answer const so your code randomly accesses a different index of the possibleAnswers array each time the component updates. Finally, insert the answer const inside the p tags. +
    + +## Tests +
    + +```yml +- text: The MagicEightBall component should exist and should render to the page. + testString: 'assert.strictEqual(Enzyme.mount(React.createElement(MagicEightBall)).find("MagicEightBall").length, 1, "The MagicEightBall component should exist and should render to the page.");' +- text: MagicEightBall's first child should be an input element. + testString: 'assert.strictEqual(Enzyme.mount(React.createElement(MagicEightBall)).children().childAt(0).name(), "input", "MagicEightBall's first child should be an input element.");' +- text: MagicEightBall's third child should be a button element. + testString: 'assert.strictEqual(Enzyme.mount(React.createElement(MagicEightBall)).children().childAt(2).name(), "button", "MagicEightBall's third child should be a button element.");' +- text: MagicEightBall's state should be initialized with a property of userInput and a property of randomIndex both set to a value of an empty string. + testString: 'assert(Enzyme.mount(React.createElement(MagicEightBall)).state("randomIndex") === "" && Enzyme.mount(React.createElement(MagicEightBall)).state("userInput") === "", "MagicEightBall's state should be initialized with a property of userInput and a property of randomIndex both set to a value of an empty string.");' +- text: 'When MagicEightBall is first mounted to the DOM, it should return an empty p element.' + testString: 'assert(Enzyme.mount(React.createElement(MagicEightBall)).find("p").length === 1 && Enzyme.mount(React.createElement(MagicEightBall)).find("p").text() === "", "When MagicEightBall is first mounted to the DOM, it should return an empty p element.");' +- text: 'When text is entered into the input element and the button is clicked, the MagicEightBall component should return a p element that contains a random element from the possibleAnswers array.' + testString: 'async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const comp = Enzyme.mount(React.createElement(MagicEightBall)); const simulate = () => { comp.find("input").simulate("change", { target: { value: "test?" }}); comp.find("button").simulate("click"); }; const result = () => comp.find("p").text(); const _1 = () => { simulate(); return waitForIt(() => result()) }; const _2 = () => { simulate(); return waitForIt(() => result()) }; const _3 = () => { simulate(); return waitForIt(() => result()) }; const _4 = () => { simulate(); return waitForIt(() => result()) }; const _5 = () => { simulate(); return waitForIt(() => result()) }; const _6 = () => { simulate(); return waitForIt(() => result()) }; const _7 = () => { simulate(); return waitForIt(() => result()) }; const _8 = () => { simulate(); return waitForIt(() => result()) }; const _9 = () => { simulate(); return waitForIt(() => result()) }; const _10 = () => { simulate(); return waitForIt(() => result()) }; const _1_val = await _1(); const _2_val = await _2(); const _3_val = await _3(); const _4_val = await _4(); const _5_val = await _5(); const _6_val = await _6(); const _7_val = await _7(); const _8_val = await _8(); const _9_val = await _9(); const _10_val = await _10(); const actualAnswers = [_1_val, _2_val, _3_val, _4_val, _5_val, _6_val, _7_val, _8_val, _9_val, _10_val]; const hasIndex = actualAnswers.filter((answer, i) => possibleAnswers.indexOf(answer) !== -1); const notAllEqual = new Set(actualAnswers); assert(notAllEqual.size > 1 && hasIndex.length === 10, "When text is entered into the input element and the button is clicked, the MagicEightBall component should return a p element that contains a random element from the possibleAnswers array.");}' + +``` + +
    + +## Challenge Seed +
    + +
    + +```jsx +const inputStyle = { + width: 235, + margin: 5 +} + +class MagicEightBall extends React.Component { + constructor(props) { + super(props); + this.state = { + userInput: ", + randomIndex: " + } + this.ask = this.ask.bind(this); + this.handleChange = this.handleChange.bind(this); + } + ask() { + if (this.state.userInput) { + this.setState({ + randomIndex: Math.floor(Math.random() * 20), + userInput: " + }); + } + } + handleChange(event) { + this.setState({ + userInput: event.target.value + }); + } + render() { + const possibleAnswers = [ + 'It is certain', + 'It is decidedly so', + 'Without a doubt', + 'Yes, definitely', + 'You may rely on it', + 'As I see it, yes', + 'Outlook good', + 'Yes', + 'Signs point to yes', + 'Reply hazy try again', + 'Ask again later', + 'Better not tell you now', + 'Cannot predict now', + 'Concentrate and ask again', + 'Don\'t count on it', + 'My reply is no', + 'My sources say no', + 'Most likely', + 'Outlook not so good', + 'Very doubtful' + ]; + const answer = 'change me!' // << change code here + return ( +
    +
    +
    +

    Answer:

    +

    + { /* change code below this line */ } + + { /* change code above this line */ } +

    +
    + ); + } +}; +``` + +
    + + +### After Test +
    + +```js +console.info('after the test'); +``` + +
    + +
    + +## Solution +
    + + +```js +const inputStyle = { + width: 235, + margin: 5 +} + +class MagicEightBall extends React.Component { + constructor(props) { + super(props); + this.state = { + userInput: ", + randomIndex: " + } + this.ask = this.ask.bind(this); + this.handleChange = this.handleChange.bind(this); + } + ask() { + if (this.state.userInput) { + this.setState({ + randomIndex: Math.floor(Math.random() * 20), + userInput: " + }); + } + } + handleChange(event) { + this.setState({ + userInput: event.target.value + }); + } + render() { + const possibleAnswers = [ + "It is certain", "It is decidedly so", "Without a doubt", + "Yes, definitely", "You may rely on it", "As I see it, yes", + "Outlook good", "Yes", "Signs point to yes", "Reply hazy try again", + "Ask again later", "Better not tell you now", "Cannot predict now", + "Concentrate and ask again", "Don't count on it", "My reply is no", + "My sources say no", "Outlook not so good","Very doubtful", "Most likely" + ]; + const answer = possibleAnswers[this.state.randomIndex]; + return ( +
    +
    +
    +

    Answer:

    +

    + {answer} +

    +
    + ); + } +}; +``` + +
    diff --git a/curriculum/challenges/03-front-end-libraries/react/Use Array.filter() to Dynamically Filter an Array.md b/curriculum/challenges/03-front-end-libraries/react/Use Array.filter() to Dynamically Filter an Array.md new file mode 100644 index 0000000000..025033c38c --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/react/Use Array.filter() to Dynamically Filter an Array.md @@ -0,0 +1,163 @@ +--- +id: 5a24c314108439a4d403618c +title: Use Array.filter() to Dynamically Filter an Array +challengeType: 6 +isRequired: false +--- + +## Description +
    +The map array method is a powerful tool that you will use often when working with React. Another method related to map is filter, which filters the contents of an array based on a condition, then returns a new array. For example, if you have an array of users that all have a property online which can be set to true or false, you can filter only those users that are online by writing: +let onlineUsers = users.filter(user => user.online); +
    + +## Instructions +
    +In the code editor, MyComponent's state is initialized with an array of users. Some users are online and some aren't. Filter the array so you see only the users who are online. To do this, first use filter to return a new array containing only the users whose online property is true. Then, in the renderOnline variable, map over the filtered array, and return a li element for each user that contains the text of their username. Be sure to include a unique key as well, like in the last challenges. +
    + +## Tests +
    + +```yml +- text: MyComponent should exist and render to the page. + testString: 'assert.strictEqual(Enzyme.mount(React.createElement(MyComponent)).find("MyComponent").length, 1, "MyComponent should exist and render to the page.");' +- text: MyComponent's state should be initialized to an array of six users.") + testString: 'assert(Array.isArray(Enzyme.mount(React.createElement(MyComponent)).state("users")) === true && Enzyme.mount(React.createElement(MyComponent)).state("users").length === 6, "MyComponent's state should be initialized to an array of six users.");' +- text: 'MyComponent should return a div, an h1, and then an unordered list containing li elements for every user whose online status is set to true.' + testString: 'async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const comp = Enzyme.mount(React.createElement(MyComponent)); const users = (bool) => ({users:[ { username: "Jeff", online: bool }, { username: "Alan", online: bool }, { username: "Mary", online: bool }, { username: "Jim", online: bool }, { username: "Laura", online: bool } ]}); const result = () => comp.find("li").length; const _1 = result(); const _2 = () => { comp.setState(users(true)); return waitForIt(() => result()) }; const _3 = () => { comp.setState(users(false)); return waitForIt(() => result()) }; const _4 = () => { comp.setState({ users: [] }); return waitForIt(() => result()) }; const _2_val = await _2(); const _3_val = await _3(); const _4_val = await _4(); assert(comp.find("div").length === 1 && comp.find("h1").length === 1 && comp.find("ul").length === 1 && _1 === 4 && _2_val === 5 && _3_val === 0 && _4_val === 0, "MyComponent should return a div, an h1, and then an unordered list containing li elements for every user whose online status is set to true."); }; ' +- text: MyComponent should render li elements that contain the username of each online user. + testString: 'async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 250)); const comp = Enzyme.mount(React.createElement(MyComponent)); const users = (bool) => ({users:[ { username: "Jeff", online: bool }, { username: "Alan", online: bool }, { username: "Mary", online: bool }, { username: "Jim", online: bool }, { username: "Laura", online: bool } ]}); const ul = () => { comp.setState(users(true)); return waitForIt(() => comp.find("ul").html()) }; const html = await ul(); assert(html === "
    • Jeff
    • Alan
    • Mary
    • Jim
    • Laura
    ", "MyComponent should render li elements that contain the username of each online user."); }; ' +- text: Each list item element should have a unique key attribute. + testString: 'assert((() => { const ul = Enzyme.mount(React.createElement(MyComponent)).find("ul"); console.log(ul.debug()); const keys = new Set([ ul.childAt(0).key(), ul.childAt(1).key(), ul.childAt(2).key(), ul.childAt(3).key() ]); return keys.size === 4; })(), "Each list item element should have a unique key attribute.");' + +``` + +
    + +## Challenge Seed +
    + +
    + +```jsx +class MyComponent extends React.Component { + constructor(props) { + super(props); + this.state = { + users: [ + { + username: 'Jeff', + online: true + }, + { + username: 'Alan', + online: false + }, + { + username: 'Mary', + online: true + }, + { + username: 'Jim', + online: false + }, + { + username: 'Sara', + online: true + }, + { + username: 'Laura', + online: true + } + ] + } + } + render() { + const usersOnline = null; // change code here + const renderOnline = null; // change code here + return ( +
    +

    Current Online Users:

    +
      + {renderOnline} +
    +
    + ); + } +}; +``` + +
    + + +### After Test +
    + +```js +console.info('after the test'); +``` + +
    + +
    + +## Solution +
    + + +```js +class MyComponent extends React.Component { + constructor(props) { + super(props); + this.state = { + users: [ + { + username: 'Jeff', + online: true + }, + { + username: 'Alan', + online: false + }, + { + username: 'Mary', + online: true + }, + { + username: 'Jim', + online: false + }, + { + username: 'Sara', + online: true + }, + { + username: 'Laura', + online: true + } + ] + } + } + render() { + const usersOnline = this.state.users.filter(user => { + return user.online; + }); + const renderOnlineUsers = usersOnline.map(user => { + return ( +
  • {user.username}
  • + ); + }); + return ( +
    +

    Current Online Users:

    +
      + {renderOnlineUsers} +
    +
    + ); + } +}; +``` + +
    diff --git a/curriculum/challenges/03-front-end-libraries/react/Use Array.map() to Dynamically Render Elements.md b/curriculum/challenges/03-front-end-libraries/react/Use Array.map() to Dynamically Render Elements.md new file mode 100644 index 0000000000..7a1790fd72 --- /dev/null +++ b/curriculum/challenges/03-front-end-libraries/react/Use Array.map() to Dynamically Render Elements.md @@ -0,0 +1,160 @@ +--- +id: 5a24c314108439a4d403618a +title: Use Array.map() to Dynamically Render Elements +challengeType: 6 +isRequired: false +--- + +## Description +
    +Conditional rendering is useful, but you may need your components to render an unknown number of elements. Often in reactive programming, a programmer has no way to know what the state of an application is until runtime, because so much depends on a user's interaction with that program. Programmers need to write their code to correctly handle that unknown state ahead of time. Using Array.map() in React illustrates this concept. +For example, you create a simple "To Do List" app. As the programmer, you have no way of knowing how many items a user might have on their list. You need to set up your component to dynamically render the correct number of list elements long before someone using the program decides that today is laundry day. +
    + +## Instructions +
    +The code editor has most of the MyToDoList component set up. Some of this code should look familiar if you completed the controlled form challenge. You'll notice a textarea and a button, along with a couple of methods that track their states, but nothing is rendered to the page yet. +Inside the constructor, create a this.state object and define two states: userInput should be initialized as an empty string, and toDoList should be initialized as an empty array. Next, delete the comment in the render() method next to the items variable. In its place, map over the toDoList array stored in the component's internal state and dynamically render a li for each item. Try entering the string eat, code, sleep, repeat into the textarea, then click the button and see what happens. +Note: You may know that all sibling child elements created by a mapping operation like this do need to be supplied with a unique key attribute. Don't worry, this is the topic of the next challenge. +
    + +## Tests +
    + +```yml +- text: The MyToDoList component should exist and render to the page. + testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(MyToDoList)); return mockedComponent.find("MyToDoList").length === 1; })(), "The MyToDoList component should exist and render to the page.");' +- text: The first child of MyToDoList should be a textarea element. + testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(MyToDoList)); return mockedComponent.find("MyToDoList").children().childAt(0).type() === "textarea"; })(), "The first child of MyToDoList should be a textarea element.");' +- text: The third child of MyToDoList should be a button element. + testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(MyToDoList)); return mockedComponent.find("MyToDoList").children().childAt(2).type() === "button"; })(), "The third child of MyToDoList should be a button element.");' +- text: The state of MyToDoList should be initialized with toDoList as an empty array. + testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(MyToDoList)); const initialState = mockedComponent.state(); return Array.isArray(initialState.toDoList) === true && initialState.toDoList.length === 0; })(), "The state of MyToDoList should be initialized with toDoList as an empty array.");' +- text: The state of MyToDoList should be initialized with userInput as an empty string. + testString: 'assert((function() { const mockedComponent = Enzyme.mount(React.createElement(MyToDoList)); const initialState = mockedComponent.state(); return typeof initialState.userInput === "string" && initialState.userInput.length === 0; })(), "The state of MyToDoList should be initialized with userInput as an empty string.");' +- text: 'When the Create List button is clicked, the MyToDoList component should dynamically return an unordered list that contains a list item element for every item of a comma-separated list entered into the textarea element.' + testString: 'async () => { const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 100)); const mockedComponent = Enzyme.mount(React.createElement(MyToDoList)); const simulateChange = (el, value) => el.simulate("change", {target: {value}}); const state_1 = () => { return waitForIt(() => mockedComponent.find("ul").find("li"))}; const setInput = () => { return waitForIt(() => simulateChange(mockedComponent.find("textarea"), "testA, testB, testC"))}; const click = () => { return waitForIt(() => mockedComponent.find("button").simulate("click"))}; const state_2 = () => { return waitForIt(() => { const nodes = mockedComponent.find("ul").find("li"); return { nodes, text: nodes.reduce((t, n) => t + n.text(), "") }; })}; const setInput_2 = () => { return waitForIt(() => simulateChange(mockedComponent.find("textarea"), "t1, t2, t3, t4, t5, t6"))}; const click_1 = () => { return waitForIt(() => mockedComponent.find("button").simulate("click"))}; const state_3 = () => { return waitForIt(() => { const nodes = mockedComponent.find("ul").find("li"); return { nodes, text: nodes.reduce((t, n) => t + n.text(), "") }; })}; const awaited_state_1 = await state_1(); const awaited_setInput = await setInput(); const awaited_click = await click(); const awaited_state_2 = await state_2(); const awaited_setInput_2 = await setInput_2(); const awaited_click_1 = await click_1(); const awaited_state_3 = await state_3(); assert(awaited_state_1.length === 0 && awaited_state_2.nodes.length === 3 && awaited_state_3.nodes.length === 6 && awaited_state_2.text === "testA testB testC" && awaited_state_3.text === "t1 t2 t3 t4 t5 t6", "When the Create List button is clicked, the MyToDoList component should dynamically return an unordered list that contains a list item element for every item of a comma-separated list entered into the textarea element."); }; ' + +``` + +
    + +## Challenge Seed +
    + +
    + +```jsx +const textAreaStyles = { + width: 235, + margin: 5 +}; + +class MyToDoList extends React.Component { + constructor(props) { + super(props); + // change code below this line + + // change code above this line + this.handleSubmit = this.handleSubmit.bind(this); + this.handleChange = this.handleChange.bind(this); + } + handleSubmit() { + const itemsArray = this.state.userInput.split(','); + this.setState({ + toDoList: itemsArray + }); + } + handleChange(e) { + this.setState({ + userInput: e.target.value + }); + } + render() { + const items = null; // change code here + return ( +
    +