328 lines
6.7 KiB
JavaScript
328 lines
6.7 KiB
JavaScript
import {
|
|
handlePauseClasses,
|
|
handlePlayClasses,
|
|
pauseVideo,
|
|
playVideo,
|
|
muteVideo,
|
|
maybePlayAutoplayedVideo,
|
|
subscribeForStateChanges
|
|
} from '../helpers/video'
|
|
|
|
import { isIosDevice } from '../helpers/is-ios-device'
|
|
|
|
import { loadStyle } from '../../helpers'
|
|
|
|
import { getScalarOrCallback } from '../helpers/get-scalar-or-callback'
|
|
|
|
const store = {}
|
|
|
|
const cachedFetch = (url) =>
|
|
store[url]
|
|
? new Promise((resolve) => {
|
|
resolve(store[url])
|
|
store[url] = store[url].clone()
|
|
})
|
|
: new Promise((resolve) =>
|
|
fetch(url).then((response) => {
|
|
resolve(response)
|
|
store[url] = response.clone()
|
|
})
|
|
)
|
|
|
|
export const fetchVideoBy = (mediaId, args = {}) => {
|
|
args = {
|
|
ignoreVideoOptions: false,
|
|
...args
|
|
}
|
|
|
|
let url =
|
|
ct_localizations.ajax_url +
|
|
'?action=blocksy_get_image_video_component&media=' +
|
|
mediaId
|
|
|
|
if (args.ignoreVideoOptions) {
|
|
url += '&ignore_video_options=true'
|
|
}
|
|
|
|
return new Promise((resolve) => {
|
|
cachedFetch(url).then((r) => {
|
|
if (r.status === 200) {
|
|
r.json().then(({ success, data }) => {
|
|
if (!success) {
|
|
return
|
|
}
|
|
|
|
resolve(data)
|
|
})
|
|
}
|
|
})
|
|
})
|
|
}
|
|
|
|
const listenForStateChanges = (videoOrIframe, args = {}) => {
|
|
args = {
|
|
onPause: () => {},
|
|
onPlay: () => {},
|
|
|
|
onReady: () => {},
|
|
|
|
...args
|
|
}
|
|
|
|
if (videoOrIframe.isListeningForStateChanges) {
|
|
return
|
|
}
|
|
|
|
videoOrIframe.isListeningForStateChanges = true
|
|
|
|
subscribeForStateChanges(videoOrIframe, (e) => {
|
|
if (e === 'pause') {
|
|
handlePauseClasses(videoOrIframe)
|
|
args.onPause()
|
|
}
|
|
|
|
if (e === 'play') {
|
|
args.onPlay()
|
|
handlePlayClasses(videoOrIframe)
|
|
}
|
|
|
|
if (e === 'ready') {
|
|
args.onReady()
|
|
}
|
|
})
|
|
}
|
|
|
|
const loadVideoOrIframeViaAjax = (el) => {
|
|
el.querySelector('.ct-video-indicator').classList.add('loading')
|
|
const hasRevert =
|
|
el.dataset.state &&
|
|
el.dataset.state.indexOf('hover') !== -1 &&
|
|
el.dataset.state.indexOf('revert') !== -1
|
|
|
|
fetchVideoBy(el.dataset.mediaId).then((data) => {
|
|
const div = document.createElement('div')
|
|
div.innerHTML = data.html
|
|
const insertVideo = div.firstChild
|
|
if (el.querySelector('.ct-dynamic-media-inner')) {
|
|
el.querySelector('.ct-dynamic-media-inner').insertAdjacentElement(
|
|
'beforeend',
|
|
insertVideo
|
|
)
|
|
} else {
|
|
el.insertAdjacentElement('beforeend', insertVideo)
|
|
}
|
|
|
|
const videoOrIframe = el.querySelector('video,iframe')
|
|
const flexyContainer = videoOrIframe.closest(
|
|
'.flexy-container[data-autoplay]'
|
|
)
|
|
const flexyInstance = flexyContainer?.flexy
|
|
|
|
listenForStateChanges(videoOrIframe, {
|
|
onPlay: () => {
|
|
setTimeout(() => {
|
|
el.querySelector('.ct-video-indicator').classList.remove(
|
|
'loading'
|
|
)
|
|
}, 120)
|
|
|
|
if (flexyInstance) {
|
|
flexyInstance.options = {
|
|
...flexyInstance.options,
|
|
autoplay: false,
|
|
_autoplay: false
|
|
}
|
|
}
|
|
},
|
|
|
|
onPause: () => {
|
|
if (flexyInstance) {
|
|
flexyInstance.options = {
|
|
...flexyInstance.options,
|
|
autoplay: parseInt(flexyContainer.dataset.autoplay),
|
|
_autoplay: parseInt(flexyContainer.dataset.autoplay)
|
|
}
|
|
|
|
flexyInstance.state = {
|
|
...flexyInstance.state,
|
|
lastTimeAnimated: new Date().getTime()
|
|
}
|
|
}
|
|
|
|
if (
|
|
hasRevert &&
|
|
!el.classList.contains('ct-simplified-player')
|
|
) {
|
|
el.dataset.state = 'hover:paused'
|
|
}
|
|
},
|
|
|
|
onReady: () => {
|
|
if (isIosDevice()) {
|
|
muteVideo(videoOrIframe)
|
|
}
|
|
|
|
playVideo(videoOrIframe)
|
|
}
|
|
})
|
|
})
|
|
}
|
|
|
|
const loadVideoWithStyles = (el) => {
|
|
const maybeMatchingContainer =
|
|
ct_localizations.dynamic_styles_selectors.find(
|
|
(descriptor) =>
|
|
'.ct-media-container[data-media-id], .ct-dynamic-media[data-media-id]' ===
|
|
descriptor.selector
|
|
)
|
|
|
|
if (maybeMatchingContainer) {
|
|
loadStyle(maybeMatchingContainer.url).then(() => {
|
|
loadVideoOrIframeViaAjax(el)
|
|
})
|
|
}
|
|
}
|
|
|
|
ctEvents.on('blocksy:frontend:flexy:slide-change', ({ instance, payload }) => {
|
|
const sliderContainer = getScalarOrCallback(instance.sliderContainer)
|
|
|
|
;[...sliderContainer.querySelectorAll('video,iframe')].map(
|
|
(videoOrIframe) => pauseVideo(videoOrIframe)
|
|
)
|
|
|
|
const currentSlide = sliderContainer.children[
|
|
payload.currentIndex
|
|
].querySelector(
|
|
'.ct-media-container[data-media-id], .ct-dynamic-media[data-media-id]'
|
|
)
|
|
|
|
if (!currentSlide) {
|
|
return
|
|
}
|
|
|
|
const maybeVideoOrIframeFromCurrentSlide =
|
|
currentSlide.querySelector('video,iframe')
|
|
|
|
if (maybeVideoOrIframeFromCurrentSlide) {
|
|
maybePlayAutoplayedVideo(maybeVideoOrIframeFromCurrentSlide)
|
|
return
|
|
}
|
|
|
|
processInitialAutoplayFor(currentSlide, {
|
|
performVisibilityCheck: false
|
|
})
|
|
})
|
|
|
|
ctEvents.on('blocksy:ajax:filters:done', () => {
|
|
;[...document.querySelectorAll('.ct-media-container[data-media-id]')].map(
|
|
(el) => {
|
|
processInitialAutoplayFor(el)
|
|
}
|
|
)
|
|
})
|
|
|
|
const processInitialAutoplayFor = (el, args = {}) => {
|
|
args = {
|
|
performVisibilityCheck: true,
|
|
...args
|
|
}
|
|
|
|
if (!el.matches('[data-state*="autoplay"]')) {
|
|
return
|
|
}
|
|
|
|
let isVisible = true
|
|
|
|
if (args.performVisibilityCheck && el.closest('.flexy-items')) {
|
|
const box = el.getBoundingClientRect()
|
|
const parentBox = el.closest('.flexy-items').getBoundingClientRect()
|
|
|
|
isVisible =
|
|
box.left >= parentBox.left &&
|
|
box.left <= parentBox.left + parentBox.width &&
|
|
box.top >= parentBox.top &&
|
|
box.top <= parentBox.top + parentBox.height
|
|
}
|
|
|
|
if (isVisible) {
|
|
el.removeAttribute('data-state')
|
|
loadVideoWithStyles(el)
|
|
}
|
|
}
|
|
|
|
let mounted = false
|
|
|
|
export const mount = (el, { event }) => {
|
|
if (!event || event.type === 'scroll') {
|
|
if (mounted) {
|
|
return
|
|
}
|
|
|
|
mounted = true
|
|
|
|
const cb = () => {
|
|
;[
|
|
...document.querySelectorAll(
|
|
'.ct-media-container[data-media-id], .ct-dynamic-media[data-media-id]'
|
|
)
|
|
].map((el) => {
|
|
processInitialAutoplayFor(el)
|
|
})
|
|
}
|
|
|
|
ctEvents.on('blocksy:frontend:init', () => {
|
|
cb()
|
|
})
|
|
|
|
cb()
|
|
|
|
return
|
|
}
|
|
|
|
if (event && event.type === 'mouseover') {
|
|
if (!el.hasMouseLeaveListener) {
|
|
el.hasMouseLeaveListener = true
|
|
|
|
el.addEventListener('mouseenter', () => {
|
|
const videoOrIframe = el.querySelector('video,iframe')
|
|
|
|
playVideo(videoOrIframe)
|
|
})
|
|
|
|
if (el.dataset.state.indexOf('revert') !== -1) {
|
|
el.addEventListener('mouseleave', () => {
|
|
const videoOrIframe = el.querySelector('video,iframe')
|
|
|
|
pauseVideo(videoOrIframe, {
|
|
shouldRevert: true
|
|
})
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Case when video is already loaded
|
|
* if it is not simplified player, we use native controls
|
|
* and we don't need to handle click to play/pause
|
|
*/
|
|
const maybeVideo = el.querySelector('video')
|
|
if (maybeVideo && !el.closest('.ct-simplified-player')) {
|
|
return
|
|
}
|
|
|
|
const videoOrIframe = el.querySelector('video,iframe')
|
|
|
|
if (videoOrIframe) {
|
|
if (el.matches('[data-state="playing"]')) {
|
|
pauseVideo(videoOrIframe)
|
|
} else {
|
|
playVideo(videoOrIframe)
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
loadVideoWithStyles(el)
|
|
}
|