| @@ -25,8 +25,22 @@ | ||
| 25 | 25 | this.init(); |
| 26 | 26 | } |
| 27 | 27 | |
| 28 | 28 | init() { |
| 29 | + // Nothing is built here on purpose. The modal markup used to be | |
| 30 | + // injected into <body> as soon as this script loaded — on every | |
| 31 | + // page, including ones with no video. It is now created on the | |
| 32 | + // first play() call, so pages that never play a video never get | |
| 33 | + // the extra DOM. | |
| 34 | + } | |
| 35 | + | |
| 36 | + /** | |
| 37 | + * Build the modal once, on first use. | |
| 38 | + */ | |
| 39 | + ensureModal() { | |
| 40 | + if (this.modal) { | |
| 41 | + return; | |
| 42 | + } | |
| 29 | 43 | this.createModal(); |
| 30 | 44 | this.attachEventListeners(); |
| 31 | 45 | } |
| 32 | 46 | |
| @@ -104,8 +118,9 @@ | ||
| 104 | 118 | } |
| 105 | 119 | |
| 106 | 120 | |
| 107 | 121 | this.currentVideo = video; |
| 122 | + this.ensureModal(); | |
| 108 | 123 | |
| 109 | 124 | // Determine the embed URL |
| 110 | 125 | let embedUrl = ''; |
| 111 | 126 | |
| @@ -166,9 +181,10 @@ | ||
| 166 | 181 | const patterns = [ |
| 167 | 182 | /youtube\.com\/watch\?v=([^&]+)/, |
| 168 | 183 | /youtube\.com\/embed\/([^?]+)/, |
| 169 | 184 | /youtu\.be\/([^?]+)/, |
| 170 | - /youtube\.com\/v\/([^?]+)/ | |
| 185 | + /youtube\.com\/v\/([^?]+)/, | |
| 186 | + /youtube\.com\/shorts\/([^?&]+)/ | |
| 171 | 187 | ]; |
| 172 | 188 | |
| 173 | 189 | for (const pattern of patterns) { |
| 174 | 190 | const match = url.match(pattern); |
| @@ -188,8 +204,11 @@ | ||
| 188 | 204 | |
| 189 | 205 | } |
| 190 | 206 | |
| 191 | 207 | close() { |
| 208 | + if (!this.modal) { | |
| 209 | + return; // never opened on this page | |
| 210 | + } | |
| 192 | 211 | this.modal.style.display = 'none'; |
| 193 | 212 | document.body.style.overflow = ''; |
| 194 | 213 | |
| 195 | 214 | // Stop video playback by clearing iframe src |