First commit

This commit is contained in:
2025-09-10 14:42:57 -04:00
commit 1d12903e4e
65 changed files with 3587 additions and 0 deletions

188
Lab 8/funs.js Executable file
View File

@@ -0,0 +1,188 @@
/* STEP 1: Given a movie object, copy its title into a new field called
* textContent and return the movie.
*
* @param {object} movie A movie object from the JSON data set
*/
function setTitleContent(movie) {
movie.textContent = movie.title;
return movie;
}
/* STEP 2: Given a movie object, append the remaining fields into the
* textContent field. Each function should append only the relevant field.
* Chaining them together would create a textContent string such as the
* following:
* Mad Max: Fury Road (2015) - 120 minutes [8.1]
* Make sure to include the correct spacing and punctuation marks.
*
* @param {object} movie A movie object from the JSON data set with the
* title already copied into the movie.textContent field.
*/
function appendYear(movie) {
movie.textContent = movie.textContent.concat(` (${movie.year})`);
return movie;
}
function appendRuntime(movie) {
movie.textContent = movie.textContent.concat(` - ${movie.runtime} minutes`);
return movie;
}
function appendRating(movie) {
movie.textContent = movie.textContent.concat(` [${movie.rating}]`);
return movie;
}
/* STEP 3: Return a closure (arrow function) that takes a movie argument
* and compares its .rating field with this function's rating argument.
* Return true if the movie's rating satisfies this minimum criterion.
* Note that you need to call parseFloat on the movie.rating field because
* JSON data defaults to a string type.
*
* @param {number} rating The minimum movie rating that will cause the
* closure to return true for a movie.
*/
function setMinRating(rating) {
// If the minimum rating value passed in the query string is NaN,
// the closure should always evaluate to false.
// Whether or not this is desireable is up to the designer
const minRating = Number.parseFloat(rating);
return (movie) => Number.parseFloat(movie.rating) >= minRating;
}
/* STEP 3: Complete the following functions just as you did setMinRating.
* You'll need to use parseInt instead of parseFloat, because these are
* all integer values.
*/
function setMinYear(year) {
const minYear = Number.parseFloat(year);
return (movie) => Number.parseFloat(movie.year) >= minYear;
}
function setMaxYear(year) {
const maxYear = Number.parseFloat(year);
return (movie) => Number.parseFloat(movie.year) <= maxYear;
}
function setMinTime(mins) {
const minMins = Number.parseFloat(mins);
return (movie) => Number.parseFloat(movie.runtime) >= minMins;
}
function setMaxTime(mins) {
const maxMins = Number.parseFloat(mins);
return (movie) => Number.parseFloat(movie.runtime) <= maxMins;
}
/* buildItem - Helper function that creates a DOM <li> element, adds the
* list-group-item class, and inserts the movie's text content. Do not
* modify.
*
* @param {object} movie The movie object to create as a list item
* @param {object} list The <ul> to add the item to
*/
function buildItem(movie, list) {
let item = document.createElement("li");
item.classList.add("list-group-item");
item.textContent = movie.textContent;
list.append(item);
}
(async function () {
// STEP 1: Start your anonymous initialization function here. Be sure to
// end the file with the needed syntax to call the function.
// FIRST CODE IN THE INITIALIZATION FUNCTION
// Get the <ul> object from the HTML (do not modify)
let ul = document.querySelector("#target");
// Set default values (do not modify)
let minYear = 0;
let maxYear = 3000;
let minTime = 0;
let maxTime = 500;
let minRating = 0.0;
// Get the query string and split it into an array of distinct queries.
// (do not modify)
// For example, given index.html?minyear=1990&minrating=9.0, the query
// variable is the array [ 'minyear=1990', 'minrating=9.0' ]
let query = window.location.search.substring(1); //.split('&');
if (query !== "") {
query = query.split("&");
} else {
query = undefined;
}
// KEEP THIS HARD-CODED TO AVOID CORS ISSUES
const hostname = "https://w3.cs.jmu.edu/kirkpams/343/labs/lab8";
const url = `${hostname}/data.json`;
// STEP 1: Fetch the JSON data from the URL. If the query string is empty
// (i.e., query is undefined), grab just the first 10 data entries. Given
// this array, use .map to call setTitleContent on each entry and .forEach
// to call buildItem for each. You may NOT use a traditional loop (e.g.,
// for-of, while, etc.) for this lab.
//
// STEP 2: Extend the movie's textContent by using .map with the additional
// functions to append the year, runtime, and rating values.
//
// STEP 3: If the query variable is defined, then the URL contains a query
// string of criteria. Use the criteria specified in the query string to
// filter the data. Each criterion would be of the form minyear=2000, with
// the criteria being minyear, maxyear, mintime, maxtime, or minrating. Use
// the values here to change the default minYear, etc., listed above. Note
// that you will need to use parseInt or parseFloat to convert the query
// string value into a number.
//
// Once you've processed all of the filter criteria, run the full JSON data
// set through these using .filter, then use .map and .forEach as before to
// generate the data.
// END OF THE INITIALIZATION FUNCTION
// ! Important caveat of this implementation, there is no specification for
// ! how to handle situations where the same query param is passed multiple
// ! times, or when query params contradict each other.
// ! This implementation sequentially applies filters for every query param
// ! regardless of the other conditions in list of query params.
let movieData = await fetch(url)
.then((response) => response.json())
.catch(() => null);
if (!movieData) return;
// In order to constrain all current and potential future filter functions
// to a singular interface all filter functions will accept a single string
// parameter (the query value).
// Any parsing of this string will be handled by the individual filter functions.
const filterMap = {
minyear: setMinYear,
maxyear: setMaxYear,
mintime: setMinTime,
maxtime: setMaxTime,
minrating: setMinRating,
};
query?.forEach((queryString) => {
const [name, value] = queryString.split("=");
if (name in filterMap) {
movieData = movieData.filter(filterMap[name](value));
}
});
if (!query) {
movieData = movieData.slice(0, 10);
}
movieData
.map(setTitleContent)
.map(appendYear)
.map(appendRuntime)
.map(appendRating)
.forEach((movie) => buildItem(movie, ul));
})();

51
Lab 8/index.html Executable file
View File

@@ -0,0 +1,51 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="author" content="Michael S. Kirkpatrick">
<title>IMDb Demo</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
</head>
<body>
<!-- Step 0: Create the nav bar in all files -->
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
<div class="container-fluid">
<a class="navbar-brand" href="index.html">Lab 9</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav mr-auto">
<li class="nav-item"> <a class="nav-link active" href="index.html?minrating=8.5">High Rating</a>
<li class="nav-item"> <a class="nav-link active" href="index.html?minyear=1970&maxyear=1979">The '70s</a>
<li class="nav-item"> <a class="nav-link active" href="index.html?mintime=150">Long Movies</a>
<li class="nav-item"> <a class="nav-link active" href="index.html?maxtime=100&minrating=8.0">Best Short Movies</a>
<li class="nav-item"> <a class="nav-link active" href="index.html?minrating=8.0&minyear=1980&maxyear=1990&mintime=116&maxtime=120">Blade Runner</a>
</ul>
</div>
</div>
</nav>
<br>
<header class="container">
<h1>IMDb Sample</h1>
<p>This page uses a small sample of records from IMDb's public web service.
</header>
<main class="container">
<ul class="list-group" id="target"></ul>
</main>
</body>
<script src="funs.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"
integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p"
crossorigin="anonymous"></script>
</html>