adding part 4 and 5

softchris-patch-9
chris 2 months ago
parent ff34c52aa7
commit f087f6d7ec

@ -1,47 +1,94 @@
# Creating a game using events
Event-driven programming is the foundation of interactive web applications, and there's no better way to understand it than by building something fun and engaging. In this lesson, you'll create a typing speed game that responds to user interactions in real-time, teaching you how to handle events, manage application state, and create dynamic user experiences.
By building this typing game, you'll discover how web browsers communicate with your JavaScript code through events, and how to write code that responds intelligently to user actions. You'll also learn essential programming patterns that form the backbone of modern web development, from simple button clicks to complex user interfaces.
By the end of this lesson, you'll have created a fully functional typing game and gained the skills to build any interactive web application. Let's dive into the exciting world of event-driven programming and bring your web pages to life!
## Pre-Lecture Quiz
[Pre-lecture quiz](https://ff-quizzes.netlify.app/web/quiz/21)
## Event driven programming
User interaction is what makes web applications come alive, transforming static pages into dynamic, responsive experiences. Understanding how to capture and respond to user actions is fundamental to creating engaging web applications that feel intuitive and professional.
The challenge we face as developers is that we can't predict when users will click buttons, type in text fields, or interact with our interface. This uncertainty requires a different programming approach than the sequential, step-by-step code you might be familiar with.
When creating a browser based application, we provide a graphical user interface (GUI) for the user to use when interacting with what we've built. The most common way to interact with the browser is through clicking and typing in various elements. The challenge we face as a developer is we don't know when they're going to perform these operations!
[Event-driven programming](https://en.wikipedia.org/wiki/Event-driven_programming) is the name for the type of programming we need to do to create our GUI. If we break this phrase down a little bit, we see the core word here is **event**. [Event](https://www.merriam-webster.com/dictionary/event), according to Merriam-Webster, is defined as "something which happens". This describes our situation perfectly. We know something is going to happen for which we want to execute some code in response, but we don't know when it will take place.
The way we mark a section of code we want to execute is by creating a function. When we think about [procedural programming](https://en.wikipedia.org/wiki/Procedural_programming), functions are called in a specific order. This same thing is going to be true with event driven programming. The difference is **how** the functions will be called.
To handle events (button clicking, typing, etc.), we register **event listeners**. An event listener is a function which listens for an event to occur and executes in response. Event listeners can update the UI, make calls to the server, or whatever else needs to be done in response to the user's action. We add an event listener by using [addEventListener](https://developer.mozilla.org/docs/Web/API/EventTarget/addEventListener), and providing a function to execute.
To handle events (button clicking, typing, etc.), we register **event listeners**. An event listener is a function which listens for an event to occur and executes in response. Event listeners can update the UI, make calls to the server, or whatever else needs to be done in response to the user's action. We add an event listener by using `addEventListener()`, and providing a function to execute.
**Here's how event listeners work:**
- **Listens** for specific user actions like clicks, keystrokes, or mouse movements
- **Executes** your custom code when the specified event occurs
- **Responds** immediately to user interactions, creating a seamless experience
- **Handles** multiple events on the same element using different listeners
> **NOTE:** It's worth highlighting there are numerous ways to create event listeners. You can use anonymous functions, or create named ones. You can use various shortcuts, like setting the `click` property, or using `addEventListener`. In our exercise we are going to focus on `addEventListener` and anonymous functions, as it's probably the most common technique web developers use. It's also the most flexible, as `addEventListener` works for all events, and the event name can be provided as a parameter.
> **NOTE:** It's worth highlighting there are numerous ways to create event listeners. You can use anonymous functions, or create named ones. You can use various shortcuts, like setting the `click` property, or using `addEventListener()`. In our exercise we are going to focus on `addEventListener()` and anonymous functions, as it's probably the most common technique web developers use. It's also the most flexible, as `addEventListener()` works for all events, and the event name can be provided as a parameter.
### Common events
While web browsers offer dozens of different events you can listen for, most interactive applications rely on just a handful of essential events. Understanding these core events will give you the foundation to build sophisticated user interactions.
There are [dozens of events](https://developer.mozilla.org/docs/Web/Events) available for you to listen to when creating an application. Basically anything a user does on a page raises an event, which gives you a lot of power to ensure they get the experience you desire. Fortunately, you'll normally only need a small handful of events. Here's a few common ones (including the two we'll use when creating our game):
- [click](https://developer.mozilla.org/docs/Web/API/Element/click_event): The user clicked on something, typically a button or hyperlink
- [contextmenu](https://developer.mozilla.org/docs/Web/API/Element/contextmenu_event): The user clicked the right mouse button
- [select](https://developer.mozilla.org/docs/Web/API/Element/select_event): The user highlighted some text
- [input](https://developer.mozilla.org/docs/Web/API/Element/input_event): The user input some text
| Event | Description | Common Use Cases |
|-------|-------------|------------------|
| `click` | The user clicked on something | Buttons, links, interactive elements |
| `contextmenu` | The user clicked the right mouse button | Custom right-click menus |
| `select` | The user highlighted some text | Text editing, copy operations |
| `input` | The user input some text | Form validation, real-time search |
**Understanding these event types:**
- **Triggers** when users interact with specific elements on your page
- **Provides** detailed information about the user's action through event objects
- **Enables** you to create responsive, interactive web applications
- **Works** consistently across different browsers and devices
## Creating the game
Now that you understand how events work, let's put that knowledge into practice by building something engaging and useful. We'll create a typing speed game that demonstrates event handling while helping you develop a crucial developer skill.
We are going to create a game to explore how events work in JavaScript. Our game is going to test a player's typing skill, which is one of the most underrated skills all developers should have. We should all be practicing our typing! The general flow of the game will look like this:
- Player clicks on start button and is presented with a quote to type
- Player types the quote as quickly as they can in a textbox
- As each word is completed, the next one is highlighted
- If the player has a typo, the textbox is updated to red
- When the player completes the quote, a success message is displayed with the elapsed time
```mermaid
flowchart TD
A[Player clicks Start] --> B[Random quote displays]
B --> C[Player types in textbox]
C --> D{Word complete?}
D -->|Yes| E[Highlight next word]
D -->|No| F{Correct so far?}
F -->|Yes| G[Keep normal styling]
F -->|No| H[Show error styling]
E --> I{Quote complete?}
I -->|No| C
I -->|Yes| J[Show success message with time]
G --> C
H --> C
```
**Here's how our game will work:**
- **Starts** when the player clicks the start button and displays a random quote
- **Tracks** the player's typing progress word by word in real-time
- **Highlights** the current word to guide the player's focus
- **Provides** immediate visual feedback for typing errors
- **Calculates** and displays the total time when the quote is completed
Let's build our game, and learn about events!
### File structure
We're going to need three total files: **index.html**, **script.js** and **style.css**. Let's start by setting those up to make life a little easier for us.
Organizing your project files properly from the start makes development smoother and helps you maintain clean, professional code. Our typing game will follow the standard web development structure that separates content, styling, and behavior.
We're going to need three total files: `index.html`, `script.js` and `style.css`. Let's start by setting those up to make life a little easier for us.
- Create a new folder for your work by opening a console or terminal window and issuing the following command:
**Create a new folder for your work by opening a console or terminal window and issuing the following command:**
```bash
# Linux or macOS
@ -51,29 +98,49 @@ mkdir typing-game && cd typing-game
md typing-game && cd typing-game
```
- Open Visual Studio Code
**Here's what these commands do:**
- **Creates** a new directory called `typing-game` for your project files
- **Navigates** into the newly created directory automatically
- **Sets up** a clean workspace for your game development
**Open Visual Studio Code:**
```bash
code .
```
- Add three files to the folder in Visual Studio Code with the following names:
- index.html
- script.js
- style.css
**This command:**
- **Launches** Visual Studio Code in the current directory
- **Opens** your project folder in the editor
- **Provides** access to all the development tools you'll need
**Add three files to the folder in Visual Studio Code with the following names:**
- `index.html` - Contains the structure and content of your game
- `script.js` - Handles all the game logic and event listeners
- `style.css` - Defines the visual appearance and styling
## Create the user interface
Building a user interface is like creating a blueprint for how users will interact with your application. We need to think about what elements users need to see and interact with, then structure them in a logical, accessible way.
If we explore the requirements, we know we're going to need a handful of elements on our HTML page. This is sort of like a recipe, where we need some ingredients:
- Somewhere to display the quote for the user to type
- Somewhere to display any messages, like a success message
- A textbox for typing
- A start button
| UI Element | Purpose | HTML Element |
|------------|---------|-------------|
| Quote Display | Shows the text to type | `<p>` with `id="quote"` |
| Message Area | Displays status and success messages | `<p>` with `id="message"` |
| Text Input | Where players type the quote | `<input>` with `id="typed-value"` |
| Start Button | Begins the game | `<button>` with `id="start"` |
**Understanding the UI structure:**
- **Organizes** content logically from top to bottom
- **Assigns** unique IDs to elements for JavaScript targeting
- **Provides** clear visual hierarchy for better user experience
- **Includes** semantic HTML elements for accessibility
Each of those will need IDs so we can work with them in our JavaScript. We will also add references to the CSS and JavaScript files we're going to create.
Create a new file named **index.html**. Add the following HTML:
Create a new file named `index.html`. Add the following HTML:
```html
<!-- inside index.html -->
@ -96,26 +163,52 @@ Create a new file named **index.html**. Add the following HTML:
</html>
```
**Breaking down what this HTML structure accomplishes:**
- **Links** the CSS stylesheet in the `<head>` for styling
- **Creates** a clear heading and instructions for users
- **Establishes** placeholder paragraphs with specific IDs for dynamic content
- **Includes** an input field with accessibility attributes
- **Provides** a start button to trigger the game
- **Loads** the JavaScript file at the end for optimal performance
### Launch the application
Testing your application frequently during development helps you catch issues early and see your progress in real-time. Live Server is an invaluable tool that automatically refreshes your browser whenever you save changes, making development much more efficient.
It's always best to develop iteratively to see how things look. Let's launch our application. There's a wonderful extension for Visual Studio Code called [Live Server](https://marketplace.visualstudio.com/items?itemName=ritwickdey.LiveServer&WT.mc_id=academic-77807-sagibbon) which will both host your application locally and refresh the browser each time you save.
- Install [Live Server](https://marketplace.visualstudio.com/items?itemName=ritwickdey.LiveServer&WT.mc_id=academic-77807-sagibbon) by following the link and clicking **Install**
- You will be prompted by the browser to open Visual Studio Code, and then by Visual Studio Code to perform the installation
- Restart Visual Studio Code if prompted
- Once installed, in Visual Studio Code, click Ctrl-Shift-P (or Cmd-Shift-P) to open the command palette
- Type **Live Server: Open with Live Server**
- Live Server will start hosting your application
- Open a browser and navigate to **https://localhost:5500**
- You should now see the page you created!
**Install [Live Server](https://marketplace.visualstudio.com/items?itemName=ritwickdey.LiveServer&WT.mc_id=academic-77807-sagibbon) by following the link and clicking Install:**
**Here's what happens during installation:**
- **Prompts** your browser to open Visual Studio Code
- **Guides** you through the extension installation process
- **May require** restarting Visual Studio Code to complete setup
**Once installed, in Visual Studio Code, click Ctrl-Shift-P (or Cmd-Shift-P) to open the command palette:**
**Understanding the command palette:**
- **Provides** quick access to all VS Code commands
- **Searches** commands as you type
- **Offers** keyboard shortcuts for faster development
**Type "Live Server: Open with Live Server":**
**What Live Server does:**
- **Starts** a local development server for your project
- **Automatically** refreshes the browser when you save files
- **Serves** your files from a local URL (typically `localhost:5500`)
Let's add some functionality.
**Open a browser and navigate to `https://localhost:5500`:**
You should now see the page you created! Let's add some functionality.
## Add the CSS
Visual feedback is essential for creating an intuitive user experience. Our CSS will provide immediate visual cues to help players understand their progress and identify errors quickly.
With our HTML created, let's add the CSS for core styling. We need to highlight the word the player should be typing, and colorize the textbox if what they've typed is incorrect. We'll do this with two classes.
Create a new file named **style.css** and add the following syntax.
Create a new file named `style.css` and add the following syntax.
```css
/* inside style.css */
@ -129,6 +222,12 @@ Create a new file named **style.css** and add the following syntax.
}
```
**Understanding these CSS classes:**
- **Highlights** the current word with a yellow background for clear visual guidance
- **Signals** typing errors with a light coral background color
- **Provides** immediate feedback without disrupting the user's typing flow
- **Uses** contrasting colors for accessibility and clear visual communication
✅ When it comes to CSS you can layout your page however you might like. Take a little time and make the page look more appealing:
- Choose a different font
@ -137,28 +236,43 @@ Create a new file named **style.css** and add the following syntax.
## JavaScript
Now comes the exciting part bringing your game to life with JavaScript! This is where you'll implement all the event handling, game logic, and dynamic behavior that makes your typing game interactive and engaging.
With our UI created, it's time to focus our attention on the JavaScript which will provide the logic. We're going to break this down into a handful of steps:
- [Create the constants](#add-the-constants)
- [Event listener to start the game](#add-start-logic)
- [Event listener to typing](#add-typing-logic)
| Step | Purpose | What You'll Learn |
|------|---------|------------------|
| [Create the constants](#add-the-constants) | Set up quotes and DOM references | Variable management and DOM selection |
| [Event listener to start the game](#add-start-logic) | Handle game initialization | Event handling and UI updates |
| [Event listener to typing](#add-typing-logic) | Process user input in real-time | Input validation and dynamic feedback |
**This structured approach helps you:**
- **Organize** your code into logical, manageable sections
- **Build** functionality incrementally for easier debugging
- **Understand** how different parts of your application work together
- **Create** reusable patterns for future projects
But first, create a new file named **script.js**.
But first, create a new file named `script.js`.
### Add the constants
We're going to need a few items to make our lives a little easier for programming. Again, similar to a recipe, here's what we'll need:
Setting up constants and variables at the beginning of your script creates a solid foundation for your application. This approach makes your code more maintainable and helps prevent errors by establishing clear references to the elements and data you'll use throughout the game.
- Array with the list of all quotes
- Empty array to store all the words for the current quote
- Space to store the index of the word the player is currently typing
- The time the player clicked start
We're going to need a few items to make our lives a little easier for programming. Again, similar to a recipe, here's what we'll need:
We're also going to want references to the UI elements:
| Data Type | Purpose | Example |
|-----------|---------|--------|
| Array of quotes | Store all possible quotes for the game | `['Quote 1', 'Quote 2', ...]` |
| Word array | Break current quote into individual words | `['When', 'you', 'have', ...]` |
| Word index | Track which word player is typing | `0, 1, 2, 3...` |
| Start time | Calculate elapsed time for scoring | `Date.now()` |
- The textbox (**typed-value**)
- The quote display (**quote**)
- The message (**message**)
**We'll also need references to our UI elements:**
| Element | ID | Purpose |
|---------|----|---------|
| Text input | `typed-value` | Where players type |
| Quote display | `quote` | Shows the quote to type |
| Message area | `message` | Displays status updates |
```javascript
// inside script.js
@ -183,9 +297,22 @@ const messageElement = document.getElementById('message');
const typedValueElement = document.getElementById('typed-value');
```
**Breaking down what this setup code accomplishes:**
- **Stores** an array of Sherlock Holmes quotes using `const` since the quotes won't change
- **Initializes** tracking variables with `let` since these values will update during gameplay
- **Captures** references to DOM elements using `document.getElementById()` for efficient access
- **Sets up** the foundation for all game functionality with clear, descriptive variable names
- **Organizes** related data and elements logically for easier code maintenance
✅ Go ahead and add more quotes to your game
> **NOTE:** We can retrieve the elements whenever we want in code by using `document.getElementById`. Because of the fact we're going to refer to these elements on a regular basis we're going to avoid typos with string literals by using constants. Frameworks such as [Vue.js](https://vuejs.org/) or [React](https://reactjs.org/) can help you better manage centralizing your code.
> 💡 **Pro Tip**: We can retrieve the elements whenever we want in code by using `document.getElementById()`. Because of the fact we're going to refer to these elements on a regular basis we're going to avoid typos with string literals by using constants. Frameworks such as [Vue.js](https://vuejs.org/) or [React](https://reactjs.org/) can help you better manage centralizing your code.
>
**Here's why this approach works so well:**
- **Prevents** spelling errors when referencing elements multiple times
- **Improves** code readability with descriptive constant names
- **Enables** better IDE support with autocomplete and error checking
- **Makes** refactoring easier if element IDs change later
Take a minute to watch a video on using `const`, `let` and `var`
@ -195,9 +322,11 @@ Take a minute to watch a video on using `const`, `let` and `var`
### Add start logic
The start button is where the magic begins! This is your first real implementation of event-driven programming, where you'll write code that waits patiently for user interaction and then springs into action.
To begin the game, the player will click on start. Of course, we don't know when they're going to click start. This is where an [event listener](https://developer.mozilla.org/docs/Web/API/EventTarget/addEventListener) comes into play. An event listener will allow us to listen for something to occur (an event) and execute code in response. In our case, we want to execute code when the user clicks on start.
When the user clicks **start**, we need to select a quote, setup the user interface, and setup tracking for the current word and timing. Below is the JavaScript you'll need to add; we discuss it just after the script block.
When the user clicks `start`, we need to select a quote, setup the user interface, and setup tracking for the current word and timing. Below is the JavaScript you'll need to add; we discuss it just after the script block.
```javascript
// at the end of script.js
@ -232,27 +361,35 @@ document.getElementById('start').addEventListener('click', () => {
});
```
Let's break down the code!
- Setup the word tracking
- Using [Math.floor](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Math/floor) and [Math.random](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Math/random) allows us to randomly select a quote from the `quotes` array
- We convert the `quote` into an array of `words` so we can track the word the player is currently typing
- `wordIndex` is set to 0, since the player will start on the first word
- Setup the UI
- Create an array of `spanWords`, which contains each word inside a `span` element
- This will allow us to highlight the word on the display
- `join` the array to create a string which we can use to update the `innerHTML` on `quoteElement`
- This will display the quote to the player
- Set the `className` of the first `span` element to `highlight` to highlight it as yellow
- Clean the `messageElement` by setting `innerText` to `''`
- Setup the textbox
- Clear the current `value` on `typedValueElement`
- Set the `focus` to `typedValueElement`
- Start the timer by calling `getTime`
**Let's break down the code into logical sections:**
**📊 Word Tracking Setup:**
- **Selects** a random quote using `Math.floor()` and `Math.random()` for variety
- **Converts** the quote into an array of individual words using `split(' ')`
- **Resets** the `wordIndex` to 0 since players start with the first word
- **Prepares** the game state for a fresh round
**🎨 UI Setup and Display:**
- **Creates** an array of `<span>` elements, wrapping each word for individual styling
- **Joins** the span elements into a single string for efficient DOM updating
- **Highlights** the first word by adding the `highlight` CSS class
- **Clears** any previous game messages to provide a clean slate
**⌨️ Textbox Preparation:**
- **Clears** any existing text in the input field
- **Sets focus** to the textbox so players can start typing immediately
- **Prepares** the input area for the new game session
**⏱️ Timer Initialization:**
- **Captures** the current timestamp using `new Date().getTime()`
- **Enables** accurate calculation of typing speed and completion time
- **Starts** the performance tracking for the game session
### Add typing logic
As the player types, an `input` event will be raised. This event listener will check to ensure the player is typing the word correctly, and handle the current status of the game. Returning to **script.js**, add the following code to the end. We will break it down afterwards.
Now for the most complex and interesting part of our game handling real-time typing input! This event listener will process every keystroke, provide immediate feedback, and manage the game's progression through the quote.
As the player types, an `input` event will be raised. This event listener will check to ensure the player is typing the word correctly, and handle the current status of the game. Returning to `script.js`, add the following code to the end. We will break it down afterwards.
```javascript
// at the end of script.js
@ -291,30 +428,68 @@ typedValueElement.addEventListener('input', () => {
});
```
Let's break down the code! We start by grabbing the current word and the value the player has typed thus far. Then we have waterfall logic, where we check if the quote is complete, the word is complete, the word is correct, or (finally), if there is an error.
- Quote is complete, indicated by `typedValue` being equal to `currentWord`, and `wordIndex` being equal to one less than the `length` of `words`
- Calculate `elapsedTime` by subtracting `startTime` from the current time
- Divide `elapsedTime` by 1,000 to convert from milliseconds to seconds
- Display a success message
- Word is complete, indicated by `typedValue` ending with a space (the end of a word) and `typedValue` being equal to `currentWord`
- Set `value` on `typedElement` to be `''` to allow for the next word to be typed
- Increment `wordIndex` to move to the next word
- Loop through all `childNodes` of `quoteElement` to set `className` to `''` to revert to default display
- Set `className` of the current word to `highlight` to flag it as the next word to type
- Word is currently typed correctly (but not complete), indicated by `currentWord` started with `typedValue`
- Ensure `typedValueElement` is displayed as default by clearing `className`
- If we made it this far, we have an error
- Set `className` on `typedValueElement` to `error`
**Understanding the typing logic flow:**
This function uses a waterfall approach, checking conditions from most specific to most general. Let's break down each scenario:
```mermaid
flowchart TD
A[Player types character] --> B[Get current word and typed value]
B --> C{Quote complete?}
C -->|Yes| D[Show completion message with time]
C -->|No| E{Word complete with space?}
E -->|Yes| F[Clear input, move to next word, update highlight]
E -->|No| G{Typing correctly so far?}
G -->|Yes| H[Remove error styling]
G -->|No| I[Show error styling]
```
**🏁 Quote Complete (Scenario 1):**
- **Checks** if typed value matches current word AND we're on the last word
- **Calculates** elapsed time by subtracting start time from current time
- **Converts** milliseconds to seconds by dividing by 1,000
- **Displays** congratulatory message with completion time
**✅ Word Complete (Scenario 2):**
- **Detects** word completion when input ends with a space
- **Validates** that trimmed input matches the current word exactly
- **Clears** the input field for the next word
- **Advances** to the next word by incrementing `wordIndex`
- **Updates** visual highlighting by removing all classes and highlighting the new word
**📝 Typing in Progress (Scenario 3):**
- **Verifies** that the current word starts with what's been typed so far
- **Removes** any error styling to show the input is correct
- **Allows** continued typing without interruption
**❌ Error State (Scenario 4):**
- **Triggers** when typed text doesn't match the expected word beginning
- **Applies** error CSS class to provide immediate visual feedback
- **Helps** players quickly identify and correct mistakes
## Test your application
Congratulations! You've built a complete typing game using event-driven programming. Testing is a crucial part of development it's where you'll discover how your application behaves in real-world use and identify any areas for improvement.
You've made it to the end! The last step is to ensure our application works. Give it a shot! Don't worry if there are errors; **all developers** have errors. Examine the messages and debug as needed.
Click on **start**, and start typing away! It should look a little like the animation we saw before.
Click on `start`, and start typing away! It should look a little like the animation we saw before.
![Animation of the game in action](../images/demo.gif)
**What to test in your application:**
- **Verifies** that clicking Start displays a random quote
- **Confirms** that typing highlights the current word correctly
- **Checks** that error styling appears for incorrect typing
- **Ensures** that completing words advances the highlight properly
- **Tests** that finishing the quote shows the completion message with timing
**Common debugging tips:**
- **Check** the browser console (F12) for JavaScript errors
- **Verify** that all file names match exactly (case-sensitive)
- **Ensure** Live Server is running and refreshing properly
- **Test** different quotes to verify the random selection works
---
## GitHub Copilot Agent Challenge 🎮
@ -334,12 +509,22 @@ Add the necessary HTML elements, CSS styles, and JavaScript functions to impleme
## 🚀 Challenge
Add more functionality
Ready to take your typing game to the next level? Try implementing these advanced features to deepen your understanding of event handling and DOM manipulation:
**Add more functionality:**
| Feature | Description | Skills You'll Practice |
|---------|-------------|------------------------|
| **Input Control** | Disable the `input` event listener on completion, and re-enable it when the button is clicked | Event management and state control |
| **UI State Management** | Disable the textbox when the player completes the quote | DOM property manipulation |
| **Modal Dialog** | Display a modal dialog box with the success message | Advanced UI patterns and accessibility |
| **High Score System** | Store high scores using `localStorage` | Browser storage APIs and data persistence |
- Disable the `input` event listener on completion, and re-enable it when the button is clicked
- Disable the textbox when the player completes the quote
- Display a modal dialog box with the success message
- Store high scores using [localStorage](https://developer.mozilla.org/docs/Web/API/Window/localStorage)
**Implementation tips:**
- **Research** `localStorage.setItem()` and `localStorage.getItem()` for persistent storage
- **Practice** adding and removing event listeners dynamically
- **Explore** HTML dialog elements or CSS modal patterns
- **Consider** accessibility when disabling and enabling form controls
## Post-Lecture Quiz

@ -2,11 +2,40 @@
## Instructions
Create a small game that uses keyboard events to do tasks. It may be a different kind of typing game, or an art type game that paints pixels to the screen on keystrokes. Get creative!
Now that you've mastered the fundamentals of event-driven programming with the typing game, it's time to unleash your creativity! You'll design and build your own keyboard-based game that demonstrates your understanding of event handling, DOM manipulation, and user interaction patterns.
Create a small game that uses keyboard events to accomplish specific tasks. This could be a different kind of typing game, an art application that paints pixels to the screen on keystrokes, a simple arcade-style game controlled with arrow keys, or any other creative concept you can imagine. Get creative and think about how different keys can trigger different behaviors!
**Your game should include:**
| Requirement | Description | Purpose |
|-------------|-------------|---------|
| **Event Listeners** | Respond to at least 3 different keyboard events | Demonstrate understanding of event handling |
| **Visual Feedback** | Provide immediate visual response to user input | Show mastery of DOM manipulation |
| **Game Logic** | Include scoring, levels, or progression mechanics | Practice implementing application state |
| **User Interface** | Clear instructions and intuitive controls | Develop user experience design skills |
**Creative project ideas to consider:**
- **Rhythm Game**: Players press keys in time with music or visual cues
- **Pixel Art Creator**: Different keys paint different colors or patterns
- **Word Builder**: Players create words by typing letters in specific orders
- **Snake Game**: Control a snake with arrow keys to collect items
- **Music Synthesizer**: Different keys play different musical notes or sounds
- **Speed Typing Variants**: Category-specific typing (programming terms, foreign languages)
- **Keyboard Drummer**: Create beats by mapping keys to different drum sounds
**Implementation guidelines:**
- **Start** with a simple concept and build complexity gradually
- **Focus** on smooth, responsive controls that feel natural
- **Include** clear visual indicators for game state and player progress
- **Test** your game with different users to ensure intuitive gameplay
- **Document** your code with comments explaining your event handling strategy
## Rubric
| Criteria | Exemplary | Adequate | Needs Improvement |
| -------- | ------------------------ | ------------------------ | ----------------- |
| | A full game is presented | The game is very minimal | The game has bugs |
| | | | |
| Criteria | Exemplary | Adequate | Needs Improvement |
| -------- | --------- | -------- | ----------------- |
| **Functionality** | A complete, polished game with multiple features and smooth gameplay | A working game with basic features that demonstrates keyboard event handling | A minimal implementation with limited functionality or significant bugs |
| **Code Quality** | Well-organized, commented code following best practices with efficient event handling | Clean, readable code with appropriate use of event listeners and DOM manipulation | Basic code structure with some organization issues or inefficient implementations |
| **User Experience** | Intuitive controls, clear feedback, and engaging gameplay that feels professional | Functional interface with adequate user guidance and responsive controls | Basic interface with unclear instructions or poor responsiveness |
| **Creativity** | Original concept with innovative use of keyboard events and creative problem-solving | Interesting variation on common game patterns with good use of event handling | Simple implementation of a basic concept with minimal creative elements |

@ -9,140 +9,286 @@
### Introduction
Browser extensions add additional functionality to a browser. But before you build one, you should learn a little about how browsers do their work.
Browser extensions are powerful tools that enhance your browsing experience by adding custom functionality directly to your web browser. Think of them as mini-applications that live inside your browser, ready to help you with specific tasks whenever you need them. From password managers to color pickers, extensions transform how you interact with the web.
### About the browser
Before you dive into building your own extension, it's essential to understand how browsers work behind the scenes. This knowledge will help you create more effective extensions and understand how they integrate with the browser's core functionality.
In this series of lessons, you'll learn how to build a browser extension that will work on Chrome, Firefox and Edge browsers. In this part, you'll discover how browsers work and scaffold out the elements of the browser extension.
In this lesson, you'll discover the inner workings of web browsers, learn about different browser architectures, and start building your first browser extension. By the end, you'll have a solid foundation for creating extensions that work across multiple browsers and provide real value to users.
But what is a browser exactly? It is a software application that allows an end user to access content from a server and display it on web pages.
## Understanding Web Browsers
✅ A little history: the first browser was called 'WorldWideWeb' and was created by Sir Timothy Berners-Lee in 1990.
Let's start by understanding what browsers are and how they work. This foundation will help you build better extensions that integrate seamlessly with browser functionality.
A web browser is a sophisticated software application that acts as your gateway to the internet. It takes web addresses (URLs), retrieves content from web servers around the world, and transforms that content into the interactive web pages you see and use every day.
**A little history**: The first browser was called 'WorldWideWeb' and was created by Sir Timothy Berners-Lee in 1990.
![early browsers](images/earlybrowsers.jpg)
> Some early browsers, via [Karen McGrane](https://www.slideshare.net/KMcGrane/week-4-ixd-history-personal-computing)
When a user connected to the internet using a URL (Uniform Resource Locator) address, usually using Hypertext Transfer Protocol via an `http` or `https` address, the browser communicates with a web server and fetches a web page.
### How Browsers Process Web Content
When you type a URL into your browser's address bar, here's what happens behind the scenes:
```mermaid
sequenceDiagram
participant User
participant Browser
participant DNS
participant Server
User->>Browser: Types URL and presses Enter
Browser->>DNS: Looks up server IP address
DNS->>Browser: Returns IP address
Browser->>Server: Requests web page content
Server->>Browser: Sends HTML, CSS, and JavaScript
Browser->>User: Renders complete web page
```
**Here's what this process accomplishes:**
- **Translates** the human-readable URL into a server IP address through DNS lookup
- **Establishes** a secure connection with the web server using HTTP or HTTPS protocols
- **Requests** the specific web page content from the server
- **Receives** HTML markup, CSS styling, and JavaScript code from the server
- **Renders** all content into the interactive web page you see
### Browser Core Features
Modern browsers provide several essential features that extensions can leverage:
| Feature | Purpose | Extension Opportunities |
|---------|---------|------------------------|
| **Rendering Engine** | Displays HTML, CSS, and JavaScript | Content modification, styling injection |
| **JavaScript Engine** | Executes JavaScript code | Custom scripts, API interactions |
| **Local Storage** | Saves data locally | User preferences, cached data |
| **Network Stack** | Handles web requests | Request monitoring, data analysis |
| **Security Model** | Protects users from malicious content | Content filtering, security enhancements |
**Understanding these features helps you:**
- **Identify** where your extension can add the most value
- **Choose** the right browser APIs for your extension's functionality
- **Design** extensions that work efficiently with browser systems
- **Ensure** your extension follows browser security best practices
### Cross-Browser Development Considerations
Each browser has its own strengths, quirks, and capabilities. As an extension developer, you'll need to consider these differences:
At this point, the browser's rendering engine displays it on the user's device, which might be a mobile phone, desktop, or laptop.
> 💡 **Pro Tip**: Use [caniuse.com](https://www.caniuse.com) to check which web technologies are supported across different browsers. This is invaluable when planning your extension's features!
Browsers also have the ability to cache content so that it doesn't have to be retrieved from the server every time. They can record the history of a user's browsing activity, store 'cookies', which are small bits of data that contain information used to store a user's activity, and more.
**Key considerations for extension development:**
- **Test** your extension across Chrome, Firefox, and Edge browsers
- **Adapt** to different browser extension APIs and manifest formats
- **Handle** varying performance characteristics and limitations
- **Provide** fallbacks for browser-specific features that may not be available
A really important thing to remember about browsers is that they are not all the same! Each browser has its strengths and weaknesses, and a professional web developer needs to understand how to make web pages perform well cross-browser. This includes handling small viewports such as a mobile phone's, as well as a user who is offline.
**Analytics Insight**: You can determine which browsers your users prefer by installing analytics packages in your web development projects. This data helps you prioritize which browsers to support first.
A really useful website that you probably should bookmark in whatever browser you prefer to use is [caniuse.com](https://www.caniuse.com). When you are building web pages, it's very helpful to use caniuse's lists of supported technologies so that you can best support your users.
## Understanding Browser Extensions
✅ How can you tell what browsers are most popular with your web site's user base? Check your analytics - you can install various analytics packages as part of your web development process, and they will tell you what browsers are most used by the various popular browsers.
Browser extensions solve real problems by adding specialized functionality exactly where you need it most. Unlike standalone applications, extensions integrate directly into your browsing experience, providing instant access to tools and features without interrupting your workflow.
## Browser extensions
Think about the repetitive tasks you do while browsing the web. Maybe you frequently need to check color codes on websites, save articles for later reading, or translate text from other languages. Extensions excel at automating these common tasks and making them accessible with just a click.
Why would you want to build a browser extension? It's a handy thing to attach to your browser when you need quick access to tasks that you tend to repeat. For example, if you find yourself needing to check colors on the various web pages that you interact with, you might install a color-picker browser extension. If you have trouble remembering passwords, you might use a password-management browser extension.
**Popular extension categories and their benefits:**
- **Productivity Tools**: Task managers, note-taking apps, and time trackers that help you stay organized
- **Security Enhancements**: Password managers, ad blockers, and privacy tools that protect your data
- **Developer Tools**: Code formatters, color pickers, and debugging utilities that streamline development
- **Content Enhancement**: Reading modes, video downloaders, and screenshot tools that improve your web experience
Browser extensions are fun to develop, too. They tend to manage a finite number of tasks that they perform well.
**Reflection Question**: What are your favorite browser extensions? What specific tasks do they perform, and how do they improve your browsing experience?
✅ What are your favorite browser extensions? What tasks do they perform?
## Installing and Managing Extensions
### Installing extensions
Before diving into development, let's understand how extensions are installed and managed. This knowledge will help you test your extensions and understand the user experience.
Before you start building, take a look at the process of building and deploying a browser extension. While each browser varies a bit in how they manage this task, the process is similar on Chrome and Firefox to this example on Edge:
The extension installation process is similar across all modern browsers, though each has slight variations in their interface and terminology.
![screenshot of the Edge browser showing the open edge://extensions page and open settings menu](images/install-on-edge.png)
> Note: Make sure to toggle on developer mode and allow extension from other stores.
> **Important**: Make sure to toggle on developer mode and allow extensions from other stores when testing your own extensions.
In essence, the process will be:
### Development Extension Installation Process
- build your extension using `npm run build`
- navigate in the browser to the extensions pane using the "Settings and more" button (the `...` icon) on the top right
- if it's a new installation, choose `load unpacked` to upload a fresh extension from its build folder (in our case it is `/dist`)
- or, click `reload` if you are reloading the already-installed extension
When you're developing and testing your own extensions, follow this workflow:
✅ These instructions pertain to extensions you build yourself; to install extensions that have been released to the browser extension store associated to each browser, you should navigate to those [stores](https://microsoftedge.microsoft.com/addons/Microsoft-Edge-Extensions-Home) and install the extension of your choice.
```bash
# Step 1: Build your extension
npm run build
```
### Get Started
**What this command accomplishes:**
- **Compiles** your source code into browser-ready files
- **Bundles** JavaScript modules into optimized packages
- **Generates** the final extension files in the `/dist` folder
- **Prepares** your extension for installation and testing
You're going to build a browser extension that displays your region's carbon footprint, showing your region's energy usage and the source of the energy. The extension will have a form that collects an API key so that you can access
CO2 Signal's API.
**Step 2: Navigate to Browser Extensions**
1. **Open** your browser's extensions management page
2. **Click** the "Settings and more" button (the `...` icon) on the top right
3. **Select** "Extensions" from the dropdown menu
**You need:**
**Step 3: Load Your Extension**
- **For new installations**: Choose `load unpacked` and select your `/dist` folder
- **For updates**: Click `reload` next to your already-installed extension
- **For testing**: Enable "Developer mode" to access additional debugging features
- [an API key](https://www.co2signal.com/); enter your email in the box on this page and one will be sent to you
- the [code for your region](http://api.electricitymap.org/v3/zones) corresponding to the [Electricity Map](https://www.electricitymap.org/map) (in Boston, for example, I use 'US-NEISO').
- the [starter code](../start). Download the `start` folder; you will be completing code in this folder.
- [NPM](https://www.npmjs.com) - NPM is a package management tool; install it locally and the packages listed in your `package.json` file will be installed for use by your web asset
### Production Extension Installation
✅ Learn more about package management in this [excellent Learn module](https://docs.microsoft.com/learn/modules/create-nodejs-project-dependencies/?WT.mc_id=academic-77807-sagibbon)
> ✅ **Note**: These development instructions are specifically for extensions you build yourself. To install published extensions, visit the official browser extension stores like the [Microsoft Edge Add-ons store](https://microsoftedge.microsoft.com/addons/Microsoft-Edge-Extensions-Home).
Take a minute to look through the codebase:
**Understanding the difference:**
- **Development installations** let you test unpublished extensions during development
- **Store installations** provide vetted, published extensions with automatic updates
- **Sideloading** allows installation of extensions from outside official stores (requires developer mode)
dist
-|manifest.json (defaults set here)
-|index.html (front-end HTML markup here)
-|background.js (background JS here)
-|main.js (built JS)
src
-|index.js (your JS code goes here)
## Building Your Carbon Footprint Extension
✅ Once you have your API key and Region code handy, store those somewhere in a note for future use.
Now it's time to start building! You'll create a browser extension that displays your region's carbon footprint by showing local energy usage and sources. This practical project will teach you the fundamentals of extension development while creating something genuinely useful.
### Build the HTML for the extension
Your extension will help users understand their environmental impact by providing real-time data about their region's energy consumption and carbon emissions. This type of awareness tool is increasingly important as we all work toward more sustainable digital habits.
This extension has two views. One to gather the API key and region code:
### Project Requirements
![screenshot of the completed extension open in a browser, displaying a form with inputs for region name and API key.](images/1.png)
Before you begin coding, gather these essential resources:
**Required API Access:**
- **[CO2 Signal API key](https://www.co2signal.com/)**: Enter your email address to receive your free API key
- **[Region code](http://api.electricitymap.org/v3/zones)**: Find your region code using the [Electricity Map](https://www.electricitymap.org/map) (for example, Boston uses 'US-NEISO')
**Development Tools:**
- **[Node.js and NPM](https://www.npmjs.com)**: Package management tool for installing project dependencies
- **[Starter code](../start)**: Download the `start` folder to begin development
**Learn More**: Enhance your package management skills with this [comprehensive Learn module](https://docs.microsoft.com/learn/modules/create-nodejs-project-dependencies/?WT.mc_id=academic-77807-sagibbon)
### Understanding the Project Structure
Let's explore the extension's file organization to understand how the pieces fit together:
```
project-root/
├── dist/ # Built extension files
│ ├── manifest.json # Extension configuration
│ ├── index.html # User interface markup
│ ├── background.js # Background script functionality
│ └── main.js # Compiled JavaScript bundle
└── src/ # Source development files
└── index.js # Your main JavaScript code
```
And the second to display the region's carbon usage:
**Breaking down what each file accomplishes:**
- **`manifest.json`**: **Defines** extension metadata, permissions, and entry points
- **`index.html`**: **Creates** the user interface that appears when users click your extension
- **`background.js`**: **Handles** background tasks and browser event listeners
- **`main.js`**: **Contains** the final bundled JavaScript after the build process
- **`src/index.js`**: **Houses** your main development code that gets compiled into `main.js`
> 💡 **Organization Tip**: Store your API key and region code in a secure note for easy reference during development. You'll need these values to test your extension's functionality.
**Security Note**: Never commit API keys or sensitive credentials to your code repository. We'll show you how to handle these securely in the next steps.
## Creating the Extension Interface
Your extension will have two main views that provide a complete user experience. Let's build these interfaces step by step, understanding how each component contributes to the overall functionality.
The first view collects user configuration data, while the second displays the carbon footprint information. This two-step approach ensures users can easily set up and then use your extension.
### Extension Views Overview
**Setup View** - First-time user configuration:
![screenshot of the completed extension open in a browser, displaying a form with inputs for region name and API key.](images/1.png)
**Results View** - Carbon footprint data display:
![screenshot of the completed extension displaying values for carbon usage and fossil fuel percentage for the US-NEISO region.](images/2.png)
Let's start by building the HTML for the form and styling it with CSS.
### Building the Configuration Form
In the `/dist` folder, you will build a form and a result area. In the `index.html` file, populate the delineated form area:
Let's start by creating the user input form. This form will collect the API key and region code, then save them to the browser's local storage for future use.
```HTML
In the `/dist/index.html` file, add this form structure:
```html
<form class="form-data" autocomplete="on">
<div>
<h2>New? Add your Information</h2>
</div>
<div>
<label for="region">Region Name</label>
<input type="text" id="region" required class="region-name" />
</div>
<div>
<label for="api">Your API Key from tmrow</label>
<input type="text" id="api" required class="api-key" />
</div>
<button class="search-btn">Submit</button>
</form>
<div>
<h2>New? Add your Information</h2>
</div>
<div>
<label for="region">Region Name</label>
<input type="text" id="region" required class="region-name" />
</div>
<div>
<label for="api">Your API Key from tmrow</label>
<input type="text" id="api" required class="api-key" />
</div>
<button class="search-btn">Submit</button>
</form>
```
This is the form where your saved information will be input and saved to local storage.
Next, create the results area; under the final form tag, add some divs:
**Here's what this form accomplishes:**
- **Creates** a semantic form structure with proper labels and input associations
- **Enables** browser autocomplete functionality for improved user experience
- **Requires** both fields to be filled before submission using the `required` attribute
- **Organizes** inputs with descriptive class names for easy styling and JavaScript targeting
- **Provides** clear instructions for users who are setting up the extension for the first time
### Building the Results Display
```HTML
Next, create the results area that will show the carbon footprint data. Add this HTML below the form:
```html
<div class="result">
<div class="loading">loading...</div>
<div class="errors"></div>
<div class="data"></div>
<div class="result-container">
<p><strong>Region: </strong><span class="my-region"></span></p>
<p><strong>Carbon Usage: </strong><span class="carbon-usage"></span></p>
<p><strong>Fossil Fuel Percentage: </strong><span class="fossil-fuel"></span></p>
</div>
<button class="clear-btn">Change region</button>
<div class="loading">loading...</div>
<div class="errors"></div>
<div class="data"></div>
<div class="result-container">
<p><strong>Region: </strong><span class="my-region"></span></p>
<p><strong>Carbon Usage: </strong><span class="carbon-usage"></span></p>
<p><strong>Fossil Fuel Percentage: </strong><span class="fossil-fuel"></span></p>
</div>
<button class="clear-btn">Change region</button>
</div>
```
At this point, you can try a build. Make sure to install the package dependencies of this extension:
```
**Breaking down what this structure provides:**
- **`loading`**: **Displays** a loading message while API data is being fetched
- **`errors`**: **Shows** error messages if API calls fail or data is invalid
- **`data`**: **Holds** raw data for debugging purposes during development
- **`result-container`**: **Presents** formatted carbon footprint information to users
- **`clear-btn`**: **Allows** users to change their region and reconfigure the extension
### Setting Up the Build Process
Now let's install the project dependencies and test the build process:
```bash
npm install
```
This command will use npm, the Node Package Manager, to install webpack for your extension's build process. Webpack is a bundler that handles compiling code. You can see the output of this process by looking in `/dist/main.js` - you see the code has been bundled.
**What this installation process accomplishes:**
- **Downloads** Webpack and other development dependencies specified in `package.json`
- **Configures** the build toolchain for compiling modern JavaScript
- **Prepares** the development environment for extension building and testing
- **Enables** code bundling, optimization, and cross-browser compatibility features
> 💡 **Build Process Insight**: Webpack bundles your source code from `/src/index.js` into `/dist/main.js`. This process optimizes your code for production and ensures browser compatibility.
### Testing Your Progress
At this point, you can test your extension:
1. **Run** the build command to compile your code
2. **Load** the extension into your browser using the developer mode
3. **Verify** that the form displays correctly and looks professional
4. **Check** that all form elements are properly aligned and functional
For now, the extension should build and, if you deploy it into Edge as an extension, you'll see a form neatly displayed.
**You've successfully:**
- **Built** the foundational HTML structure for your extension
- **Created** both configuration and results interfaces
- **Set up** the development workflow with modern build tools
- **Prepared** your extension for the next phase of JavaScript functionality
Congratulations, you've taken the first steps towards building a browser extension. In subsequent lessons, you'll make it more functional and useful.
Congratulations! You've completed the first major milestone in browser extension development. In the upcoming lessons, you'll add JavaScript functionality to make your extension fully interactive and useful.
## GitHub Copilot Agent Challenge 🚀

@ -1,11 +1,130 @@
# Restyle your Extension
# Assignment: Restyle Your Browser Extension
## Overview
Now that you've built the HTML structure for your carbon footprint browser extension, it's time to make it visually appealing and user-friendly. Great design enhances the user experience and makes your extension more professional and engaging.
Your extension comes with basic CSS styling, but this assignment challenges you to create a unique visual identity that reflects your personal style while maintaining excellent usability.
## Instructions
The codebase for this extension comes complete with styles, but you don't have to use them; make your extension your own by restyling it by editing its css file.
### Part 1: Analyze the Current Design
Before making changes, examine the existing CSS structure:
1. **Locate** the CSS files in your extension project
2. **Review** the current styling approach and color scheme
3. **Identify** areas for improvement in layout, typography, and visual hierarchy
4. **Consider** how the design supports user goals (easy form completion and clear data display)
### Part 2: Design Your Custom Styling
Create a cohesive visual design that includes:
**Color Scheme:**
- Choose a primary color palette that reflects environmental themes
- Ensure sufficient contrast for accessibility (use tools like WebAIM's contrast checker)
- Consider how colors will look across different browser themes
**Typography:**
- Select readable fonts that work well at small extension sizes
- Establish a clear hierarchy with appropriate font sizes and weights
- Ensure text remains legible in both light and dark browser themes
**Layout and Spacing:**
- Improve the visual organization of form elements and data display
- Add appropriate padding and margins for better readability
- Consider responsive design principles for different screen sizes
### Part 3: Implement Your Design
Modify the CSS files to implement your design:
```css
/* Example starting points for customization */
.form-data {
/* Style the configuration form */
background: /* your choice */;
padding: /* your spacing */;
border-radius: /* your preference */;
}
.result-container {
/* Style the data display area */
background: /* complementary color */;
border: /* your border style */;
margin: /* your spacing */;
}
/* Add your custom styles here */
```
**Key areas to style:**
- **Form elements**: Input fields, labels, and submit button
- **Results display**: Data container, text styling, and loading states
- **Interactive elements**: Hover effects, button states, and transitions
- **Overall layout**: Container spacing, background colors, and visual hierarchy
### Part 4: Test and Refine
1. **Build** your extension with `npm run build`
2. **Load** the updated extension into your browser
3. **Test** all visual states (form entry, loading, results display, errors)
4. **Verify** accessibility with browser developer tools
5. **Refine** your styles based on actual usage
## Creative Challenges
### Basic Level
- Update colors and fonts to create a cohesive theme
- Improve spacing and alignment throughout the interface
- Add subtle hover effects to interactive elements
### Intermediate Level
- Design custom icons or graphics for your extension
- Implement smooth transitions between different states
- Create a unique loading animation for API calls
### Advanced Level
- Design multiple theme options (light/dark/high-contrast)
- Implement responsive design for different browser window sizes
- Add micro-interactions that enhance the user experience
## Submission Guidelines
Your completed assignment should include:
- **Modified CSS files** with your custom styling
- **Screenshots** showing your extension in different states (form, loading, results)
- **Brief description** (2-3 sentences) explaining your design choices and how they improve the user experience
## Assessment Rubric
| Criteria | Exemplary (4) | Proficient (3) | Developing (2) | Beginning (1) |
|----------|---------------|----------------|----------------|----------------|
| **Visual Design** | Creative, cohesive design that enhances usability and reflects strong design principles | Good design choices with consistent styling and clear visual hierarchy | Basic design improvements with some consistency issues | Minimal styling changes or inconsistent design |
| **Functionality** | All styles work perfectly across different states and browser environments | Styles work well with minor issues in edge cases | Most styles functional with some display problems | Significant styling issues that impact usability |
| **Code Quality** | Clean, well-organized CSS with meaningful class names and efficient selectors | Good CSS structure with appropriate use of selectors and properties | Acceptable CSS with some organization issues | Poor CSS structure or overly complex styling |
| **Accessibility** | Excellent color contrast, readable fonts, and consideration for users with disabilities | Good accessibility practices with minor areas for improvement | Basic accessibility considerations with some issues | Limited attention to accessibility requirements |
## Tips for Success
> 💡 **Design Tip**: Start with subtle changes and build up to more dramatic styling. Small improvements in typography and spacing often have big impacts on perceived quality.
**Best practices to follow:**
- **Test** your extension in both light and dark browser themes
- **Use** relative units (em, rem) for better scalability
- **Maintain** consistent spacing using CSS custom properties
- **Consider** how your design will look to users with different visual needs
- **Validate** your CSS to ensure it follows proper syntax
> ⚠️ **Common Mistake**: Don't sacrifice usability for visual appeal. Your extension should be both beautiful and functional.
## Rubric
**Remember to:**
- **Keep** important information easily readable
- **Ensure** buttons and interactive elements are easy to click
- **Maintain** clear visual feedback for user actions
- **Test** your design with real data, not just placeholder text
| Criteria | Exemplary | Adequate | Needs Improvement |
| -------- | -------------------------------------------- | --------------------- | ----------------- |
| | Code is submitted with functional new styles | Styling is incomplete | Styles are buggy |
Good luck creating a browser extension that's both functional and visually stunning!

@ -4,19 +4,23 @@
[Pre-lecture quiz](https://ff-quizzes.netlify.app/web/quiz/25)
### Introduction
## Introduction
In this lesson, you'll call an API by submitting your browser extension's form and displaying the results in your browser extension. In addition, you'll learn about how you can store data in your browser's local storage for future reference and use.
Now that you've built the foundation of your browser extension with HTML and CSS, it's time to bring it to life with dynamic functionality. In this lesson, you'll transform your static form into an interactive tool that communicates with external APIs and intelligently stores data for future use.
API integration is a cornerstone skill in modern web development. Whether you're fetching weather data, user profiles, or carbon emission statistics like we'll do today, understanding how to work with APIs opens up endless possibilities for your applications. You'll also discover how browser storage works behind the scenes, allowing your extension to remember user preferences and data even after closing and reopening.
By the end of this lesson, you'll have a fully functional browser extension that fetches real environmental data, stores user settings, and provides a polished user experience. Let's dive into the exciting world of API integration and data persistence!
✅ Follow the numbered segments in the appropriate files to know where to place your code
### Set up the elements to manipulate in the extension:
## Set up the elements to manipulate in the extension
By this time you have built the HTML for the form and results `<div>` for your browser extension. From now on, you'll need to work in the `/src/index.js` file and build your extension bit by bit. Refer to the [previous lesson](../1-about-browsers/README.md) on getting your project set up and on the build process.
Before we can make our extension interactive, we need to establish connections between our JavaScript code and the HTML elements we created earlier. Think of this step as creating a communication bridge between your code and the user interface.
Working in your `index.js` file, start by creating some `const` variables to hold the values associated with various fields:
Working in your `index.js` file, you'll start by creating `const` variables that reference each important element on your form. This approach keeps your code organized and makes it easy to update the interface later.
```JavaScript
```javascript
// form fields
const form = document.querySelector('.form-data');
const region = document.querySelector('.region-name');
@ -32,120 +36,171 @@ const myregion = document.querySelector('.my-region');
const clearBtn = document.querySelector('.clear-btn');
```
All of these fields are referenced by their css class, as you set it up in the HTML in the previous lesson.
**Here's what this code does:**
- **Captures** form elements using `document.querySelector()` with CSS class selectors
- **Creates** references to input fields for the region name and API key
- **Establishes** connections to result display elements for carbon usage data
- **Sets up** access to UI elements like loading indicators and error messages
- **Stores** each element reference in a `const` variable for easy reuse throughout your code
### Add listeners
## Add event listeners
Next, add event listeners to the form and the clear button that resets the form, so that if a user submits the form or clicks that reset button, something will happen, and add the call to initialize the app at the bottom of the file:
Event listeners are like watchful assistants that wait for specific user actions and then execute your code in response. You'll add listeners for form submission and button clicks to make your extension interactive.
```JavaScript
```javascript
form.addEventListener('submit', (e) => handleSubmit(e));
clearBtn.addEventListener('click', (e) => reset(e));
init();
```
✅ Notice the shorthand used to listen for a submit or click event, and how the event it is passed to the handleSubmit or reset functions. Can you write the equivalent of this shorthand in a longer format? Which do you prefer?
**Understanding these concepts:**
- **Attaches** a submit listener to the form that triggers when users press Enter or click submit
- **Connects** a click listener to the clear button for resetting the form
- **Passes** the event object `(e)` to handler functions for additional control
- **Calls** the `init()` function immediately to set up the initial state of your extension
✅ Notice the shorthand arrow function syntax used here. This modern JavaScript approach is cleaner than traditional function expressions, but both work equally well!
### Build out the init() function and the reset() function:
## Build the initialization and reset functions
Now you are going to build the function that initializes the extension, which is called init():
The `init()` function is like the startup routine for your extension - it checks what data is already stored and decides what to show the user. The `reset()` function provides a clean slate when users want to start over.
```JavaScript
```javascript
function init() {
//if anything is in localStorage, pick it up
// Check if user has previously saved API credentials
const storedApiKey = localStorage.getItem('apiKey');
const storedRegion = localStorage.getItem('regionName');
//set icon to be generic green
//todo
// Set extension icon to generic green (placeholder for future lesson)
// TODO: Implement icon update in next lesson
if (storedApiKey === null || storedRegion === null) {
//if we don't have the keys, show the form
// First-time user: show the setup form
form.style.display = 'block';
results.style.display = 'none';
loading.style.display = 'none';
clearBtn.style.display = 'none';
errors.textContent = '';
} else {
//if we have saved keys/regions in localStorage, show results when they load
displayCarbonUsage(storedApiKey, storedRegion);
// Returning user: load their saved data automatically
displayCarbonUsage(storedApiKey, storedRegion);
results.style.display = 'none';
form.style.display = 'none';
clearBtn.style.display = 'block';
}
};
}
function reset(e) {
e.preventDefault();
//clear local storage for region only
// Clear stored region to allow user to choose a new location
localStorage.removeItem('regionName');
// Restart the initialization process
init();
}
```
In this function, there is some interesting logic. Reading through it, can you see what happens?
- two `const` are set up to check if the user has stored an APIKey and region code in local storage.
- if either of those is null, show the form by changing its style to display as 'block'
- hide the results, loading, and clearBtn and set any error text to an empty string
- if there exists a key and region, start a routine to:
- call the API to get carbon usage data
- hide the results area
- hide the form
- show the reset button
**Breaking down what happens here:**
- **Retrieves** stored API key and region from browser's local storage
- **Checks** if this is a first-time user (no stored credentials) or returning user
- **Shows** the setup form for new users and hides other interface elements
- **Loads** saved data automatically for returning users and displays the reset option
- **Manages** the user interface state based on available data
Before moving on, it's useful to learn about a very important concept available in browsers: [LocalStorage](https://developer.mozilla.org/docs/Web/API/Window/localStorage). LocalStorage is a useful way to store strings in the browser as a `key-value` pair. This type of web storage can be manipulated by JavaScript to manage data in the browser. LocalStorage does not expire, while SessionStorage, another kind of web storage, is cleared when the browser is closed. The various types of storage have pros and cons to their usage.
**Key concepts about Local Storage:**
- **Persists** data between browser sessions (unlike session storage)
- **Stores** data as key-value pairs using `getItem()` and `setItem()`
- **Returns** `null` when no data exists for a given key
- **Provides** a simple way to remember user preferences and settings
> Note - your browser extension has its own local storage; the main browser window is a different instance and behaves separately.
> 💡 **Understanding Browser Storage**: [LocalStorage](https://developer.mozilla.org/docs/Web/API/Window/localStorage) is one of several storage options available in web browsers. Think of it as a mini-database that lives in your user's browser.
>
> **What you need to know:**
> - **Stores** data as key-value pairs that persist between browser sessions
> - **Survives** browser restarts (unlike SessionStorage which expires when tabs close)
> - **Provides** up to 5-10MB of storage space per domain
> - **Works** synchronously, making it easy to use in your JavaScript code
You set your APIKey to have a string value, for example, and you can see that it is set on Edge by "inspecting" a web page (you can right-click a browser to inspect) and going to the Applications tab to see the storage.
> **Important Note**: Your browser extension has its own isolated local storage that's separate from regular web pages. This provides security and prevents conflicts with other websites.
![Local storage pane](images/localstorage.png)
You can view your stored data by opening browser Developer Tools (F12), navigating to the **Application** tab, and expanding the **Local Storage** section.
✅ Think about situations where you would NOT want to store some data in LocalStorage. In general, placing API Keys in LocalStorage is a bad idea! Can you see why? In our case, since our app is purely for learning and will not be deployed to an app store, we will use this method.
![Local storage pane](images/localstorage.png)
Notice that you use the Web API to manipulate LocalStorage, either by using `getItem()`, `setItem()`, or `removeItem()`. It's widely supported across browsers.
> ⚠️ **Security Consideration**: In production applications, storing API keys in LocalStorage poses security risks since JavaScript can access this data. For learning purposes, this approach works fine, but real applications should use secure server-side storage for sensitive credentials.
Before building the `displayCarbonUsage()` function that is called in `init()`, let's build the functionality to handle the initial form submission.
## Handle form submission
### Handle the form submission
When users submit your form, you need to intercept that action and process their input instead of letting the browser handle it normally. This is where form submission handling becomes crucial for single-page applications and extensions.
Create a function called `handleSubmit` that accepts an event argument `(e)`. Stop the event from propagating (in this case, we want to stop the browser from refreshing) and call a new function, `setUpUser`, passing in the arguments `apiKey.value` and `region.value`. In this way, you use the two values that are brought in via the initial form when the appropriate fields are populated.
Create a function that captures the form submission event and extracts the user's input:
```JavaScript
```javascript
function handleSubmit(e) {
e.preventDefault();
setUpUser(apiKey.value, region.value);
}
```
✅ Refresh your memory - the HTML you set up in the last lesson has two input fields whose `values` are captured via the `const` you set up at the top of the file, and they are both `required` so the browser stops users from inputting null values.
### Set up the user
**In the above, we've:**
- **Prevents** the default form submission behavior that would refresh the page
- **Extracts** user input values from the API key and region fields
- **Passes** the form data to the `setUpUser()` function for processing
- **Maintains** single-page application behavior by avoiding page reloads
✅ Remember that your HTML form fields include the `required` attribute, so the browser automatically validates that users provide both the API key and region before this function runs.
## Set up user preferences
Moving on to the `setUpUser` function, here is where you set local storage values for apiKey and regionName. Add a new function:
The `setUpUser` function is responsible for saving the user's credentials and initiating the first API call. This creates a smooth transition from setup to displaying results.
```JavaScript
```javascript
function setUpUser(apiKey, regionName) {
// Save user credentials for future sessions
localStorage.setItem('apiKey', apiKey);
localStorage.setItem('regionName', regionName);
// Update UI to show loading state
loading.style.display = 'block';
errors.textContent = '';
clearBtn.style.display = 'block';
//make initial call
// Fetch carbon usage data with user's credentials
displayCarbonUsage(apiKey, regionName);
}
```
This function sets a loading message to show while the API is called. At this point, you have arrived at creating the most important function of this browser extension!
### Display Carbon Usage
**Step by step, here's what's happening:**
- **Saves** the API key and region name to local storage for future use
- **Shows** a loading indicator to inform users that data is being fetched
- **Clears** any previous error messages from the display
- **Reveals** the clear button for users to reset their settings later
- **Initiates** the API call to fetch real carbon usage data
This function creates a seamless user experience by managing both data persistence and user interface updates in one coordinated action.
## Display carbon usage data
Finally, it's time to query the API!
Now comes the exciting part - fetching real environmental data from an external API! This is where your extension transforms from a simple form into a powerful tool that provides valuable information to users.
Before going further, we should discuss APIs. APIs, or [Application Programming Interfaces](https://www.webopedia.com/TERM/A/API.html), is a critical element of a web developer's toolbox. They provide standard ways for programs to interact and interface with each other. For example, if you are building a web site that needs to query a database, someone might have created an API for you to use. While there are many types of APIs, one of the most popular is a [REST API](https://www.smashingmagazine.com/2018/01/understanding-using-rest-api/).
**Understanding APIs in web development:**
✅ The term 'REST' stands for 'Representational State Transfer' and features using variously-configured URLs to fetch data. Do a little research on the various types of APIs available to developers. What format appeals to you?
[Application Programming Interfaces (APIs)](https://www.webopedia.com/TERM/A/API.html) are the bridges that connect different software systems. Think of them as specialized messengers that allow your application to request specific data from external services. When you check the weather on your phone, submit a payment online, or share content on social media, APIs are working behind the scenes.
There are important things to note about this function. First, notice the [`async` keyword](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/async_function). Writing your functions so that they run asynchronously means that they wait for an action, such as data being returned, to be completed before continuing.
**Key concepts about REST APIs:**
- **REST** stands for 'Representational State Transfer'
- **Uses** standard HTTP methods (GET, POST, PUT, DELETE) to interact with data
- **Returns** data in predictable formats, typically JSON
- **Provides** consistent, URL-based endpoints for different types of requests
✅ The [CO2 Signal API](https://www.co2signal.com/) we'll use provides real-time carbon intensity data from electrical grids worldwide. This helps users understand the environmental impact of their electricity usage!
> 💡 **Understanding Asynchronous JavaScript**: The [`async` keyword](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/async_function) is essential for modern web development. When you make API calls, you're requesting data from external servers, which takes time.
>
> **Here's why async/await matters:**
> - **Prevents** your application from freezing while waiting for API responses
> - **Allows** other code to continue running during network requests
> - **Provides** cleaner, more readable code compared to callback-based approaches
> - **Handles** errors gracefully when network requests fail
Here's a quick video about `async`:
@ -153,56 +208,82 @@ Here's a quick video about `async`:
> 🎥 Click the image above for a video about async/await.
Create a new function to query the C02Signal API:
```JavaScript
import axios from '../node_modules/axios';
Create the function to fetch and display carbon usage data:
```javascript
// Modern fetch API approach (no external dependencies needed)
async function displayCarbonUsage(apiKey, region) {
try {
await axios
.get('https://api.co2signal.com/v1/latest', {
params: {
countryCode: region,
},
headers: {
'auth-token': apiKey,
},
})
.then((response) => {
let CO2 = Math.floor(response.data.data.carbonIntensity);
//calculateColor(CO2);
loading.style.display = 'none';
form.style.display = 'none';
myregion.textContent = region;
usage.textContent =
Math.round(response.data.data.carbonIntensity) + ' grams (grams C02 emitted per kilowatt hour)';
fossilfuel.textContent =
response.data.data.fossilFuelPercentage.toFixed(2) +
'% (percentage of fossil fuels used to generate electricity)';
results.style.display = 'block';
});
// Fetch carbon intensity data from CO2 Signal API
const response = await fetch('https://api.co2signal.com/v1/latest', {
method: 'GET',
headers: {
'auth-token': apiKey,
'Content-Type': 'application/json'
},
// Add query parameters for the specific region
...new URLSearchParams({ countryCode: region }) && {
url: `https://api.co2signal.com/v1/latest?countryCode=${region}`
}
});
// Check if the API request was successful
if (!response.ok) {
throw new Error(`API request failed: ${response.status}`);
}
const data = await response.json();
const carbonData = data.data;
// Calculate rounded carbon intensity value
const carbonIntensity = Math.round(carbonData.carbonIntensity);
// Update the user interface with fetched data
loading.style.display = 'none';
form.style.display = 'none';
myregion.textContent = region.toUpperCase();
usage.textContent = `${carbonIntensity} grams (grams CO₂ emitted per kilowatt hour)`;
fossilfuel.textContent = `${carbonData.fossilFuelPercentage.toFixed(2)}% (percentage of fossil fuels used to generate electricity)`;
results.style.display = 'block';
// TODO: calculateColor(carbonIntensity) - implement in next lesson
} catch (error) {
console.log(error);
console.error('Error fetching carbon data:', error);
// Show user-friendly error message
loading.style.display = 'none';
results.style.display = 'none';
errors.textContent = 'Sorry, we have no data for the region you have requested.';
errors.textContent = 'Sorry, we couldn\'t fetch data for that region. Please check your API key and region code.';
}
}
```
This is a big function. What's going on here?
**Breaking down what happens here:**
- **Uses** the modern `fetch()` API instead of external libraries like Axios for cleaner, dependency-free code
- **Implements** proper error checking with `response.ok` to catch API failures early
- **Handles** asynchronous operations with `async/await` for more readable code flow
- **Authenticates** with the CO2 Signal API using the `auth-token` header
- **Parses** JSON response data and extracts carbon intensity information
- **Updates** multiple UI elements with formatted environmental data
- **Provides** user-friendly error messages when API calls fail
**Key modern JavaScript concepts demonstrated:**
- **Template literals** with `${}` syntax for clean string formatting
- **Error handling** with try/catch blocks for robust applications
- **Async/await** pattern for handling network requests gracefully
- **Object destructuring** to extract specific data from API responses
- **Method chaining** for multiple DOM manipulations
- following best practices, you use an `async` keyword to make this function behave asynchronously. The function contains a `try/catch` block as it will return a promise when the API returns data. Because you don't have control over the speed that the API will respond (it may not respond at all!), you need to handle this uncertainty by calling it asynchronously.
- you're querying the co2signal API to get your region's data, using your API Key. To use that key, you have to use a type of authentication in your header parameters.
- once the API responds, you assign various elements of its response data to the parts of your screen you set up to show this data.
- if there's an error, or if there is no result, you show an error message.
✅ This function showcases the complete lifecycle of API integration: authentication, request, data processing, UI updates, and error handling - all essential skills for modern web development!
✅ Using asynchronous programming patterns is another very useful tool in your toolbox. Read [about the various ways](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/async_function) you can configure this type of code.
🎉 **Congratulations!** You've built a fully functional browser extension that:
- **Integrates** with external APIs to fetch real-world data
- **Stores** user preferences in local storage
- **Handles** errors gracefully with user-friendly messages
- **Provides** a smooth, interactive user experience
Congratulations! If you build your extension (`npm run build`) and refresh it in your extensions pane, you have a working extension! The only thing that isn't working is the icon, and you'll fix that in the next lesson.
To test your extension, run `npm run build` and refresh it in your browser's extensions panel. You now have a working carbon footprint tracker! The only feature left to implement is the dynamic icon, which you'll tackle in the next lesson.
---
@ -216,7 +297,21 @@ Use the Agent mode to complete the following challenge:
## 🚀 Challenge
We've discussed several types of API so far in these lessons. Choose a web API and research in depth what it offers. For example, take a look at APIs available within browsers such as the [HTML Drag and Drop API](https://developer.mozilla.org/docs/Web/API/HTML_Drag_and_Drop_API). What makes a great API in your opinion?
Expand your understanding of APIs by exploring the wealth of browser-based APIs available for web development. Choose one of these browser APIs and build a small demonstration:
- [Geolocation API](https://developer.mozilla.org/docs/Web/API/Geolocation_API) - Get user's current location
- [Notification API](https://developer.mozilla.org/docs/Web/API/Notifications_API) - Send desktop notifications
- [HTML Drag and Drop API](https://developer.mozilla.org/docs/Web/API/HTML_Drag_and_Drop_API) - Create interactive drag interfaces
- [Web Storage API](https://developer.mozilla.org/docs/Web/API/Web_Storage_API) - Advanced local storage techniques
- [Fetch API](https://developer.mozilla.org/docs/Web/API/Fetch_API) - Modern alternative to XMLHttpRequest
**Research questions to consider:**
- What real-world problems does this API solve?
- How does the API handle errors and edge cases?
- What security considerations exist when using this API?
- How widely supported is this API across different browsers?
After your research, identify what characteristics make an API developer-friendly and reliable.
## Post-Lecture Quiz

@ -1,11 +1,93 @@
# Adopt an API
## Overview
APIs open up endless possibilities for creative web development! In this assignment, you'll choose an external API and build a browser extension that solves a real problem or provides valuable functionality to users.
## Instructions
APIs can be very fun to play with. Here is a [list of many free ones](https://github.com/public-apis/public-apis). Pick an API, and build a browser extension that solves a problem. It can be as small a problem of not having enough pet pictures (so, try the [dog CEO API](https://dog.ceo/dog-api/)) or something bigger - have fun!
### Step 1: Choose Your API
Select an API from this curated [list of free public APIs](https://github.com/public-apis/public-apis). Consider these categories:
**Popular options for beginners:**
- **Entertainment**: [Dog CEO API](https://dog.ceo/dog-api/) for random dog pictures
- **Weather**: [OpenWeatherMap](https://openweathermap.org/api) for current weather data
- **Quotes**: [Quotable API](https://quotable.io/) for inspirational quotes
- **News**: [NewsAPI](https://newsapi.org/) for current headlines
- **Fun Facts**: [Numbers API](http://numbersapi.com/) for interesting number facts
### Step 2: Plan Your Extension
Before coding, answer these planning questions:
- What problem does your extension solve?
- Who is your target user?
- What data will you store in local storage?
- How will you handle API failures or rate limits?
### Step 3: Build Your Extension
Your extension should include:
**Required Features:**
- Form inputs for any required API parameters
- API integration with proper error handling
- Local storage for user preferences or API keys
- Clean, responsive user interface
- Loading states and user feedback
**Code Requirements:**
- Use modern JavaScript (ES6+) features
- Implement async/await for API calls
- Include proper error handling with try/catch blocks
- Add meaningful comments explaining your code
- Follow consistent code formatting
### Step 4: Test and Polish
- Test your extension with various inputs
- Handle edge cases (no internet, invalid API responses)
- Ensure your extension works after browser restart
- Add user-friendly error messages
## Bonus Challenges
Take your extension to the next level:
- Add multiple API endpoints for richer functionality
- Implement data caching to reduce API calls
- Create keyboard shortcuts for common actions
- Add data export/import features
- Implement user customization options
## Submission Requirements
1. **Working browser extension** that successfully integrates with your chosen API
2. **README file** explaining:
- Which API you chose and why
- How to install and use your extension
- Any API keys or setup required
- Screenshots of your extension in action
3. **Clean, commented code** following modern JavaScript practices
## Rubric
| Criteria | Exemplary | Adequate | Needs Improvement |
| -------- | -------------------------------------------------------------------------- | ---------------------------------------- | ----------------------- |
| | A complete browser extension is submitted using an API from the above list | A partial browser extension is submitted | The submission has bugs |
| Criteria | Exemplary (90-100%) | Proficient (80-89%) | Developing (70-79%) | Beginning (60-69%) |
|----------|---------------------|---------------------|---------------------|--------------------|
| **API Integration** | Flawless API integration with comprehensive error handling and edge case management | Successful API integration with basic error handling | API works but has limited error handling | API integration has significant issues |
| **Code Quality** | Clean, well-commented modern JavaScript following best practices | Good code structure with adequate comments | Code works but needs better organization | Poor code quality with minimal comments |
| **User Experience** | Polished interface with excellent loading states and user feedback | Good interface with basic user feedback | Basic interface that functions adequately | Poor user experience with confusing interface |
| **Local Storage** | Sophisticated use of local storage with data validation and management | Proper implementation of local storage for key features | Basic local storage implementation | Minimal or incorrect use of local storage |
| **Documentation** | Comprehensive README with setup instructions and screenshots | Good documentation covering most requirements | Basic documentation missing some details | Poor or missing documentation |
## Getting Started Tips
1. **Start simple**: Choose an API that doesn't require complex authentication
2. **Read the docs**: Thoroughly understand your chosen API's endpoints and responses
3. **Plan your UI**: Sketch your extension's interface before coding
4. **Test frequently**: Build incrementally and test each feature as you add it
5. **Handle errors**: Always assume API calls might fail and plan accordingly
## Resources
- [Browser Extension Documentation](https://developer.mozilla.org/docs/Mozilla/Add-ons/WebExtensions)
- [Fetch API Guide](https://developer.mozilla.org/docs/Web/API/Fetch_API/Using_Fetch)
- [Local Storage Tutorial](https://developer.mozilla.org/docs/Web/API/Window/localStorage)
- [JSON Parsing and Handling](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/JSON)
Have fun building something useful and creative! 🚀

@ -1,5 +1,11 @@
# Browser Extension Project Part 3: Learn about Background Tasks and Performance
Background tasks and performance optimization are the invisible engines that power exceptional web experiences. While users interact with your browser extension's interface, behind the scenes your code is managing data fetching, icon updates, and system resources. Understanding how to optimize these processes transforms a functional extension into a professional, efficient tool that users love.
In this final lesson of the browser extension module, you'll complete your carbon footprint tracker by implementing dynamic icon updates and learning essential performance monitoring techniques. You'll discover how browsers manage background processes, explore the tools that help you identify performance bottlenecks, and apply optimization strategies that make your extension lightning-fast.
By the end of this lesson, you'll have a fully functional browser extension and the knowledge to build performant web applications that scale beautifully. Let's dive into the world of browser performance and bring your extension to life!
## Pre-Lecture Quiz
[Pre-lecture quiz](https://ff-quizzes.netlify.app/web/quiz/27)
@ -12,12 +18,22 @@ It remains to manage some background tasks, including refreshing the color of th
## Web Performance Basics
Web performance is the foundation of user experience on the modern web. When your code runs efficiently, users feel the difference in every interaction - from instant page loads to smooth animations and responsive interfaces. Understanding performance isn't just about making things faster; it's about creating web experiences that feel magical rather than frustrating.
Let's explore the tools and techniques that help you measure and optimize your web applications. We'll start with browser-based profiling tools, then apply these concepts to optimize your browser extension.
> "Website performance is about two things: how fast the page loads, and how fast the code on it runs." -- [Zack Grossbart](https://www.smashingmagazine.com/2012/06/javascript-profiling-chrome-developer-tools/)
The topic of how to make your websites blazingly fast on all kinds of devices, for all kinds of users, in all kinds of situations, is unsurprisingly vast. Here are some points to keep in mind as you build either a standard web project or a browser extension.
The first thing you need to do to ensure that your site is running efficiently is to gather data about its performance. The first place to do this is in the developer tools of your web browser. In Edge, you can select the "Settings and more" button (the three dots icon on the top right of the browser), then navigate to More Tools > Developer Tools and open the Performance tab. You can also use the keyboard shortcuts `Ctrl` + `Shift` + `I` on Windows or `Option` + `Command` + `I` on Mac to open developer tools.
**Here's how to get started with performance profiling:**
- **Opens** the Developer Tools using the keyboard shortcut or menu option
- **Navigates** to the Performance tab to access profiling tools
- **Records** a performance session while your page loads or runs
- **Analyzes** the results to identify bottlenecks and optimization opportunities
The Performance tab contains a Profiling tool. Open a website (try, for example, [https://www.microsoft.com](https://www.microsoft.com/?WT.mc_id=academic-77807-sagibbon)) and click the 'Record' button, then refresh the site. Stop the recording at any time, and you will be able to see the routines that are generated to 'script', 'render', and 'paint' the site:
![Edge profiler](./images/profiler.png)
@ -40,102 +56,179 @@ Check the Event Log pane to see if any event took longer than 15 ms:
## Profiling checks
Effective performance profiling goes beyond just running the tools - it requires knowing what to look for and how to interpret the data. Experienced developers have learned to spot common performance patterns that can make or break user experience.
Let's examine the key areas where performance issues typically emerge and how to identify them before they become problems in production.
In general, there are some "problem areas" that every web developer should watch for when building a site to avoid nasty surprises when it's time to deploy to production.
**Asset sizes**: The web has gotten 'heavier', and thus slower, over the past few years. Some of this weight has to do with the use of images.
✅ Look through the [Internet Archive](https://httparchive.org/reports/page-weight) for a historical view of page weight and more.
A good practice is to ensure that your images are optimized and delivered at the right size and resolution for your users.
**Best practices for asset optimization:**
- **Compresses** images using modern formats like WebP or AVIF
- **Serves** appropriately sized images for different screen resolutions
- **Minifies** CSS and JavaScript files to reduce download size
- **Implements** lazy loading for images and content below the fold
**DOM traversals**: The browser has to build its Document Object Model based on the code you write, so it's in the interest of good page performance to keep your tags minimal, only using and styling what the page needs. To this point, excess CSS associated with a page could be optimized; styles that need to be used only on one page don't need to be included in the main style sheet, for example.
**Key strategies for DOM optimization:**
- **Minimizes** the number of HTML elements and nesting levels
- **Removes** unused CSS rules and consolidates stylesheets efficiently
- **Organizes** CSS to load only what's needed for each page
- **Structures** HTML semantically for better browser parsing
**JavaScript**: Every JavaScript developer should watch for 'render-blocking' scripts that must be loaded before the rest of the DOM can be traversed and painted to the browser. Consider using `defer` with your inline scripts (as is done in the Terrarium module).
**Modern JavaScript optimization techniques:**
- **Uses** the `defer` attribute to load scripts after DOM parsing
- **Implements** code splitting to load only necessary JavaScript
- **Applies** lazy loading for non-critical functionality
- **Minimizes** the use of heavy libraries and frameworks when possible
✅ Try some sites on a [Site Speed Test website](https://www.webpagetest.org/) to learn more about the common checks that are done to determine site performance.
Now that you have an idea of how the browser renders the assets you send to it, let's look at the last few things you need to do to complete your extension:
### Create a function to calculate color
Now we'll implement the core logic that transforms CO2 data into a visual indicator. This function will take the carbon intensity value from our API and map it to an appropriate color that reflects the environmental impact.
Working in `/src/index.js`, add a function called `calculateColor()` after the series of `const` variables you set to gain access to the DOM:
```JavaScript
```javascript
function calculateColor(value) {
let co2Scale = [0, 150, 600, 750, 800];
let colors = ['#2AA364', '#F5EB4D', '#9E4229', '#381D02', '#381D02'];
// Define CO2 intensity scale (grams per kWh)
const co2Scale = [0, 150, 600, 750, 800];
// Corresponding colors from green (clean) to dark brown (high carbon)
const colors = ['#2AA364', '#F5EB4D', '#9E4229', '#381D02', '#381D02'];
let closestNum = co2Scale.sort((a, b) => {
// Find the closest scale value to our input
const closestNum = co2Scale.sort((a, b) => {
return Math.abs(a - value) - Math.abs(b - value);
})[0];
console.log(value + ' is closest to ' + closestNum);
let num = (element) => element > closestNum;
let scaleIndex = co2Scale.findIndex(num);
let closestColor = colors[scaleIndex];
console.log(`${value} is closest to ${closestNum}`);
// Find the index for color mapping
const num = (element) => element > closestNum;
const scaleIndex = co2Scale.findIndex(num);
const closestColor = colors[scaleIndex];
console.log(scaleIndex, closestColor);
// Send color update message to background script
chrome.runtime.sendMessage({ action: 'updateIcon', value: { color: closestColor } });
}
```
What's going on here? You pass in a value (the carbon intensity) from the API call you completed in the last lesson, and then you calculate how close its value is to the index presented in colors array. Then you send that closest color value over to the chrome runtime.
**Breaking down what happens here:**
- **Defines** arrays for CO2 intensity scale and corresponding colors
- **Calculates** the closest scale value using array sorting and Math.abs()
- **Finds** the appropriate color index using findIndex() method
- **Sends** a message to the Chrome runtime with the selected color
- **Uses** template literals for cleaner string formatting
- **Applies** const declarations for values that don't change
The chrome.runtime has [an API](https://developer.chrome.com/extensions/runtime) that handles all kinds of background tasks, and your extension is leveraging that:
The `chrome.runtime` has [an API](https://developer.chrome.com/extensions/runtime) that handles all kinds of background tasks, and your extension is leveraging that:
> "Use the chrome.runtime API to retrieve the background page, return details about the manifest, and listen for and respond to events in the app or extension lifecycle. You can also use this API to convert the relative path of URLs to fully-qualified URLs."
**Understanding Chrome Runtime API benefits:**
- **Manages** communication between different parts of your extension
- **Handles** background tasks without blocking the user interface
- **Provides** lifecycle management for extension events
- **Enables** message passing between content scripts and background scripts
✅ If you're developing this browser extension for Edge, it might surprise you that you're using a chrome API. The newer Edge browser versions run on the Chromium browser engine, so you can leverage these tools.
> Note, if you want to profile a browser extension, launch the dev tools from within the extension itself, as it is its own separate browser instance.
> **Pro Tip**: If you want to profile a browser extension, launch the dev tools from within the extension itself, as it is its own separate browser instance. This gives you access to extension-specific performance metrics.
### Set a default icon color
Before we fetch real data, it's important to initialize our extension with a default state. This provides immediate visual feedback to users and ensures the extension appears functional from the moment it loads.
Now, in the `init()` function, set the icon to be generic green to start by again calling chrome's `updateIcon` action:
```JavaScript
```javascript
chrome.runtime.sendMessage({
action: 'updateIcon',
value: {
color: 'green',
},
value: {
color: 'green',
},
});
```
**What this initialization accomplishes:**
- **Sets** a neutral green color as the default state
- **Provides** immediate visual feedback when the extension loads
- **Establishes** the communication pattern with the background script
- **Ensures** users see a functional extension before data loads
### Call the function, execute the call
Now we'll integrate our color calculation function with the API data flow. This connects the data retrieval process with the visual indicator system, creating a seamless user experience.
Next, call that function you just created by adding it to the promise returned by the C02Signal API:
```JavaScript
//let CO2...
```javascript
// After retrieving CO2 data from the API
// let CO2 = data.data[0].intensity.actual;
calculateColor(CO2);
```
**This integration accomplishes:**
- **Connects** the API data flow with the visual indicator system
- **Triggers** icon updates automatically when new data arrives
- **Ensures** real-time visual feedback based on current carbon intensity
- **Maintains** the separation of concerns between data fetching and display logic
And finally, in `/dist/background.js`, add the listener for these background action calls:
```JavaScript
```javascript
// Listen for messages from the content script
chrome.runtime.onMessage.addListener(function (msg, sender, sendResponse) {
if (msg.action === 'updateIcon') {
chrome.action.setIcon({ imageData: drawIcon(msg.value) });
}
});
//borrowed from energy lollipop extension, nice feature!
// Draw dynamic icon using Canvas API
// Borrowed from energy lollipop extension - nice feature!
function drawIcon(value) {
let canvas = new OffscreenCanvas(200, 200);
let context = canvas.getContext('2d');
// Create an offscreen canvas for better performance
const canvas = new OffscreenCanvas(200, 200);
const context = canvas.getContext('2d');
// Draw a colored circle representing carbon intensity
context.beginPath();
context.fillStyle = value.color;
context.arc(100, 100, 50, 0, 2 * Math.PI);
context.fill();
// Return the image data for the browser icon
return context.getImageData(50, 50, 100, 100);
}
```
In this code, you are adding a listener for any messages coming to the backend task manager. If it's called 'updateIcon', then the next code is run to draw an icon of the proper color using the Canvas API.
**Understanding the background script functionality:**
- **Listens** for messages from content scripts using runtime.onMessage
- **Processes** 'updateIcon' actions to change the extension's toolbar icon
- **Creates** dynamic icons using the Canvas API and OffscreenCanvas
- **Draws** a colored circle that reflects current carbon intensity levels
- **Updates** the browser toolbar with the newly generated icon image
- **Uses** OffscreenCanvas for better performance in background contexts
✅ You'll learn more about the Canvas API in the [Space Game lessons](../../6-space-game/2-drawing-to-canvas/README.md).
Now, rebuild your extension (`npm run build`), refresh and launch your extension, and watch the color change. Is it a good time to run an errand or wash the dishes? Now you know!
**Testing your completed extension:**
- **Build** your extension using `npm run build`
- **Reload** the extension in your browser's extension management page
- **Launch** your extension and watch the color change based on current data
- **Monitor** how the icon updates reflect real-time carbon intensity
Is it a good time to run an errand or wash the dishes? Now you know!
Congratulations, you've built a useful browser extension and learned more about how the browser works and how to profile its performance.
@ -153,7 +246,13 @@ Use the Agent mode to complete the following challenge:
## 🚀 Challenge
Investigate some open source websites that have been around a long time ago, and, based on their GitHub history, see if you can determine how they were optimized over the years for performance, if at all. What is the most common pain point?
Investigate some open source websites that have been around a long time, and, based on their GitHub history, see if you can determine how they were optimized over the years for performance, if at all. What is the most common pain point?
**Research approach:**
- **Examines** commit history for performance-related changes
- **Identifies** patterns in optimization strategies over time
- **Analyzes** common performance bottlenecks across different projects
- **Documents** your findings and shares insights with the community
## Post-Lecture Quiz

@ -1,9 +1,93 @@
# Analyze a site for performance
Provide a detailed report of a web site, showing areas where performance is problematic. Analyze why the site is slow and what you could do to speed it up. Don't rely only on the browser tools, but do some research on other tools that can help your report.
## Assignment Overview
Performance analysis is a critical skill for modern web developers. In this assignment, you'll conduct a comprehensive performance audit of a real website, using both browser-based tools and third-party services to identify bottlenecks and propose optimization strategies.
Your task is to provide a detailed performance report that demonstrates your understanding of web performance principles and your ability to use professional analysis tools effectively.
## Assignment Instructions
**Choose a website** for analysis - select one of the following options:
- A popular website you use frequently (news site, social media, e-commerce)
- An open-source project website (GitHub pages, documentation sites)
- A local business website or portfolio site
- Your own project or previous coursework
**Conduct multi-tool analysis** using at least three different approaches:
- **Browser DevTools** - Use Chrome/Edge Performance tab for detailed profiling
- **Online auditing tools** - Try Lighthouse, GTmetrix, or WebPageTest
- **Network analysis** - Examine resource loading, file sizes, and request patterns
**Document your findings** in a comprehensive report that includes:
### Performance Metrics Analysis
- **Load time measurements** from multiple tools and perspectives
- **Core Web Vitals** scores (LCP, FID, CLS) and their implications
- **Resource breakdown** showing which assets contribute most to load time
- **Network waterfall analysis** identifying blocking resources
### Problem Identification
- **Specific performance bottlenecks** with supporting data
- **Root cause analysis** explaining why each issue occurs
- **User impact assessment** describing how problems affect real users
- **Priority ranking** of issues based on severity and fixing difficulty
### Optimization Recommendations
- **Specific, actionable improvements** with expected impact
- **Implementation strategies** for each recommended change
- **Modern best practices** that could be applied (lazy loading, compression, etc.)
- **Tools and techniques** for ongoing performance monitoring
## Research Requirements
**Don't rely only on browser tools** - expand your analysis using:
**Third-party auditing services:**
- [Google Lighthouse](https://developers.google.com/web/tools/lighthouse) - Comprehensive audits
- [GTmetrix](https://gtmetrix.com/) - Performance and optimization insights
- [WebPageTest](https://www.webpagetest.org/) - Real-world testing conditions
- [Pingdom](https://tools.pingdom.com/) - Global performance monitoring
**Specialized analysis tools:**
- [Bundle Analyzer](https://bundlephobia.com/) - JavaScript bundle size analysis
- [Image optimization tools](https://squoosh.app/) - Asset optimization opportunities
- [Security headers analysis](https://securityheaders.com/) - Security performance impact
## Deliverables Format
Create a professional report (2-3 pages) that includes:
1. **Executive Summary** - Key findings and recommendations overview
2. **Methodology** - Tools used and testing approach
3. **Current Performance Assessment** - Baseline metrics and measurements
4. **Issues Identified** - Detailed problem analysis with supporting data
5. **Recommendations** - Prioritized improvement strategies
6. **Implementation Roadmap** - Step-by-step optimization plan
**Include visual evidence:**
- Screenshots of performance tools and metrics
- Charts or graphs showing performance data
- Before/after comparisons where possible
- Network waterfall charts and resource breakdowns
## Rubric
| Criteria | Exemplary | Adequate | Needs Improvement |
| -------- | ---------------------------------------------------------------------------------------------------------- | --------------------------- | ----------------------------- |
| | A report is presented with details drawn not only from browser tools but from 3rd party tools if available | A basic report is presented | A minimal report is presented |
| Criteria | Exemplary (90-100%) | Adequate (70-89%) | Needs Improvement (50-69%) |
| -------- | ------------------- | ----------------- | -------------------------- |
| **Analysis Depth** | Comprehensive analysis using 4+ tools with detailed metrics, root cause analysis, and user impact assessment | Good analysis using 3 tools with clear metrics and basic problem identification | Basic analysis using 2 tools with limited depth and minimal problem identification |
| **Tool Diversity** | Uses browser tools + 3+ third-party services with comparative analysis and insights from each | Uses browser tools + 2 third-party services with some comparative analysis | Uses browser tools + 1 third-party service with limited comparison |
| **Problem Identification** | Identifies 5+ specific performance issues with detailed root cause analysis and quantified impact | Identifies 3-4 performance issues with good analysis and some impact measurement | Identifies 1-2 performance issues with basic analysis |
| **Recommendations** | Provides specific, actionable recommendations with implementation details, expected impact, and modern best practices | Provides good recommendations with some implementation guidance and expected outcomes | Provides basic recommendations with limited implementation details |
| **Professional Presentation** | Well-organized report with clear structure, visual evidence, executive summary, and professional formatting | Good organization with some visual evidence and clear structure | Basic organization with minimal visual evidence |
## Learning Outcomes
By completing this assignment, you will demonstrate your ability to:
- **Apply** professional performance analysis tools and methodologies
- **Identify** performance bottlenecks using data-driven analysis
- **Analyze** the relationship between code quality and user experience
- **Recommend** specific, actionable optimization strategies
- **Communicate** technical findings in a professional format
This assignment reinforces the performance concepts learned in the lesson while building practical skills you'll use throughout your web development career.

Loading…
Cancel
Save