1import { Controller } from "../stimulus.js"; 2 3export default class extends Controller { 4 static targets = ["modal", "iframe", "title"]; 5 6 connect() { 7 this._onClose = this.handleModalClose.bind(this); 8 this.modalTarget.addEventListener("close", this._onClose); 9 } 10 11 disconnect() { 12 this.modalTarget.removeEventListener("close", this._onClose); 13 if (this.hasIframeTarget) this.iframeTarget.src = ""; 14 document.body.classList.remove("overflow-hidden"); 15 } 16 17 open(event) { 18 const button = event.currentTarget; 19 const videoUrl = button.dataset.videoUrl; 20 const videoTitle = button.dataset.videoTitle; 21 22 if (!videoUrl) return; 23 const videoId = this.extractVideoId(videoUrl); 24 if (!videoId) return; 25 26 this.titleTarget.textContent = videoTitle || "Video"; 27 this.iframeTarget.src = `https://www.youtube.com/embed/${videoId}?autoplay=1&rel=0`; 28 this.modalTarget.showModal(); 29 document.body.classList.add("overflow-hidden"); 30 } 31 32 close() { 33 this.iframeTarget.src = ""; 34 this.modalTarget.close(); 35 } 36 37 handleModalClose() { 38 this.iframeTarget.src = ""; 39 document.body.classList.remove("overflow-hidden"); 40 } 41 42 clickOutside(event) { 43 if (event.target === this.modalTarget) this.close(); 44 } 45 46 extractVideoId(url) { 47 const watchMatch = url.match(/[?&]v=([^&]+)/); 48 if (watchMatch) return watchMatch[1]; 49 const shareMatch = url.match(/youtu\.be\/([^?]+)/); 50 if (shareMatch) return shareMatch[1]; 51 return null; 52 } 53}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.