189 lines
6.5 KiB
JavaScript
Executable File
189 lines
6.5 KiB
JavaScript
Executable File
/* 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));
|
|
})();
|