Implementierung eines etxra Fensters für jeden Film -> Infos, Schauspieler, Trailer (YouTube), Spielzeiten Tabelle

This commit is contained in:
2026-06-22 13:28:31 +02:00
parent d913d0c145
commit f8fc262290

367
main.js
View File

@@ -65,7 +65,9 @@ document.addEventListener("DOMContentLoaded", () => {
fsk: "6",
description: "In Walt Disney Animation Studios \"Zoomania 2\" geraten die tierischen Detektive Judy Hopps und Nick Wilde auf die rätselhafte Spur eines geheimnisvollen Reptils, das in Zoomania auftaucht und die Metropole völlig auf den Kopf stellt: Gary DeSnake! ",
poster: "img/Zoomania-2.jpg",
backdrop: "img/Zoomania-2.jpg"
backdrop: "img/Zoomania-2.jpg",
trailerYoutubeId: "https://www.youtube.com/watch?v=RPE_6KbMgYU&pp=ygUZem9vbWFuaWEgMiB0cmFpbGVyIGdlcm1hbg%3D%3D",
actors: ["Name 1", "Name 2", "Name 3"]
},
{
title: "Shelter",
@@ -74,7 +76,9 @@ document.addEventListener("DOMContentLoaded", () => {
fsk: "16",
description: "Michael Mason, ein untergetauchter Elite-Agent, lebt auf einer abgelegenen Insel in Schottland. Als er in einem schweren Sturm ein Mädchen vor dem Ertrinken rettet, setzt er damit eine Kette von Ereignissen in Gang, die sein Versteck enttarnen und ihn zurück in die Welt zwingen. Dort muss er nicht nur um das Überleben der Teenagerin kämpfen, sondern sich auch den Dämonen seiner Vergangenheit stellen…",
poster: "img/shelter.jpg",
backdrop: "img/shelter.jpg"
backdrop: "img/shelter.jpg",
trailerYoutubeId: "https://www.youtube.com/watch?v=_DgEucbPMZI&pp=ygUWc2hlbHRlciB0cmFpbGVyIGdlcm1hbg%3D%3D",
actors: ["Name 1", "Name 2", "Name 3"]
},
{
title: "Mutiny",
@@ -83,7 +87,9 @@ document.addEventListener("DOMContentLoaded", () => {
fsk: "?",
description: "Als sein milliardenschwerer Boss vor seinen Augen einem Mordkomplott zum Opfer fällt, wird Cole Reed (Jason Statham) für das Verbrechen verantwortlich gemacht. Im Bestreben dessen Tod zu rächen und die Täter zu überführen, gelangt Reed an Bord eines Frachters und stößt dabei auf eine internationale Verschwörung. Im Alleingang startet Cole eine gnadenlose Racheaktion auf hoher See…",
poster: "img/mutiny.jpg",
backdrop: "img/mutiny.jpg"
backdrop: "img/mutiny.jpg",
trailerYoutubeId: "https://www.youtube.com/watch?v=DU2cBNrvHA4&pp=ygUObXV0aW55IHRyYWlsZXI%3D",
actors: ["Name 1", "Name 2", "Name 3"],
},
{
title: "Der Austronaut - Project Hail Mary",
@@ -92,7 +98,9 @@ document.addEventListener("DOMContentLoaded", () => {
fsk: "12",
description: "Der Naturwissenschaftslehrer Ryland Grace wacht eines Tages auf einem Raumschiff auf - Lichtjahre von zu Hause entfernt und ohne Erinnerung daran, wer er ist oder wie er dorthin gekommen ist.",
poster: "img/derAustronaut.jpg",
backdrop: "img/derAustronaut.jpg"
backdrop: "img/derAustronaut.jpg",
trailerYoutubeId: "https://www.youtube.com/watch?v=-KXQttVDPyk&pp=ygUdZGVyIGFzdHJvbmF1dCB0cmFpbGVyIGRldXRzY2g%3D",
actors: ["Name 1", "Name 2", "Name 3"]
},
{
title: "Der Super Mario Galaxy Film",
@@ -101,7 +109,9 @@ document.addEventListener("DOMContentLoaded", () => {
fsk: "6",
description: "''Der Super Mario Galaxy Film'' ist der neue Animationsfilm, basierend auf der Welt von „Super Mario Bros.“!",
poster: "img/mariogalaxy.jpg",
backdrop: "img/mariogalaxy.jpg"
backdrop: "img/mariogalaxy.jpg",
trailerYoutubeId:"https://www.youtube.com/watch?v=RtoRPSh0jvM&pp=ygUrZGVyIHN1cGVyIG1hcmlvIGdhbGF4eSBmaWxtIHRyYWlsZXIgZGV1dHNjaA%3D%3D",
actors: ["Name 1", "Name 2", "Name 3"]
},
{
title: "Hoppers",
@@ -110,7 +120,9 @@ document.addEventListener("DOMContentLoaded", () => {
fsk: "6",
description: "In Disney Pixars ''Hoppers'' hoppt Tierfreundin Mabel mithilfe neuester Technologie in einen Roboterbiber und macht die Tierwelt (un)sicher! ",
poster: "img/hoppers.jpg",
backdrop: "img/hoppers.jpg"
backdrop: "img/hoppers.jpg",
trailerYoutubeId: "https://www.youtube.com/watch?v=WqTZZcPe5R0&pp=ygUPaG9wcGVycyB0cmFpbGVy",
actors: ["Name 1", "Name 2", "Name 3"]
},
{
title: "Solo Mio",
@@ -119,7 +131,9 @@ document.addEventListener("DOMContentLoaded", () => {
fsk: "12",
description: "Nachdem er in Rom am Altar stehen gelassen wurde, beschließt ein Mann, allein in die Flitterwochen zu fahren.",
poster: "img/solomio.png",
backdrop: "img/solomio.png"
backdrop: "img/solomio.png",
trailerYoutubeId: "https://www.youtube.com/watch?v=tYtiinTvE3s&pp=ygUYc29sZSBtaW8gdHJhaWxlciBkZXV0c2No",
actors: ["Name 1", "Name 2", "Name 3"]
},
{
title: "The Mandalorian and Grogu",
@@ -128,7 +142,9 @@ document.addEventListener("DOMContentLoaded", () => {
fsk: "?",
description: "Während die Neue Republik daran arbeitet, alles zu schützen, wofür die Rebellion gekämpft hat, sichern sie sich die Unterstützung des legendären mandalorianischen Kopfgeldjägers Din Djarin und seines jungen Lehrlings Grogu. ",
poster: "img/mandalorian.jpeg",
backdrop: "img/mandalorian.jpeg"
backdrop: "img/mandalorian.jpeg",
trailerYoutubeId: "https://www.youtube.com/watch?v=cMJMtGccVfs&pp=ygUlbWFuZGFsb3JpYW4gYW5kIGdyb2d1IHRyYWlsZXIgZGV1dHNjaA%3D%3D",
actors: ["Name 1", "Name 2", "Name 3"]
},
{
title: "Glennkill - Ein Schafskrimi",
@@ -137,7 +153,9 @@ document.addEventListener("DOMContentLoaded", () => {
fsk: "?",
description: "Schäfer George liest seinen geliebten Schafen jeden Abend Krimis vor und nimmt an, dass sie kein Wort davon verstehen. Doch als ein mysteriöser Vorfall das friedliche Leben auf der Farm durchbricht, wird den Schafen bewusst, dass sie selbst nun die Ermittlungen übernehmen müssen. Also folgen sie der Spur der Beweise und machen menschliche Verdächtige ausfindig.",
poster: "img/glennkill.jpg",
backdrop: "img/glennkill.jpg"
backdrop: "img/glennkill.jpg",
trailerYoutubeId: "https://www.youtube.com/watch?v=Ylu6xVTHAlk&pp=ygUZZ2xlbm5raWxsIGVpbiBzY2hhZnNrcmltaQ%3D%3D",
actors: ["Name 1", "Name 2", "Name 3"]
},
{
title: "Masters of the Universe",
@@ -146,7 +164,9 @@ document.addEventListener("DOMContentLoaded", () => {
fsk: "?",
description: "Nach 15 Jahren der Trennung führt das Schwert der Macht Prinz Adam zurück nach Eternia und er entdeckt, dass seine Heimat unter der Herrschaft von Skeletor in Trümmern liegt.",
poster: "img/masteruniverse.jpg",
backdrop: "img/masteruniverse.jpg"
backdrop: "img/masteruniverse.jpg",
trailerYoutubeId: "https://www.youtube.com/watch?v=COJU2b4XZ8U&pp=ygUfbWFzdGVycyBvZiB0aGUgdW5pdmVyc2UgdHJhaWxlcg%3D%3D",
actors: ["Name 1", "Name 2", "Name 3"]
},
{
title: "Minions and Monsters",
@@ -155,7 +175,9 @@ document.addEventListener("DOMContentLoaded", () => {
fsk: "?",
description: "MINIONS & MONSTER erzählt die abgefahrene, aberwitzige und natürlich absolut wahre Geschichte von den Minions und wie sie Hollywood erobern, Filmstars werden, alles verlieren, Monster auf die Welt loslassen und sich dann heldenhaft daranmachen, den Planeten vor genau dem Chaos zu retten, das sie selbst angerichtet haben. ",
poster: "img/minionsmonsters.jpg",
backdrop: "img/minionsmonsters.jpg"
backdrop: "img/minionsmonsters.jpg",
trailerYoutubeId: "https://www.youtube.com/watch?v=a31E7qNxwtI&pp=ygUcbWluaW9ucyBhbmQgbW9uc3RlcnMgdHJhaWxlctIHCQkECwGHKiGM7w%3D%3D",
actors: ["Name 1", "Name 2", "Name 3"]
},
{
title: "Spider Man - Brand New Day",
@@ -334,6 +356,10 @@ document.addEventListener("DOMContentLoaded", () => {
let heroItems = [];
let heroIndex = 0;
let heroTimer = null;
let activeMovieDetail = {
index: null,
sourceCard: null
};
const weekdayShort = ["So", "Mo", "Di", "Mi", "Do", "Fr", "Sa"];
@@ -437,6 +463,29 @@ document.addEventListener("DOMContentLoaded", () => {
`;
};
const getMovieDurationLabel = (movie) => {
const duration = movie?.duration ?? "";
return Number.isFinite(Number(duration)) ? `${duration} Min.` : escapeHtml(duration || "tba");
};
const getYoutubeVideoId = (input) => {
const value = String(input || "").trim();
if (!value) {
return "";
}
const watchMatch = value.match(/[?&]v=([^&]+)/);
const shortMatch = value.match(/youtu\.be\/([^?&/]+)/);
const embedMatch = value.match(/embed\/([^?&/]+)/);
return decodeURIComponent(watchMatch?.[1] || shortMatch?.[1] || embedMatch?.[1] || value);
};
const getYoutubeThumbnailUrl = (videoId) => {
const id = getYoutubeVideoId(videoId);
return id ? `https://i.ytimg.com/vi/${encodeURIComponent(id)}/hqdefault.jpg` : "";
};
const formatDateShort = (dateObj) => {
const day = String(dateObj.getDate()).padStart(2, "0");
const month = String(dateObj.getMonth() + 1).padStart(2, "0");
@@ -499,6 +548,9 @@ document.addEventListener("DOMContentLoaded", () => {
const buildMovieProgram = () => {
movieProgram = movieCatalog.map((movie, movieIndex) => ({
...movie,
trailerYoutubeId: getYoutubeVideoId(movie.trailerYoutubeId || movie.trailerUrl || ""),
trailerThumbnail: getYoutubeThumbnailUrl(movie.trailerYoutubeId || movie.trailerUrl || "") || movie.backdrop || movie.poster,
actors: Array.isArray(movie.actors) ? movie.actors : [],
schedule: buildScheduleForMovie(movieIndex)
}));
heroItems = movieProgram.slice(0, 5);
@@ -575,7 +627,7 @@ document.addEventListener("DOMContentLoaded", () => {
}
ui.nowRunningRow.innerHTML = movieProgram.map((movie, index) => `
<article class="running-poster">
<article class="running-poster" data-program-index="${index}" tabindex="0" role="button" aria-label="Details zu ${escapeHtml(movie.title)} öffnen">
<img src="${escapeHtml(movie.poster)}" alt="${escapeHtml(movie.title)}">
<div class="running-meta">
<h4>${escapeHtml(movie.title)}</h4>
@@ -637,7 +689,7 @@ document.addEventListener("DOMContentLoaded", () => {
<div class="card-right">
<div class="card-header">
<h2>${escapeHtml(movie.title)}</h2>
<span class="duration movie-meta-line">${movie.duration} Min. | ${escapeHtml(movie.genre)} | FSK: ${renderFskMetaLogo(movie)}</span>
<span class="duration movie-meta-line">${getMovieDurationLabel(movie)} | ${escapeHtml(movie.genre)} | FSK: ${renderFskMetaLogo(movie)}</span>
</div>
<div class="program-halls-summary">
<strong>Kinosaal</strong>
@@ -663,6 +715,169 @@ document.addEventListener("DOMContentLoaded", () => {
});
};
const ensureMovieDetailOverlay = () => {
let overlay = document.getElementById("movie-detail-overlay");
if (overlay) {
return overlay;
}
overlay = document.createElement("div");
overlay.id = "movie-detail-overlay";
overlay.className = "movie-detail-overlay hidden";
document.body.appendChild(overlay);
return overlay;
};
const renderMovieDetailScheduleRows = (programIndex, dayIndex) => {
const movie = movieProgram[programIndex];
const day = movie?.schedule?.[dayIndex];
const body = document.getElementById("movie-detail-schedule-body");
if (!movie || !day || !body) {
return;
}
body.innerHTML = day.showings.map((showing) => `
<button class="schedule-row time-chip program-time-row movie-detail-time-row" data-movie="${escapeHtml(movie.title)}" data-hall="${escapeHtml(showing.hall)}" data-time="${escapeHtml(showing.time)}">
<span>${escapeHtml(day.long)}</span>
<span class="hall-pill">${escapeHtml(showing.hall)}</span>
<span class="time-btn">${escapeHtml(showing.time)}</span>
</button>
`).join("");
};
const buildMovieDetailContent = (movie, programIndex) => {
const trailerId = getYoutubeVideoId(movie.trailerYoutubeId);
const trailerThumb = getYoutubeThumbnailUrl(trailerId) || movie.backdrop || movie.poster;
const actorMarkup = movie.actors.length
? movie.actors.map((actor) => `<span>${escapeHtml(actor)}</span>`).join("")
: `<p>Noch keine Schauspieler hinterlegt.</p>`;
const dayTabs = movie.schedule.map((day, dayIndex) => `
<button type="button" class="program-day-tab movie-detail-day-tab ${dayIndex === 0 ? "active" : ""}" data-program-index="${programIndex}" data-day-index="${dayIndex}">
<span>${escapeHtml(day.short)}</span>
<small>${escapeHtml(formatDateShort(day.date))}</small>
</button>
`).join("");
return `
<div class="movie-detail-stage">
<button type="button" class="movie-detail-close" aria-label="Filmdetails schließen">&times;</button>
<div class="movie-detail-backdrop" style="background-image: linear-gradient(180deg, rgba(4, 6, 10, 0.28), #05070a 78%), url('${escapeHtml(movie.backdrop || movie.poster)}');"></div>
<div class="movie-detail-content">
<section class="movie-detail-hero-block">
<div class="movie-detail-poster">
<img src="${escapeHtml(movie.poster)}" alt="${escapeHtml(movie.title)}">
</div>
<div class="movie-detail-copy">
<p class="movie-detail-kicker">Aktueller Film</p>
<h2>${escapeHtml(movie.title)}</h2>
<div class="movie-detail-meta movie-meta-line">
<span>${getMovieDurationLabel(movie)}</span>
<span>${escapeHtml(movie.genre)}</span>
${renderFskMetaLogo(movie)}
</div>
<p>${escapeHtml(movie.description)}</p>
</div>
</section>
<section class="movie-detail-section">
<div class="movie-detail-section-head movie-detail-trailer-head">
<h3>Trailer</h3>
<span class="movie-detail-youtube-logo"><img src="img/youtube-logo.png" alt="YouTube Logo"></span>
</div>
<div class="movie-trailer-frame">
<button type="button" class="movie-trailer-preview" data-trailer-id="${escapeHtml(trailerId)}" style="background-image: linear-gradient(180deg, rgba(0,0,0,0.05), rgba(0,0,0,0.42)), url('${escapeHtml(trailerThumb)}');">
<span class="movie-trailer-play" aria-hidden="true"></span>
<strong>Trailer ansehen</strong>
</button>
</div>
</section>
<section class="movie-detail-section">
<div class="movie-detail-section-head">
<h3>Schauspieler</h3>
<span>Cast</span>
</div>
<div class="movie-actor-list">${actorMarkup}</div>
</section>
<section class="movie-detail-section movie-detail-schedule">
<div class="movie-detail-section-head">
<h3>Spielzeiten</h3>
<span>Nur für diesen Film</span>
</div>
<div class="program-day-tabs">${dayTabs}</div>
<div class="schedule-container program-schedule-shell">
<div class="schedule-header">
<span>Tag</span><span>Kinosaal</span><span>Uhrzeit</span>
</div>
<div id="movie-detail-schedule-body" class="program-schedule-body"></div>
</div>
</section>
</div>
</div>
`;
};
const closeMovieDetail = () => {
const overlay = document.getElementById("movie-detail-overlay");
if (!overlay || overlay.classList.contains("hidden")) {
return;
}
const targetCard = activeMovieDetail.sourceCard?.isConnected ? activeMovieDetail.sourceCard : null;
const rect = targetCard?.getBoundingClientRect();
overlay.classList.remove("is-open");
overlay.classList.add("is-closing");
if (rect) {
overlay.style.left = `${rect.left}px`;
overlay.style.top = `${rect.top}px`;
overlay.style.width = `${rect.width}px`;
overlay.style.height = `${rect.height}px`;
overlay.style.borderRadius = getComputedStyle(targetCard).borderRadius || "20px";
}
setTimeout(() => {
overlay.className = "movie-detail-overlay hidden";
overlay.removeAttribute("style");
overlay.innerHTML = "";
document.body.style.overflow = "auto";
activeMovieDetail = { index: null, sourceCard: null };
}, 430);
};
const openMovieDetail = (programIndex, sourceCard) => {
const movie = movieProgram[programIndex];
if (!movie || !sourceCard) {
return;
}
const overlay = ensureMovieDetailOverlay();
const rect = sourceCard.getBoundingClientRect();
activeMovieDetail = { index: programIndex, sourceCard };
overlay.innerHTML = buildMovieDetailContent(movie, programIndex);
overlay.className = "movie-detail-overlay";
overlay.style.left = `${rect.left}px`;
overlay.style.top = `${rect.top}px`;
overlay.style.width = `${rect.width}px`;
overlay.style.height = `${rect.height}px`;
overlay.style.borderRadius = getComputedStyle(sourceCard).borderRadius || "20px";
document.body.style.overflow = "hidden";
renderMovieDetailScheduleRows(programIndex, 0);
requestAnimationFrame(() => {
overlay.classList.add("is-open");
overlay.style.left = "0px";
overlay.style.top = "0px";
overlay.style.width = "100vw";
overlay.style.height = "100vh";
overlay.style.borderRadius = "0px";
});
};
const initRevealAnimations = () => {
const revealElements = Array.from(document.querySelectorAll(".reveal-on-scroll"));
if (!revealElements.length) {
@@ -749,28 +964,107 @@ document.addEventListener("DOMContentLoaded", () => {
const bindProgramActions = () => {
views.moviesGrid?.addEventListener("click", (event) => {
const trigger = event.target.closest(".open-program-btn");
if (!trigger) {
if (trigger) {
const programIndex = Number(trigger.dataset.programIndex || 0);
showMovieList(programIndex);
return;
}
const programIndex = Number(trigger.dataset.programIndex || 0);
showMovieList(programIndex);
const runningCard = event.target.closest(".running-poster");
if (runningCard) {
const programIndex = Number(runningCard.dataset.programIndex || 0);
openMovieDetail(programIndex, runningCard);
}
});
views.moviesGrid?.addEventListener("keydown", (event) => {
if (event.key !== "Enter" && event.key !== " ") {
return;
}
if (event.target.closest(".open-program-btn")) {
return;
}
const runningCard = event.target.closest(".running-poster");
if (!runningCard) {
return;
}
event.preventDefault();
const programIndex = Number(runningCard.dataset.programIndex || 0);
openMovieDetail(programIndex, runningCard);
});
ui.movieProgramList?.addEventListener("click", (event) => {
const dayButton = event.target.closest(".program-day-tab");
if (!dayButton) {
if (dayButton) {
const programIndex = Number(dayButton.dataset.programIndex || 0);
const dayIndex = Number(dayButton.dataset.dayIndex || 0);
const tabRow = dayButton.closest(".program-day-tabs");
tabRow?.querySelectorAll(".program-day-tab").forEach((tab) => tab.classList.remove("active"));
dayButton.classList.add("active");
renderScheduleRows(programIndex, dayIndex);
return;
}
const programIndex = Number(dayButton.dataset.programIndex || 0);
const dayIndex = Number(dayButton.dataset.dayIndex || 0);
if (event.target.closest("button, a, input, select, textarea")) {
return;
}
const tabRow = dayButton.closest(".program-day-tabs");
tabRow?.querySelectorAll(".program-day-tab").forEach((tab) => tab.classList.remove("active"));
dayButton.classList.add("active");
const movieCard = event.target.closest(".program-card");
if (!movieCard) {
return;
}
renderScheduleRows(programIndex, dayIndex);
const programIndex = Number(movieCard.dataset.programIndex || 0);
openMovieDetail(programIndex, movieCard);
});
};
const bindMovieDetailOverlay = () => {
document.addEventListener("click", (event) => {
const overlay = event.target.closest("#movie-detail-overlay");
if (!overlay) {
return;
}
if (event.target.closest(".movie-detail-close")) {
closeMovieDetail();
return;
}
const dayButton = event.target.closest(".movie-detail-day-tab");
if (dayButton) {
const dayIndex = Number(dayButton.dataset.dayIndex || 0);
overlay.querySelectorAll(".movie-detail-day-tab").forEach((tab) => tab.classList.remove("active"));
dayButton.classList.add("active");
renderMovieDetailScheduleRows(activeMovieDetail.index, dayIndex);
return;
}
const trailerPreview = event.target.closest(".movie-trailer-preview");
if (trailerPreview) {
const trailerId = getYoutubeVideoId(trailerPreview.dataset.trailerId);
const frame = trailerPreview.closest(".movie-trailer-frame");
if (!trailerId || !frame) {
trailerPreview.classList.add("is-missing");
trailerPreview.querySelector("strong").textContent = "Trailer-ID in main.js hinterlegen";
return;
}
frame.innerHTML = `
<iframe src="https://www.youtube-nocookie.com/embed/${encodeURIComponent(trailerId)}?autoplay=1&rel=0" title="YouTube Trailer" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>
`;
}
});
document.addEventListener("keydown", (event) => {
if (event.key === "Escape") {
closeMovieDetail();
}
});
};
@@ -872,6 +1166,10 @@ document.addEventListener("DOMContentLoaded", () => {
const loginEmailInput = document.getElementById("login-email");
const loginPasswordInput = document.getElementById("login-password");
if (typeof initAccountFieldValidation === "function") {
initAccountFieldValidation();
}
const openModal = (modal) => modal?.classList.remove("hidden");
const closeModal = (modal) => modal?.classList.add("hidden");
const triggerLogin = () => {
@@ -882,6 +1180,24 @@ document.addEventListener("DOMContentLoaded", () => {
};
document.getElementById("btn-open-register")?.addEventListener("click", () => {
registerModal?.querySelectorAll("input, select").forEach((input) => {
if (input.type !== "hidden" && input.tagName !== "SELECT") {
input.value = "";
}
if (input.tagName === "SELECT") {
input.value = "Deutschland";
}
if (input.id === "reg-salutation") {
input.value = "";
}
input.dataset.touched = "";
if (typeof clearFieldError === "function") {
clearFieldError(input);
}
});
registerModal?.querySelectorAll(".gender-selector button").forEach((button) => {
button.classList.remove("active");
});
openModal(registerModal);
});
@@ -898,6 +1214,10 @@ document.addEventListener("DOMContentLoaded", () => {
document.getElementById("btn-login-account")?.addEventListener("click", triggerLogin);
[loginEmailInput, loginPasswordInput].forEach((input) => {
input?.addEventListener("input", () => {
loginError?.classList.add("hidden");
});
input?.addEventListener("keydown", (event) => {
if (event.key !== "Enter") {
return;
@@ -1134,6 +1454,7 @@ document.addEventListener("DOMContentLoaded", () => {
initThemeToggle();
bindNavigation();
bindProgramActions();
bindMovieDetailOverlay();
bindHomeInfoNavigation();
bindAccountActions();
bindGlobalDocumentClicks();