| 1 |
(function ($) { |
| 2 |
("use strict"); |
| 3 |
|
| 4 |
$(document).on("click", ".ultp-video-icon", function () { |
| 5 |
const vid = $(this); |
| 6 |
let isAutoPlay = |
| 7 |
vid.attr("enableautoplay") === "true" || |
| 8 |
vid.attr("enableautoplay") === "1"; |
| 9 |
|
| 10 |
const parent = vid.parents(".ultp-block-item"); |
| 11 |
const blockImage = vid.closest(".ultp-block-image"); |
| 12 |
|
| 13 |
// Get settings from video icon attributes |
| 14 |
let enablePopup = |
| 15 |
vid.attr("enableVideoPopup") === "true" || |
| 16 |
vid.attr("enableVideoPopup") === "1"; |
| 17 |
|
| 18 |
// Fix: Get video content based on popup mode |
| 19 |
let videoContent; |
| 20 |
if (enablePopup) { |
| 21 |
// For popup, look for modal video content |
| 22 |
videoContent = parent.find(".ultp-video-modal .ultp-video-wrapper"); |
| 23 |
if (videoContent.length === 0) { |
| 24 |
// Fallback to blockImage if modal not found |
| 25 |
videoContent = blockImage.find( |
| 26 |
"div.ultp-block-video-content .ultp-video-wrapper" |
| 27 |
); |
| 28 |
} |
| 29 |
} else { |
| 30 |
// For inline, use blockImage video content |
| 31 |
videoContent = blockImage.find( |
| 32 |
"div.ultp-block-video-content .ultp-video-wrapper" |
| 33 |
); |
| 34 |
blockImage.find("div.ultp-block-video-content").show(); |
| 35 |
} |
| 36 |
|
| 37 |
// Check if video content exists |
| 38 |
if (videoContent.length === 0) { |
| 39 |
console.error("Video content wrapper not found"); |
| 40 |
return; |
| 41 |
} |
| 42 |
|
| 43 |
const videoData = { |
| 44 |
url: videoContent.data("video-url"), |
| 45 |
id: videoContent.data("video-id"), |
| 46 |
type: videoContent.data("video-type"), |
| 47 |
autoplay: videoContent.data("autoplay"), |
| 48 |
loop: videoContent.data("loop"), |
| 49 |
mute: videoContent.data("mute"), |
| 50 |
controls: videoContent.data("controls"), |
| 51 |
preload: videoContent.data("preload"), |
| 52 |
poster: videoContent.data("poster"), |
| 53 |
playsinline: videoContent.data("playsinline"), |
| 54 |
width: videoContent.data("width"), |
| 55 |
height: videoContent.data("height"), |
| 56 |
}; |
| 57 |
|
| 58 |
// Extract video ID if not available |
| 59 |
let videoId = videoData.id; |
| 60 |
if (!videoId && videoData.url) { |
| 61 |
switch (videoData.type) { |
| 62 |
case "youtube": |
| 63 |
const youtubeRegex = |
| 64 |
/(?:youtu\.be\/|youtube\.com\/(?:embed\/|v\/|watch\?v=|watch\?.+&v=))((\w|-){11})/; |
| 65 |
const youtubeMatch = videoData.url.match(youtubeRegex); |
| 66 |
videoId = youtubeMatch ? youtubeMatch[1] : null; |
| 67 |
break; |
| 68 |
case "vimeo": |
| 69 |
const vimeoRegex = |
| 70 |
/vimeo\.com\/(?:channels\/(?:\w+\/)?|groups\/([^\/]*)\/videos\/|album\/(\d+)\/video\/|video\/|)(\d+)(?:$|\/|\?)/; |
| 71 |
const vimeoMatch = videoData.url.match(vimeoRegex); |
| 72 |
videoId = vimeoMatch ? vimeoMatch[vimeoMatch.length - 1] : null; |
| 73 |
break; |
| 74 |
case "local": |
| 75 |
videoId = "local"; |
| 76 |
break; |
| 77 |
} |
| 78 |
} |
| 79 |
|
| 80 |
// Return early if no video ID found and it's not a local video |
| 81 |
if (!videoId && videoData.type !== "local") { |
| 82 |
console.error(`${videoData.type} video ID not found`); |
| 83 |
return; |
| 84 |
} |
| 85 |
|
| 86 |
// Fix: Clear existing video content before adding new |
| 87 |
videoContent.empty(); |
| 88 |
|
| 89 |
// Generate iframe based on video type |
| 90 |
let embedHtml = ""; |
| 91 |
|
| 92 |
switch (videoData.type) { |
| 93 |
case "youtube": |
| 94 |
const youtubeParams = new URLSearchParams({ |
| 95 |
autoplay: isAutoPlay ? "1" : "0", |
| 96 |
loop: videoData.loop ? "1" : "0", |
| 97 |
mute: videoData.mute || isAutoPlay ? "1" : "0", |
| 98 |
controls: videoData.controls ? "1" : "0", |
| 99 |
playsinline: videoData.playsinline ? "1" : "0", |
| 100 |
modestbranding: "1", |
| 101 |
rel: "0", |
| 102 |
}); |
| 103 |
|
| 104 |
if (videoData.loop && videoId) { |
| 105 |
youtubeParams.append("playlist", videoId); |
| 106 |
} |
| 107 |
|
| 108 |
embedHtml = `<iframe |
| 109 |
src="https://www.youtube.com/embed/${videoId}?${youtubeParams.toString()}" |
| 110 |
width="${videoData.width || "100%"}" |
| 111 |
height="${videoData.height || "315"}" |
| 112 |
frameborder="0" |
| 113 |
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" |
| 114 |
allowfullscreen |
| 115 |
loading="lazy"> |
| 116 |
</iframe>`; |
| 117 |
break; |
| 118 |
|
| 119 |
case "vimeo": |
| 120 |
const vimeoParams = new URLSearchParams({ |
| 121 |
autoplay: isAutoPlay ? "1" : "0", |
| 122 |
loop: videoData.loop ? "1" : "0", |
| 123 |
muted: videoData.mute || isAutoPlay ? "1" : "0", |
| 124 |
controls: videoData.controls ? "1" : "0", |
| 125 |
playsinline: videoData.playsinline ? "1" : "0", |
| 126 |
dnt: "1", |
| 127 |
}); |
| 128 |
|
| 129 |
embedHtml = `<iframe |
| 130 |
src="https://player.vimeo.com/video/${videoId}?${vimeoParams.toString()}" |
| 131 |
width="${videoData.width || "100%"}" |
| 132 |
height="${videoData.height || "315"}" |
| 133 |
frameborder="0" |
| 134 |
allow="autoplay; fullscreen; picture-in-picture" |
| 135 |
allowfullscreen |
| 136 |
loading="lazy"> |
| 137 |
</iframe>`; |
| 138 |
break; |
| 139 |
|
| 140 |
case "local": |
| 141 |
const videoFormat = videoData.url |
| 142 |
.split(".") |
| 143 |
.pop() |
| 144 |
.toLowerCase() |
| 145 |
.split("?")[0]; |
| 146 |
const formats = { |
| 147 |
mp4: "mp4", |
| 148 |
webm: "webm", |
| 149 |
ogg: "ogg", |
| 150 |
avi: "mp4", |
| 151 |
mov: "mp4", |
| 152 |
}; |
| 153 |
const mimeType = formats[videoFormat] || "mp4"; |
| 154 |
|
| 155 |
const attributes = []; |
| 156 |
if (isAutoPlay) { |
| 157 |
attributes.push("autoplay"); |
| 158 |
attributes.push("muted"); |
| 159 |
} |
| 160 |
if (videoData.loop) attributes.push("loop"); |
| 161 |
if (videoData.controls) attributes.push("controls"); |
| 162 |
if (videoData.playsinline) attributes.push("playsinline"); |
| 163 |
if (videoData.poster) attributes.push(`poster="${videoData.poster}"`); |
| 164 |
if (videoData.preload) |
| 165 |
attributes.push(`preload="${videoData.preload}"`); |
| 166 |
|
| 167 |
embedHtml = `<video ${attributes.join(" ")} |
| 168 |
width="${videoData.width || "100%"}" |
| 169 |
height="${videoData.height || "auto"}" |
| 170 |
class="ultp-video-html"> |
| 171 |
<source src="${videoData.url}" type="video/${mimeType}"> |
| 172 |
<p>Your browser does not support the video tag. |
| 173 |
<a href="${ |
| 174 |
videoData.url |
| 175 |
}" target="_blank">Download the video</a> |
| 176 |
</p> |
| 177 |
</video>`; |
| 178 |
break; |
| 179 |
|
| 180 |
default: |
| 181 |
console.error(`Unsupported video type: ${videoData.type}`); |
| 182 |
return; |
| 183 |
} |
| 184 |
|
| 185 |
// Return early if no embed HTML generated |
| 186 |
if (!embedHtml) { |
| 187 |
console.error("Failed to generate video embed"); |
| 188 |
return; |
| 189 |
} |
| 190 |
|
| 191 |
// Append the generated embed HTML |
| 192 |
videoContent.html(embedHtml); |
| 193 |
|
| 194 |
// Handle popup vs inline display |
| 195 |
if (enablePopup) { |
| 196 |
// Fix: Show video in modal popup |
| 197 |
const modal = parent.find(".ultp-video-modal"); |
| 198 |
if (modal.length > 0) { |
| 199 |
modal.addClass("modal_active"); |
| 200 |
|
| 201 |
// Fix: Show modal content and hide loader |
| 202 |
modal.find(".ultp-video-modal__content").show(); |
| 203 |
$(".ultp-loader-container").hide(); |
| 204 |
|
| 205 |
// Fix: Focus management for accessibility |
| 206 |
modal.attr("tabindex", "-1").focus(); |
| 207 |
} else { |
| 208 |
console.error("Video modal not found"); |
| 209 |
return; |
| 210 |
} |
| 211 |
} else { |
| 212 |
// Inline video display without popup |
| 213 |
blockImage.find("> a img").hide(); |
| 214 |
videoContent.parent().css({ display: "block" }); |
| 215 |
vid.hide(); |
| 216 |
} |
| 217 |
|
| 218 |
// Auto-play handling for local videos |
| 219 |
const videoElement = videoContent.find("video"); |
| 220 |
if (isAutoPlay && videoElement.length > 0) { |
| 221 |
setTimeout(() => { |
| 222 |
videoElement[0] |
| 223 |
.play() |
| 224 |
.catch((e) => console.log("Autoplay prevented:", e)); |
| 225 |
}, 500); |
| 226 |
} |
| 227 |
|
| 228 |
// Hide loader when video loads |
| 229 |
const allVideoElements = videoContent.find("iframe, video"); |
| 230 |
if (allVideoElements.length) { |
| 231 |
allVideoElements.on("load loadeddata canplay", function () { |
| 232 |
$(".ultp-loader-container").hide(); |
| 233 |
}); |
| 234 |
} |
| 235 |
}); |
| 236 |
|
| 237 |
// Fix: Close modal on click (improved) |
| 238 |
$(document).on("click", ".ultp-video-close, .ultp-video-modal", function (e) { |
| 239 |
// Only close if clicking the close button or modal backdrop |
| 240 |
if ($(this).hasClass("ultp-video-close") || e.target === this) { |
| 241 |
closeVideoModal(); |
| 242 |
} |
| 243 |
}); |
| 244 |
|
| 245 |
// Prevent modal close when clicking modal content |
| 246 |
$(document).on("click", ".ultp-video-modal__content", function (e) { |
| 247 |
e.stopPropagation(); |
| 248 |
}); |
| 249 |
|
| 250 |
// Close modal on escape key |
| 251 |
$(document).on("keyup", function (e) { |
| 252 |
if (e.key === "Escape" || e.keyCode === 27) { |
| 253 |
closeVideoModal(); |
| 254 |
} |
| 255 |
}); |
| 256 |
|
| 257 |
// Fix: Improved close modal function |
| 258 |
function closeVideoModal() { |
| 259 |
const activeModal = $(".ultp-video-modal.modal_active"); |
| 260 |
if (activeModal.length > 0) { |
| 261 |
const videoIframe = activeModal.find("iframe"); |
| 262 |
const videoElement = activeModal.find("video"); |
| 263 |
|
| 264 |
// Stop iframe videos |
| 265 |
if (videoIframe.length) { |
| 266 |
videoIframe.each(function () { |
| 267 |
const iframe = $(this); |
| 268 |
const videoSrc = iframe.attr("src"); |
| 269 |
if (videoSrc) { |
| 270 |
// Force stop by removing and re-adding src |
| 271 |
iframe.attr("src", ""); |
| 272 |
setTimeout(() => { |
| 273 |
iframe.remove(); |
| 274 |
}, 100); |
| 275 |
} |
| 276 |
}); |
| 277 |
} |
| 278 |
|
| 279 |
// Stop HTML5 videos |
| 280 |
if (videoElement.length) { |
| 281 |
videoElement.each(function () { |
| 282 |
this.pause(); |
| 283 |
this.currentTime = 0; |
| 284 |
}); |
| 285 |
} |
| 286 |
|
| 287 |
// Hide modal and clear content |
| 288 |
activeModal.removeClass("modal_active"); |
| 289 |
activeModal.find(".ultp-video-wrapper").empty(); |
| 290 |
|
| 291 |
// Return focus to the video icon |
| 292 |
activeModal.closest(".ultp-block-item").find(".ultp-video-icon").focus(); |
| 293 |
} |
| 294 |
} |
| 295 |
|
| 296 |
// ...existing code... |
| 297 |
})(jQuery); |
| 298 |
|