!function(e,s){Drupal.behaviors.heroCarouselFormatterV1={attached:!1,attach:function(a){if(!this.attached){this.attached=!0;var r,t=e(".js-hero-carousel-formatter-v1",a);t.each((function(){var a=e(this),t=s.translations.elc_general&&s.translations.elc_general.next?s.translations.elc_general.next:"next",o=s.translations.elc_general&&s.translations.elc_general.previous?s.translations.elc_general.previous:"previous",i=a.find(".js-hero-carousel-formatter__container"),l=a.find(".js-hero-carousel-formatter__controls"),n='',c='',d=(r=i).data("slides-autoplay")||!1,u=r.data("slides-infinite")||!1,p=parseInt(i.data("slides-speed")),v=parseInt(i.data("slides-speedplay")),h=parseInt(i.data("slides-scroll"));isNaN(p)&&(p=6e3),isNaN(v)&&(v=300),isNaN(h)&&(h=1);var g={appendArrows:l,slide:".js-hero-carousel-formatter__container-slide",infinite:u,slidesToShow:2,slidesToScroll:h,autoplay:d,autoplaySpeed:p,speed:v,arrows:!0,prevArrow:n,nextArrow:c,responsive:[{breakpoint:1024,settings:{arrows:!0,slidesToShow:1,slidesToScroll:1}}]};r.not(".slick-initialized").slick(g)}))}}}}(jQuery,window.site||{}); ; !function(r){Drupal.behaviors.editorialGridFormatterV1={attach:function(e,i){r(".js-editorial-grid-formatter-v1",e).each((function(){var e=r(this),o=e.find(".js-editorial-grid-formatter__carousel"),s=e.find(".editorial-grid-formatter__carousel-controls"),t=e.find(".editorial-grid-formatter__carousel-dots"),a=o.attr("data-slides-pc"),d=o.attr("data-slides-mob"),l={arrows:!0,appendArrows:s,prevArrow:'',nextArrow:'',dots:!0,appendDots:t,infinite:!(e.data("slides-pc")&&e.data("slides-pc")>1),slidesToShow:parseFloat(a)||0,slidesToScroll:1,rtl:site.direction.isRTL,autoplaySpeed:5e3,adaptiveHeight:!1,pauseOnFocus:!0,responsive:[{breakpoint:1024,settings:{adaptiveHeight:!1,slidesToShow:parseFloat(d)||0}}]};const n=i.slick_slider_align_resize||!1;if(o.slick(l),n){let e;const i=()=>{const r=o.find(".js-slick-slide-card-content"),e=r.get().map((r=>r.scrollHeight)),i=Math.max(...e);r.css("height",`${i}px`)};e=_.debounce(i,250),r(window).on("resize",e),i();const s=()=>{e&&(r(window).off("resize",e),e=null)};r(window).on("beforeunload",s)}}))}}}(jQuery); ; /*global JSBoot */ var MantleVideo = MantleVideo || {}; window.site = window.site || {}; var site = window.site; (function($) { /* * Video Player manager that handles cuepoints. * * TODO: This might want to merge with ELCVideoJS. */ var MantleVideoPlayer = function($videoPlayer) { if (!$videoPlayer.is('.js-mantle-video-player')) { throw new Error('Needs to attach to js-mantle-video-player element'); } this.$videoPlayer = $videoPlayer; this.$videoElement = $('.js-videojs-video', $videoPlayer); this.$cuepointTarget = $('.js-video-cuepoint-target', $videoPlayer); this.$cuepointContainer = $('.js-video-cuepoint-container', $videoPlayer); this.$cuepoints = $('.js-video-cuepoint', this.$cuepointContainer); this.cuepointTargetDisplayed = this.$cuepointTarget.css('display') !== 'none' ? true : false; this.markerInfo = null; this.videoElementController = null; this.init(); $videoPlayer.data('mantle-video-player-manager', this); }; /* * Static method to get attach Manager. */ MantleVideoPlayer.getManager = function($dom) { if ($dom.data('mantle-video-player-manager')) { return $dom.data('mantle-video-player-manager'); } return null; }; MantleVideoPlayer.getVideoPlayerDom = function(context) { var $context = $(context); if ($context.is('.js-mantle-video-player')) { return $context; } var $videoPlayer = $('.js-mantle-video-player', $context); return $videoPlayer; }; MantleVideoPlayer.prototype.clone = function() { var $videoPlayerClone = this.$videoPlayer.clone(); var mantleVideoPlayerClone = new MantleVideo.MantleVideoPlayer($videoPlayerClone); return mantleVideoPlayerClone; }; MantleVideoPlayer.prototype.init = function() { var self = this; var $videoPlayer = this.$videoPlayer; var $videoElement = this.$videoElement; // already inited. bye if ($videoPlayer.data('video-player-initialized')) { return; } // Run the attach for the video element contained within the player. var elcVideo = new MantleVideo.ELCVideoJS($videoElement); this.videoElementController = elcVideo; // HACK for now. // Process cuepointers after drupal attach. so that timeline reaction // behaviors have the chance to attach. $(function() { self.setupMarkers(); }); this.attachDomEvents(); $videoPlayer.data('video-player-initialized', 1); }; MantleVideoPlayer.prototype.setupMarkers = function() { var $videoElement = this.$videoElement; var onLoadMarkers = this.getOnLoadMarkers(); var timelineMarkers = this.getTimelineMarkers(); var cuepointTargetDisplayed = this.cuepointTargetDisplayed; var $cuepointContainer = this.$cuepointContainer; // TODO think about moving all the marker logic up to this level. We // can handle the markers at this level if we subscribe to tick events // from the video element. // For now, the timeline markers are being handled via video.js and the // plugin $videoElement.trigger('video-set-markers', [timelineMarkers]); if (cuepointTargetDisplayed) { $cuepointContainer.addClass('video-cuepoint-mobile'); } else { $cuepointContainer.removeClass('video-cuepoint-mobile'); } // activate the on_load markers $.each(onLoadMarkers, function(i, obj) { var onLoadMarker = obj; onLoadMarker.$content.addClass('on_load-marker'); $videoElement.trigger('video-add-current-marker', [onLoadMarker]); onLoadMarker.$content.trigger('cuepoint-reached', [onLoadMarker]); if (cuepointTargetDisplayed) { $cuepointContainer.height(onLoadMarker.$content.height()); } else { $cuepointContainer.height(''); } }); }; // Utils to get markers MantleVideoPlayer.prototype.getOnLoadMarkers = function() { var markerInfo = this.getMarkerInfo(); return markerInfo.onLoadMarkers; }; MantleVideoPlayer.prototype.getOnEndMarkers = function() { var markerInfo = this.getMarkerInfo(); return markerInfo.onEndMarkers; }; MantleVideoPlayer.prototype.getTimelineMarkers = function() { var markerInfo = this.getMarkerInfo(); return markerInfo.timelineMarkers; }; /* * Process the timeline reaction objects and collect the markers. */ MantleVideoPlayer.prototype.getMarkerInfo = function() { var $cuepoints = this.$cuepoints; var cuepointTargetDisplayed = this.cuepointTargetDisplayed; // Only generate this once. if (this.markerInfo !== null) { return this.markerInfo; } var timelineMarkers = []; var onLoadMarkers = []; var onEndMarkers = []; var allMarkers = []; // eslint-disable-next-line complexity $cuepoints.each(function(i, obj) { var $cuepoint = $(obj); var $next = $($cuepoints.get(i + 1)); var marker = { '$content': $cuepoint, 'mantle_key': JSBoot.generateUUID(), }; var time = $cuepoint.data('time'); if (time || time === 0) { marker['time'] = time; timelineMarkers.push(marker); } var duration = $cuepoint.data('duration'); if (cuepointTargetDisplayed) { // Set duration till the next element for mobile. if ($next.length && $next.data('time')) { var nexTime = $next.data('time'); duration = nexTime - time; } else { // Set a large time for the last element duration = 1000; } } else if (!duration) { duration = 5; } marker['time_duration'] = duration; if ($cuepoint.data('show-on-load')) { onLoadMarkers.push(marker); } if ($cuepoint.data('show-on-end')) { onEndMarkers.push(marker); } allMarkers.push(marker); }); var markerInfo = { allMarkers: allMarkers, timelineMarkers: timelineMarkers, onLoadMarkers: onLoadMarkers, onEndMarkers: onEndMarkers, }; this.markerInfo = markerInfo; return markerInfo; }; /* * Attach Dom listeners. */ MantleVideoPlayer.prototype.attachDomEvents = function() { var self = this; var $videoPlayer = this.$videoPlayer; var $videoElement = this.$videoElement; var $cuepointContainer = this.$cuepointContainer; var cuepointTargetDisplayed = this.cuepointTargetDisplayed; var $chapterizedVideoBlock = $videoPlayer.closest('.js-chapterized-video-wrapper'); var $chapterDetails = $('.js-chapterized-video', $chapterizedVideoBlock); var $cuepoints = this.$cuepoints; var $videoBlock = $videoPlayer.closest('.js-video-block'); var $window = $(window); $videoElement.on('video-marker-reached', function(e, marker) { marker.$content.trigger('cuepoint-reached', [marker]); if (cuepointTargetDisplayed) { $cuepointContainer.height(marker.$content.height()); } else { $cuepointContainer.height(''); } }); $videoElement.on('video-marker-exited', function(e, marker) { marker.$content.trigger('cuepoint-exited', [marker]); }); // Display the control panel on touch and mouseovering chapter details. function addClassOnChapterHoverAndTouch() { $videoPlayer.addClass('chapters-hovered'); } $chapterDetails.on('mouseenter', addClassOnChapterHoverAndTouch).on('mouseleave', function () { $videoPlayer.removeClass('chapters-hovered'); }); $chapterDetails.on('touchstart', function () { addClassOnChapterHoverAndTouch(); setTimeout(function () { $videoPlayer.removeClass('chapters-hovered'); }, 5000); }); // Display the control panel and chapter details on pause. $videoElement.on('click', function () { var $currentVideoElement = $(this).closest($videoPlayer).find('.video-js'); setTimeout(function () { if ($currentVideoElement.hasClass('vjs-has-started') && $currentVideoElement.hasClass('vjs-paused')) { $videoPlayer.addClass('paused'); } else { $videoPlayer.removeClass('paused'); } }, 500); }); // Updates the progress bar's current time as per the chapter start-time. $chapterDetails.on('click', function () { var $videoid = $(this).closest($videoPlayer).find('.video-js').attr('id'); // Since videojs is a global variable, disabling eslint for this line. // eslint-disable-next-line no-undef videojs($videoid).currentTime($(this).prev($cuepoints).data('time')); }); // Chapter progress's animation. function chapterProgress() { var $progressControl = $('.vjs-progress-control', $videoElement); function updateChapterProgress() { $chapterDetails.each(function () { var $chapterDetail = $(this); var $videoid = $(this).closest($videoPlayer).find('.video-js').attr('id'); // Since videojs is a global variable, disabling eslint for this line. // eslint-disable-next-line no-undef var currentTime = parseFloat(videojs($videoid).currentTime()); var $cuepoint = $chapterDetail.prev($cuepoints); var $chapterProgress = $('.js-chapterized-video__progress', $chapterDetail); var startTime = parseFloat($cuepoint.data('time')); var endTime = parseFloat($cuepoint.data('duration')); var chapterDuration = endTime - startTime; var progressValue = Math.max(0, Math.min((currentTime - startTime) / chapterDuration, 1)); var progressWidth = (progressValue * 100) + '%'; if (currentTime >= startTime && currentTime < endTime) { $chapterDetail.addClass('active'); $chapterDetail.find($chapterProgress).css('width', progressWidth); } else if (endTime <= currentTime) { $chapterDetail.removeClass('active').find($chapterProgress).css('width', '100%'); } else { $chapterDetail.removeClass('active'); $chapterDetail.find($chapterProgress).css('width', '0'); } }); } if ($videoBlock.hasClass('js-chapterized-video-wrapper')) { updateChapterProgress(); setInterval(updateChapterProgress, 500); $progressControl.on('mousemove', updateChapterProgress); $window.on('resize', updateChapterProgress); } } // video-waiting triggers before the video actual starts playing // this might be not cross usable across different techs? $videoElement.on('video-waiting', function(e) { $videoPlayer.addClass('video-interacted'); chapterProgress(); }); $videoElement.on('video-started', function () { var $videoDetails = $(this).data('video-manager'); var show_id = $videoDetails._player.tagAttributes.id; var video_platform = $videoDetails._player.techName_; var video_player_cache = $videoDetails._player.player_.cache_; var video_length = video_player_cache.duration; var video_playhead = video_player_cache.currentTime; var video_type = video_player_cache.source.type; var video_watched = (video_player_cache.currentTime / video_player_cache.duration); var video_percent_watched = (video_watched * 100).toFixed(2); if (video_playhead !== 0) { site.track.evtLink({ event_name: 'elc_video_player', event_category: 'video', event_action: 'video_resume', event_label: show_id, video_id: show_id, video_platform: video_platform, video_length: video_length, video_milestone: video_percent_watched, video_playhead: video_playhead, video_type: video_type }); } else { site.track.evtLink({ event_name: 'elc_video_player', event_category: 'video', event_action: 'video_started', event_label: show_id, video_id: show_id, video_platform: video_platform }); } var onEndMarkers = self.getOnEndMarkers(); $videoPlayer.addClass('video-interacted'); chapterProgress(); // deactive the on end markers $.each(onEndMarkers, function(i, obj) { var onEndMarker = obj; onEndMarker.$content.addClass('on_end-marker'); onEndMarker.$content.trigger('cuepoint-exited', [onEndMarker]); }); }); $videoElement.on('video-paused', function () { var $videoDetails = $(this).data('video-manager'); var show_id = $videoDetails._player.tagAttributes.id; var video_platform = $videoDetails._player.techName_; var video_player_cache = $videoDetails._player.player_.cache_; var video_length = video_player_cache.duration; var video_milestone = video_player_cache.duration - video_player_cache.currentTime; var video_playhead = video_player_cache.currentTime; var video_type = video_player_cache.source.type; var video_watched = (video_player_cache.currentTime / video_player_cache.duration); var video_percent_watched = (video_watched * 100).toFixed(2); if (video_milestone === 0) { return; } site.track.evtLink({ event_name: 'elc_video_player', event_category: 'video', event_action:'video_pause', event_label: show_id, video_id: show_id, video_platform: video_platform, video_length: video_length, video_milestone: video_percent_watched, video_playhead: video_playhead, video_type: video_type }); }); $videoElement.on('video-play', function () { var $videoDetails = $(this).data('video-manager'); var show_id = $videoDetails._player.tagAttributes.id; var video_platform = $videoDetails._player.techName_; var video_player_cache = $videoDetails._player.player_.cache_; var video_length = video_player_cache.duration; var video_playhead = video_player_cache.currentTime; var video_type = video_player_cache.source.type; var video_watched = (video_player_cache.currentTime / video_player_cache.duration); var video_percent_watched = (video_watched * 100).toFixed(2); site.track.evtLink({ event_name: 'elc_video_player', event_category: 'video', event_action:'video_resume', event_label: show_id, video_id: show_id, video_platform: video_platform, video_length: video_length, video_milestone: video_percent_watched, video_playhead: video_playhead, video_type: video_type }); }); $videoElement.on('video-ended', function () { var $videoDetails = $(this).data('video-manager'); var show_id = $videoDetails._player.tagAttributes.id; var video_platform = $videoDetails._player.techName_; var video_player_cache = $videoDetails._player.player_.cache_; var video_length = video_player_cache.duration; var video_playhead = video_player_cache.currentTime; var video_type = video_player_cache.source.type; var video_watched = (video_player_cache.currentTime / video_player_cache.duration); var video_percent_watched = (video_watched * 100).toFixed(2); site.track.evtLink({ event_name: 'elc_video_player', event_category: 'video', event_action:'video_stop', event_label: show_id, video_id: show_id, video_platform: video_platform, video_length: video_length, video_milestone: video_percent_watched, video_playhead: video_playhead, video_type: video_type }); var onEndMarkers = self.getOnEndMarkers(); // activate the on_load markers $.each(onEndMarkers, function(i, obj) { var onEndMarker = obj; onEndMarker.$content.addClass('on_end-marker'); onEndMarker.$content.trigger('cuepoint-reached', [onEndMarker]); if (cuepointTargetDisplayed) { $cuepointContainer.height(onEndMarker.$content.height()); } else { $cuepointContainer.height(''); } }); }); $videoPlayer.on('cuepoint-pause-requested', '.js-video-cuepoint', function(e) { $videoElement.trigger('video-pause'); }); $videoPlayer.on('cuepoint-resume-requested', '.js-video-cuepoint', function(e) { $videoElement.trigger('video-play'); }); }; MantleVideo.MantleVideoPlayer = MantleVideoPlayer; })(jQuery); (function($, Drupal) { Drupal.behaviors.videojsVideo = { attach: function(context, settings) { var $videoPlayers = $('.js-mantle-video-player', context); $videoPlayers.each(function(i, obj) { var $videoPlayer = $(obj); // Allow containing template to control when this template attaches. var $videoPlayerController = $videoPlayer.closest('[data-video-player-controller="1"]'); if ($videoPlayerController.length > 0) { return; } var mvp = new MantleVideo.MantleVideoPlayer($videoPlayer); }); } }; })(jQuery, Drupal); ;