From 5d77dc3c8e70cde0dd932bc7d6978873e963f329 Mon Sep 17 00:00:00 2001 From: Pezhman-Azizi <80008463+Pezhman-Azizi@users.noreply.github.com> Date: Wed, 15 Jan 2025 11:49:22 +0000 Subject: [PATCH 1/8] removed episode.js from index.html --- index.html | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/index.html b/index.html index bfec4df..cdf5bc9 100644 --- a/index.html +++ b/index.html @@ -13,6 +13,11 @@

TV Series Episodes

+ + +

@@ -28,6 +33,5 @@

TV Series Episodes

- From 409b8dff0029a2a67ed57c6d89d67dd28a185454 Mon Sep 17 00:00:00 2001 From: Pezhman-Azizi <80008463+Pezhman-Azizi@users.noreply.github.com> Date: Wed, 15 Jan 2025 11:51:09 +0000 Subject: [PATCH 2/8] applied the fetch --- script.js | 102 ++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 83 insertions(+), 19 deletions(-) diff --git a/script.js b/script.js index 4e0213c..63c41f3 100644 --- a/script.js +++ b/script.js @@ -1,28 +1,92 @@ +let allEpisodes = []; // Store all episodes globally for reuse throughout the script + +// Utility function to pad numbers with leading zeros (e.g., 1 becomes 01) function padNumber(number) { - return number.toString().padStart(2, '0'); + return number.toString().padStart(2, '0'); } -function createEpisodeCard(episode) { - const episodeNumber = `S${padNumber(episode.season)}E${padNumber(episode.number)}`; +// Generate HTML structure for an individual episode card +function generateEpisodeHTML(episode) { + const episodeNumber = `S${padNumber(episode.season)}E${padNumber(episode.number)}`; + return ` +
+
${episodeNumber}
+ ${episode.name} +
+

${episode.name}

+

${episode.summary || 'No description available.'}

+
+
`; +} + +// Render the list of episodes on the page +function renderEpisodes(episodesToDisplay) { + const episodesGrid = document.getElementById('episodes-grid'); + episodesGrid.innerHTML = episodesToDisplay.map(generateEpisodeHTML).join(''); + const searchResult = document.getElementById('search-result'); + searchResult.textContent = `Showing ${episodesToDisplay.length} out of ${allEpisodes.length} episodes`; +} - return ` -
-
${episodeNumber}
- ${episode.name} -
-

${episode.name}

-

${episode.summary}

-
-
- `; +// Filter episodes based on the search input +function filterEpisodes(event) { + const searchTerm = event.target.value.toLowerCase(); + const filteredEpisodes = allEpisodes.filter(episode => + episode.name.toLowerCase().includes(searchTerm) || + (episode.summary && episode.summary.toLowerCase().includes(searchTerm)) + ); + renderEpisodes(filteredEpisodes); } -function displayEpisodes() { - const episodes = getAllEpisodes(); - const episodesGrid = document.getElementById('episodes-grid'); +// Populate the episode selector dropdown with all episodes +function populateEpisodeSelector() { + const episodeSelector = document.getElementById('episode-selector'); + episodeSelector.innerHTML = ''; + allEpisodes.forEach(episode => { + const episodeNumber = `S${padNumber(episode.season)}E${padNumber(episode.number)}`; + const option = document.createElement('option'); + option.value = episode.id; + option.textContent = `${episodeNumber} - ${episode.name}`; + episodeSelector.appendChild(option); + }); +} + +// Handle the selection of an episode from the dropdown +function handleEpisodeSelection(event) { + const selectedEpisodeId = event.target.value; + if (selectedEpisodeId) { + const selectedEpisode = allEpisodes.find(episode => episode.id === Number(selectedEpisodeId)); + renderEpisodes([selectedEpisode]); + } else { + renderEpisodes(allEpisodes); + } +} - const episodesHTML = episodes.map(episode => createEpisodeCard(episode)).join(''); - episodesGrid.innerHTML = episodesHTML; +// Fetch episodes from the TVMaze API +function fetchEpisodes() { + const episodesGrid = document.getElementById('episodes-grid'); + episodesGrid.innerHTML = '

Loading episodes...

'; + fetch('https://api.tvmaze.com/shows/82/episodes') + .then(response => { + if (!response.ok) { + throw new Error('Failed to fetch episodes'); + } + return response.json(); + }) + .then(data => { + allEpisodes = data; // Store fetched episodes globally + renderEpisodes(allEpisodes); // Display episodes + populateEpisodeSelector(); // Populate dropdown + }) + .catch(error => { + episodesGrid.innerHTML = `

Error loading episodes: ${error.message}

`; + }); } -document.addEventListener('DOMContentLoaded', displayEpisodes); +// Set up the page once the DOM content is fully loaded +document.addEventListener('DOMContentLoaded', () => { + fetchEpisodes(); // Fetch episodes from the API + const searchBox = document.getElementById('search-box'); + searchBox.addEventListener('input', filterEpisodes); + const episodeSelector = document.getElementById('episode-selector'); + episodeSelector.addEventListener('change', handleEpisodeSelection); +}); From 2cc6a17ff3db75e8f0cb82f494feac8596bd50f2 Mon Sep 17 00:00:00 2001 From: Pezhman-Azizi <80008463+Pezhman-Azizi@users.noreply.github.com> Date: Wed, 15 Jan 2025 11:53:16 +0000 Subject: [PATCH 3/8] modified style.css --- style.css | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/style.css b/style.css index d97d718..f25f9a4 100644 --- a/style.css +++ b/style.css @@ -32,6 +32,60 @@ header h1 { font-weight: 700; } +/* Search Box */ +#search-box { + width: 100%; + max-width: 400px; + padding: 5px 5px; + margin-bottom: 1rem; + border: 1px solid #ccc; + border-radius: 25px; + font-size: 1rem; + color: #333; + background-color: #f9f9f9; + box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); + transition: all 0.3s ease; +} + +#search-box:focus { + border-color: #3498db; + box-shadow: 0 4px 10px rgba(52, 152, 219, 0.3); + outline: none; + background-color: #fff; +} + +#search-box::placeholder { + color: #aaa; + font-style: italic; +} + +/* Episode Selector */ +#episode-selector { + width: 100%; + max-width: 400px; + padding: 5px 5px; + border: 1px solid #ccc; + border-radius: 25px; + font-size: 1rem; + color: #a4a4a4; + background-color: #f9f9f9; + box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); + appearance: none; + background-image: url('data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="gray" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"%3E%3Cpolyline points="6 9 12 15 18 9"%3E%3C/polyline%3E%3C/svg%3E'); + background-repeat: no-repeat; + background-position: right 15px center; + background-size: 16px; + transition: all 0.3s ease; +} + +#episode-selector:focus { + border-color: #3498db; + box-shadow: 0 4px 10px rgba(52, 152, 219, 0.3); + outline: none; + background-color: #fff; +} + + /* Episodes Grid */ .episodes-grid { display: grid; From 40066c5e06490dab0da6b4089449b5d2c7a7d35d Mon Sep 17 00:00:00 2001 From: donarbl Date: Wed, 15 Jan 2025 15:51:24 +0000 Subject: [PATCH 4/8] html selector --- index.html | 3 +++ 1 file changed, 3 insertions(+) diff --git a/index.html b/index.html index cdf5bc9..b951f8d 100644 --- a/index.html +++ b/index.html @@ -19,6 +19,9 @@

TV Series Episodes

+
From 27ef5f3342b3bacb7b83a72a0e4f39d7ad10de38 Mon Sep 17 00:00:00 2001 From: donarbl Date: Wed, 15 Jan 2025 15:57:43 +0000 Subject: [PATCH 5/8] show selector css --- style.css | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/style.css b/style.css index f25f9a4..ecb674e 100644 --- a/style.css +++ b/style.css @@ -58,7 +58,22 @@ header h1 { color: #aaa; font-style: italic; } + /* show-selector*/ + #show-selector + { + width: 100%; + max-width: 400px; + padding: 5px 5px; + margin-bottom: 1rem; + border: 1px solid #ccc; + border-radius: 25px; + font-size: 1rem; + color: #333; + background-color: #f9f9f9; + box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); + transition: all 0.3s ease; +} /* Episode Selector */ #episode-selector { width: 100%; From 2c1db5bc8cb30db1a985044230abe82e78e7a5e3 Mon Sep 17 00:00:00 2001 From: donarbl Date: Wed, 15 Jan 2025 17:29:08 +0000 Subject: [PATCH 6/8] search box css --- index.html | 7 ++++--- style.css | 31 +++++++++++++++---------------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/index.html b/index.html index b951f8d..e896579 100644 --- a/index.html +++ b/index.html @@ -18,10 +18,11 @@

TV Series Episodes

+ - +
diff --git a/style.css b/style.css index ecb674e..b632a60 100644 --- a/style.css +++ b/style.css @@ -33,7 +33,7 @@ header h1 { } /* Search Box */ -#search-box { +#search-box, #show-selector{ width: 100%; max-width: 400px; padding: 5px 5px; @@ -47,6 +47,18 @@ header h1 { transition: all 0.3s ease; } +#show-selector:focus { +border-color: #3498db; + box-shadow: 0 4px 10px rgba(52, 152, 219, 0.3); + outline: none; + background-color: #fff; + +} +#show-selector::placeholder{ + color: #aaa; + font-style: italic; +} + #search-box:focus { border-color: #3498db; box-shadow: 0 4px 10px rgba(52, 152, 219, 0.3); @@ -58,22 +70,7 @@ header h1 { color: #aaa; font-style: italic; } - /* show-selector*/ - #show-selector - { - width: 100%; - max-width: 400px; - padding: 5px 5px; - margin-bottom: 1rem; - border: 1px solid #ccc; - border-radius: 25px; - font-size: 1rem; - color: #333; - background-color: #f9f9f9; - box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); - transition: all 0.3s ease; -} /* Episode Selector */ #episode-selector { width: 100%; @@ -209,4 +206,6 @@ footer { grid-template-columns: 1fr; gap: 1rem; } + + } From 95bcd24428e4f37d2ec2094ecc1160d1c4c66b83 Mon Sep 17 00:00:00 2001 From: donarbl Date: Wed, 15 Jan 2025 17:33:52 +0000 Subject: [PATCH 7/8] declaring allepisodes and cache functions --- script.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/script.js b/script.js index 63c41f3..83fb8e7 100644 --- a/script.js +++ b/script.js @@ -1,5 +1,6 @@ let allEpisodes = []; // Store all episodes globally for reuse throughout the script - +let allShows =[]; +let showEpisodesCache ={}; // Utility function to pad numbers with leading zeros (e.g., 1 becomes 01) function padNumber(number) { return number.toString().padStart(2, '0'); From 54601fa2131d0d19f8ec682a94f59b1e18c4bdc9 Mon Sep 17 00:00:00 2001 From: donarbl Date: Wed, 15 Jan 2025 17:38:04 +0000 Subject: [PATCH 8/8] implemented the fetch for all the shows --- script.js | 104 ++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 70 insertions(+), 34 deletions(-) diff --git a/script.js b/script.js index 83fb8e7..f9a5bc3 100644 --- a/script.js +++ b/script.js @@ -1,12 +1,11 @@ -let allEpisodes = []; // Store all episodes globally for reuse throughout the script -let allShows =[]; -let showEpisodesCache ={}; -// Utility function to pad numbers with leading zeros (e.g., 1 becomes 01) +let allShows = []; +let allEpisodes = []; +let showEpisodesCache = {}; + function padNumber(number) { return number.toString().padStart(2, '0'); } -// Generate HTML structure for an individual episode card function generateEpisodeHTML(episode) { const episodeNumber = `S${padNumber(episode.season)}E${padNumber(episode.number)}`; return ` @@ -20,7 +19,6 @@ function generateEpisodeHTML(episode) { `; } -// Render the list of episodes on the page function renderEpisodes(episodesToDisplay) { const episodesGrid = document.getElementById('episodes-grid'); episodesGrid.innerHTML = episodesToDisplay.map(generateEpisodeHTML).join(''); @@ -28,7 +26,6 @@ function renderEpisodes(episodesToDisplay) { searchResult.textContent = `Showing ${episodesToDisplay.length} out of ${allEpisodes.length} episodes`; } -// Filter episodes based on the search input function filterEpisodes(event) { const searchTerm = event.target.value.toLowerCase(); const filteredEpisodes = allEpisodes.filter(episode => @@ -38,7 +35,6 @@ function filterEpisodes(event) { renderEpisodes(filteredEpisodes); } -// Populate the episode selector dropdown with all episodes function populateEpisodeSelector() { const episodeSelector = document.getElementById('episode-selector'); episodeSelector.innerHTML = ''; @@ -51,7 +47,6 @@ function populateEpisodeSelector() { }); } -// Handle the selection of an episode from the dropdown function handleEpisodeSelection(event) { const selectedEpisodeId = event.target.value; if (selectedEpisodeId) { @@ -62,32 +57,73 @@ function handleEpisodeSelection(event) { } } -// Fetch episodes from the TVMaze API -function fetchEpisodes() { - const episodesGrid = document.getElementById('episodes-grid'); - episodesGrid.innerHTML = '

Loading episodes...

'; - fetch('https://api.tvmaze.com/shows/82/episodes') - .then(response => { - if (!response.ok) { - throw new Error('Failed to fetch episodes'); - } - return response.json(); - }) - .then(data => { - allEpisodes = data; // Store fetched episodes globally - renderEpisodes(allEpisodes); // Display episodes - populateEpisodeSelector(); // Populate dropdown - }) - .catch(error => { +async function fetchShows() { + if (allShows.length === 0) { + const response = await fetch('https://api.tvmaze.com/shows'); + if (!response.ok) { + throw new Error('Failed to fetch shows'); + } + allShows = await response.json(); + allShows.sort((a, b) => a.name.localeCompare(b.name, undefined, { sensitivity: 'base' })); + } + return allShows; +} + +async function fetchEpisodes(showId) { + if (!showEpisodesCache[showId]) { + const response = await fetch(`https://api.tvmaze.com/shows/${showId}/episodes`); + if (!response.ok) { + throw new Error('Failed to fetch episodes'); + } + showEpisodesCache[showId] = await response.json(); + } + return showEpisodesCache[showId]; +} + +function populateShowSelector(shows) { + const showSelector = document.getElementById('show-selector'); + showSelector.innerHTML = ''; + shows.forEach(show => { + const option = document.createElement('option'); + option.value = show.id; + option.textContent = show.name; + showSelector.appendChild(option); + }); +} + +async function handleShowSelection(event) { + const selectedShowId = event.target.value; + if (selectedShowId) { + try { + allEpisodes = await fetchEpisodes(selectedShowId); + renderEpisodes(allEpisodes); + populateEpisodeSelector(); + } catch (error) { + const episodesGrid = document.getElementById('episodes-grid'); episodesGrid.innerHTML = `

Error loading episodes: ${error.message}

`; - }); + } + } else { + allEpisodes = []; + renderEpisodes([]); + populateEpisodeSelector(); + } } -// Set up the page once the DOM content is fully loaded -document.addEventListener('DOMContentLoaded', () => { - fetchEpisodes(); // Fetch episodes from the API - const searchBox = document.getElementById('search-box'); - searchBox.addEventListener('input', filterEpisodes); - const episodeSelector = document.getElementById('episode-selector'); - episodeSelector.addEventListener('change', handleEpisodeSelection); +document.addEventListener('DOMContentLoaded', async () => { + try { + const shows = await fetchShows(); + populateShowSelector(shows); + + const showSelector = document.getElementById('show-selector'); + showSelector.addEventListener('change', handleShowSelection); + + const searchBox = document.getElementById('search-box'); + searchBox.addEventListener('input', filterEpisodes); + + const episodeSelector = document.getElementById('episode-selector'); + episodeSelector.addEventListener('change', handleEpisodeSelection); + } catch (error) { + const episodesGrid = document.getElementById('episodes-grid'); + episodesGrid.innerHTML = `

Error loading shows: ${error.message}

`; + } });