const maxRating = 10; window.addEventListener( "load", (e) => { let config; /** * @type {HTMLTableElement} */ let table = document.querySelector("table#output"); let form = document.getElementById("movieSearch"); let textInput = form.querySelector("input"); table.hidden = true; form.addEventListener( "submit", async (e) => { e.preventDefault(); table.hidden = true; config ??= await queryTMDb("configuration"); while (table.tBodies.length > 0) { table.removeChild(table.tBodies[0]); } let result = await queryTMDb( "search/movie", { include_adult: true, language: "en-US", query: textInput.value }); let tBody = table.createTBody(); tBody.classList.add("align-middle"); for (let i = 0; i < result.results.length; i++) { let movie = result.results[i]; let row = tBody.insertRow(); let title = document.createElement("a"); let poster = document.createElement("img"); title.href = `${new URL(`${movie.id}`, "https://themoviedb.org/movie/")}`; title.classList.add("link-body-emphasis"); title.target = "_blank"; title.innerText = movie.title; poster.src = new URL( `./${movie.poster_path}`, new URL( `${config.images.poster_sizes[0]}/`, config.images.secure_base_url).toString()).toString(); row.insertCell().innerText = `#${i + 1}`; row.insertCell().appendChild(poster); row.insertCell().appendChild(title); row.insertCell().appendChild(createRating(movie.vote_average)); row.insertCell().innerText = movie.overview; } table.hidden = false; console.log(config); console.log(result); }); }); /** * Queries an endpoint of the TMDb API. * * @param {string} endpoint * @param {Record} params * The parameters to send to the API. */ async function queryTMDb(endpoint, params) { let url = new URL(endpoint, "https://api.themoviedb.org/3/"); for (let param in params) { url.searchParams.append(param, `${params[param]}`); } return ( await fetch( `${url}`, { headers: { Accept: "application/json" } })).json(); } function createRating(rating) { let progressBar = document.createElement("div"); let indicator = progressBar.appendChild(document.createElement("div")); let rounded = Math.round(rating * 10) / 10; progressBar.style.minWidth = "10rem"; progressBar.classList.add("progress"); for ( let attribute of [ ["role", "progressbar"], ["aria-label", "Rating"], ["aria-valuenow", `${rating}`], ["aria-valuemin", `${0}`], ["aria-valuemax", `${maxRating}`] ]) { progressBar.setAttribute(attribute[0], attribute[1]); } indicator.classList.add("progress-bar", "text-bg-warning", "overflow-visible"); indicator.style.width = `${rating * 10}%`; indicator.textContent = `${rounded}/${maxRating}`; return progressBar; }