UNPKG

25.4 kBJavaScriptView Raw
1/*!
2 * lightgallery | 2.7.2 | September 20th 2023
3 * http://www.lightgalleryjs.com/
4 * Copyright (c) 2020 Sachin Neravath;
5 * @license GPLv3
6 */
7
8(function (global, factory) {
9 typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
10 typeof define === 'function' && define.amd ? define(factory) :
11 (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.lgVideo = factory());
12}(this, (function () { 'use strict';
13
14 /*! *****************************************************************************
15 Copyright (c) Microsoft Corporation.
16
17 Permission to use, copy, modify, and/or distribute this software for any
18 purpose with or without fee is hereby granted.
19
20 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
21 REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
22 AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
23 INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
24 LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
25 OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
26 PERFORMANCE OF THIS SOFTWARE.
27 ***************************************************************************** */
28
29 var __assign = function() {
30 __assign = Object.assign || function __assign(t) {
31 for (var s, i = 1, n = arguments.length; i < n; i++) {
32 s = arguments[i];
33 for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
34 }
35 return t;
36 };
37 return __assign.apply(this, arguments);
38 };
39
40 var videoSettings = {
41 autoplayFirstVideo: true,
42 youTubePlayerParams: false,
43 vimeoPlayerParams: false,
44 wistiaPlayerParams: false,
45 gotoNextSlideOnVideoEnd: true,
46 autoplayVideoOnSlide: false,
47 videojs: false,
48 videojsTheme: '',
49 videojsOptions: {},
50 };
51
52 /**
53 * List of lightGallery events
54 * All events should be documented here
55 * Below interfaces are used to build the website documentations
56 * */
57 var lGEvents = {
58 afterAppendSlide: 'lgAfterAppendSlide',
59 init: 'lgInit',
60 hasVideo: 'lgHasVideo',
61 containerResize: 'lgContainerResize',
62 updateSlides: 'lgUpdateSlides',
63 afterAppendSubHtml: 'lgAfterAppendSubHtml',
64 beforeOpen: 'lgBeforeOpen',
65 afterOpen: 'lgAfterOpen',
66 slideItemLoad: 'lgSlideItemLoad',
67 beforeSlide: 'lgBeforeSlide',
68 afterSlide: 'lgAfterSlide',
69 posterClick: 'lgPosterClick',
70 dragStart: 'lgDragStart',
71 dragMove: 'lgDragMove',
72 dragEnd: 'lgDragEnd',
73 beforeNextSlide: 'lgBeforeNextSlide',
74 beforePrevSlide: 'lgBeforePrevSlide',
75 beforeClose: 'lgBeforeClose',
76 afterClose: 'lgAfterClose',
77 rotateLeft: 'lgRotateLeft',
78 rotateRight: 'lgRotateRight',
79 flipHorizontal: 'lgFlipHorizontal',
80 flipVertical: 'lgFlipVertical',
81 autoplay: 'lgAutoplay',
82 autoplayStart: 'lgAutoplayStart',
83 autoplayStop: 'lgAutoplayStop',
84 };
85
86 var param = function (obj) {
87 return Object.keys(obj)
88 .map(function (k) {
89 return encodeURIComponent(k) + '=' + encodeURIComponent(obj[k]);
90 })
91 .join('&');
92 };
93 var paramsToObject = function (url) {
94 var paramas = url
95 .slice(1)
96 .split('&')
97 .map(function (p) { return p.split('='); })
98 .reduce(function (obj, pair) {
99 var _a = pair.map(decodeURIComponent), key = _a[0], value = _a[1];
100 obj[key] = value;
101 return obj;
102 }, {});
103 return paramas;
104 };
105 var getYouTubeParams = function (videoInfo, youTubePlayerParamsSettings) {
106 if (!videoInfo.youtube)
107 return '';
108 var slideUrlParams = videoInfo.youtube[2]
109 ? paramsToObject(videoInfo.youtube[2])
110 : '';
111 // For youtube first params gets priority if duplicates found
112 var defaultYouTubePlayerParams = {
113 wmode: 'opaque',
114 autoplay: 0,
115 mute: 1,
116 enablejsapi: 1,
117 };
118 var playerParamsSettings = youTubePlayerParamsSettings || {};
119 var youTubePlayerParams = __assign(__assign(__assign({}, defaultYouTubePlayerParams), playerParamsSettings), slideUrlParams);
120 var youTubeParams = "?" + param(youTubePlayerParams);
121 return youTubeParams;
122 };
123 var isYouTubeNoCookie = function (url) {
124 return url.includes('youtube-nocookie.com');
125 };
126 var getVimeoURLParams = function (defaultParams, videoInfo) {
127 if (!videoInfo || !videoInfo.vimeo)
128 return '';
129 var urlParams = videoInfo.vimeo[2] || '';
130 var defaultPlayerParams = defaultParams && Object.keys(defaultParams).length !== 0
131 ? '&' + param(defaultParams)
132 : '';
133 // Support private video
134 var urlWithHash = videoInfo.vimeo[0].split('/').pop() || '';
135 var urlWithHashWithParams = urlWithHash.split('?')[0] || '';
136 var hash = urlWithHashWithParams.split('#')[0];
137 var isPrivate = videoInfo.vimeo[1] !== hash;
138 if (isPrivate) {
139 urlParams = urlParams.replace("/" + hash, '');
140 }
141 urlParams =
142 urlParams[0] == '?' ? '&' + urlParams.slice(1) : urlParams || '';
143 // For vimeo last params gets priority if duplicates found
144 var vimeoPlayerParams = "?autoplay=0&muted=1" + (isPrivate ? "&h=" + hash : '') + defaultPlayerParams + urlParams;
145 return vimeoPlayerParams;
146 };
147
148 /**
149 * Video module for lightGallery
150 * Supports HTML5, YouTube, Vimeo, wistia videos
151 *
152 *
153 * @ref Wistia
154 * https://wistia.com/support/integrations/wordpress(How to get url)
155 * https://wistia.com/support/developers/embed-options#using-embed-options
156 * https://wistia.com/support/developers/player-api
157 * https://wistia.com/support/developers/construct-an-embed-code
158 * http://jsfiddle.net/xvnm7xLm/
159 * https://developer.mozilla.org/en-US/docs/Web/HTML/Element/video
160 * https://wistia.com/support/embed-and-share/sharing-videos
161 * https://private-sharing.wistia.com/medias/mwhrulrucj
162 *
163 * @ref Youtube
164 * https://developers.google.com/youtube/player_parameters#enablejsapi
165 * https://developers.google.com/youtube/iframe_api_reference
166 * https://developer.chrome.com/blog/autoplay/#iframe-delegation
167 *
168 * @ref Vimeo
169 * https://stackoverflow.com/questions/10488943/easy-way-to-get-vimeo-id-from-a-vimeo-url
170 * https://vimeo.zendesk.com/hc/en-us/articles/360000121668-Starting-playback-at-a-specific-timecode
171 * https://vimeo.zendesk.com/hc/en-us/articles/360001494447-Using-Player-Parameters
172 */
173 var Video = /** @class */ (function () {
174 function Video(instance) {
175 // get lightGallery core plugin instance
176 this.core = instance;
177 this.settings = __assign(__assign({}, videoSettings), this.core.settings);
178 return this;
179 }
180 Video.prototype.init = function () {
181 var _this = this;
182 /**
183 * Event triggered when video url found without poster
184 * Append video HTML
185 * Play if autoplayFirstVideo is true
186 */
187 this.core.LGel.on(lGEvents.hasVideo + ".video", this.onHasVideo.bind(this));
188 this.core.LGel.on(lGEvents.posterClick + ".video", function () {
189 var $el = _this.core.getSlideItem(_this.core.index);
190 _this.loadVideoOnPosterClick($el);
191 });
192 this.core.LGel.on(lGEvents.slideItemLoad + ".video", this.onSlideItemLoad.bind(this));
193 // @desc fired immediately before each slide transition.
194 this.core.LGel.on(lGEvents.beforeSlide + ".video", this.onBeforeSlide.bind(this));
195 // @desc fired immediately after each slide transition.
196 this.core.LGel.on(lGEvents.afterSlide + ".video", this.onAfterSlide.bind(this));
197 };
198 /**
199 * @desc Event triggered when a slide is completely loaded
200 *
201 * @param {Event} event - lightGalley custom event
202 */
203 Video.prototype.onSlideItemLoad = function (event) {
204 var _this = this;
205 var _a = event.detail, isFirstSlide = _a.isFirstSlide, index = _a.index;
206 // Should check the active slide as well as user may have moved to different slide before the first slide is loaded
207 if (this.settings.autoplayFirstVideo &&
208 isFirstSlide &&
209 index === this.core.index) {
210 // Delay is just for the transition effect on video load
211 setTimeout(function () {
212 _this.loadAndPlayVideo(index);
213 }, 200);
214 }
215 // Should not call on first slide. should check only if the slide is active
216 if (!isFirstSlide &&
217 this.settings.autoplayVideoOnSlide &&
218 index === this.core.index) {
219 this.loadAndPlayVideo(index);
220 }
221 };
222 /**
223 * @desc Event triggered when video url or poster found
224 * Append video HTML is poster is not given
225 * Play if autoplayFirstVideo is true
226 *
227 * @param {Event} event - Javascript Event object.
228 */
229 Video.prototype.onHasVideo = function (event) {
230 var _a = event.detail, index = _a.index, src = _a.src, html5Video = _a.html5Video, hasPoster = _a.hasPoster;
231 if (!hasPoster) {
232 // All functions are called separately if poster exist in loadVideoOnPosterClick function
233 this.appendVideos(this.core.getSlideItem(index), {
234 src: src,
235 addClass: 'lg-object',
236 index: index,
237 html5Video: html5Video,
238 });
239 // Automatically navigate to next slide once video reaches the end.
240 this.gotoNextSlideOnVideoEnd(src, index);
241 }
242 };
243 /**
244 * @desc fired immediately before each slide transition.
245 * Pause the previous video
246 * Hide the download button if the slide contains YouTube, Vimeo, or Wistia videos.
247 *
248 * @param {Event} event - Javascript Event object.
249 * @param {number} prevIndex - Previous index of the slide.
250 * @param {number} index - Current index of the slide
251 */
252 Video.prototype.onBeforeSlide = function (event) {
253 if (this.core.lGalleryOn) {
254 var prevIndex = event.detail.prevIndex;
255 this.pauseVideo(prevIndex);
256 }
257 };
258 /**
259 * @desc fired immediately after each slide transition.
260 * Play video if autoplayVideoOnSlide option is enabled.
261 *
262 * @param {Event} event - Javascript Event object.
263 * @param {number} prevIndex - Previous index of the slide.
264 * @param {number} index - Current index of the slide
265 * @todo should check on onSlideLoad as well if video is not loaded on after slide
266 */
267 Video.prototype.onAfterSlide = function (event) {
268 var _this = this;
269 var _a = event.detail, index = _a.index, prevIndex = _a.prevIndex;
270 // Do not call on first slide
271 var $slide = this.core.getSlideItem(index);
272 if (this.settings.autoplayVideoOnSlide && index !== prevIndex) {
273 if ($slide.hasClass('lg-complete')) {
274 setTimeout(function () {
275 _this.loadAndPlayVideo(index);
276 }, 100);
277 }
278 }
279 };
280 Video.prototype.loadAndPlayVideo = function (index) {
281 var $slide = this.core.getSlideItem(index);
282 var currentGalleryItem = this.core.galleryItems[index];
283 if (currentGalleryItem.poster) {
284 this.loadVideoOnPosterClick($slide, true);
285 }
286 else {
287 this.playVideo(index);
288 }
289 };
290 /**
291 * Play HTML5, Youtube, Vimeo or Wistia videos in a particular slide.
292 * @param {number} index - Index of the slide
293 */
294 Video.prototype.playVideo = function (index) {
295 this.controlVideo(index, 'play');
296 };
297 /**
298 * Pause HTML5, Youtube, Vimeo or Wistia videos in a particular slide.
299 * @param {number} index - Index of the slide
300 */
301 Video.prototype.pauseVideo = function (index) {
302 this.controlVideo(index, 'pause');
303 };
304 Video.prototype.getVideoHtml = function (src, addClass, index, html5Video) {
305 var video = '';
306 var videoInfo = this.core.galleryItems[index]
307 .__slideVideoInfo || {};
308 var currentGalleryItem = this.core.galleryItems[index];
309 var videoTitle = currentGalleryItem.title || currentGalleryItem.alt;
310 videoTitle = videoTitle ? 'title="' + videoTitle + '"' : '';
311 var commonIframeProps = "allowtransparency=\"true\"\n frameborder=\"0\"\n scrolling=\"no\"\n allowfullscreen\n mozallowfullscreen\n webkitallowfullscreen\n oallowfullscreen\n msallowfullscreen";
312 if (videoInfo.youtube) {
313 var videoId = 'lg-youtube' + index;
314 var youTubeParams = getYouTubeParams(videoInfo, this.settings.youTubePlayerParams);
315 var isYouTubeNoCookieURL = isYouTubeNoCookie(src);
316 var youtubeURL = isYouTubeNoCookieURL
317 ? '//www.youtube-nocookie.com/'
318 : '//www.youtube.com/';
319 video = "<iframe allow=\"autoplay\" id=" + videoId + " class=\"lg-video-object lg-youtube " + addClass + "\" " + videoTitle + " src=\"" + youtubeURL + "embed/" + (videoInfo.youtube[1] + youTubeParams) + "\" " + commonIframeProps + "></iframe>";
320 }
321 else if (videoInfo.vimeo) {
322 var videoId = 'lg-vimeo' + index;
323 var playerParams = getVimeoURLParams(this.settings.vimeoPlayerParams, videoInfo);
324 video = "<iframe allow=\"autoplay\" id=" + videoId + " class=\"lg-video-object lg-vimeo " + addClass + "\" " + videoTitle + " src=\"//player.vimeo.com/video/" + (videoInfo.vimeo[1] + playerParams) + "\" " + commonIframeProps + "></iframe>";
325 }
326 else if (videoInfo.wistia) {
327 var wistiaId = 'lg-wistia' + index;
328 var playerParams = param(this.settings.wistiaPlayerParams);
329 playerParams = playerParams ? '?' + playerParams : '';
330 video = "<iframe allow=\"autoplay\" id=\"" + wistiaId + "\" src=\"//fast.wistia.net/embed/iframe/" + (videoInfo.wistia[4] + playerParams) + "\" " + videoTitle + " class=\"wistia_embed lg-video-object lg-wistia " + addClass + "\" name=\"wistia_embed\" " + commonIframeProps + "></iframe>";
331 }
332 else if (videoInfo.html5) {
333 var html5VideoMarkup = '';
334 for (var i = 0; i < html5Video.source.length; i++) {
335 html5VideoMarkup += "<source src=\"" + html5Video.source[i].src + "\" type=\"" + html5Video.source[i].type + "\">";
336 }
337 if (html5Video.tracks) {
338 var _loop_1 = function (i) {
339 var trackAttributes = '';
340 var track = html5Video.tracks[i];
341 Object.keys(track || {}).forEach(function (key) {
342 trackAttributes += key + "=\"" + track[key] + "\" ";
343 });
344 html5VideoMarkup += "<track " + trackAttributes + ">";
345 };
346 for (var i = 0; i < html5Video.tracks.length; i++) {
347 _loop_1(i);
348 }
349 }
350 var html5VideoAttrs_1 = '';
351 var videoAttributes_1 = html5Video.attributes || {};
352 Object.keys(videoAttributes_1 || {}).forEach(function (key) {
353 html5VideoAttrs_1 += key + "=\"" + videoAttributes_1[key] + "\" ";
354 });
355 video = "<video class=\"lg-video-object lg-html5 " + (this.settings.videojs && this.settings.videojsTheme
356 ? this.settings.videojsTheme + ' '
357 : '') + " " + (this.settings.videojs ? ' video-js' : '') + "\" " + html5VideoAttrs_1 + ">\n " + html5VideoMarkup + "\n Your browser does not support HTML5 video.\n </video>";
358 }
359 return video;
360 };
361 /**
362 * @desc - Append videos to the slide
363 *
364 * @param {HTMLElement} el - slide element
365 * @param {Object} videoParams - Video parameters, Contains src, class, index, htmlVideo
366 */
367 Video.prototype.appendVideos = function (el, videoParams) {
368 var _a;
369 var videoHtml = this.getVideoHtml(videoParams.src, videoParams.addClass, videoParams.index, videoParams.html5Video);
370 el.find('.lg-video-cont').append(videoHtml);
371 var $videoElement = el.find('.lg-video-object').first();
372 if (videoParams.html5Video) {
373 $videoElement.on('mousedown.lg.video', function (e) {
374 e.stopPropagation();
375 });
376 }
377 if (this.settings.videojs && ((_a = this.core.galleryItems[videoParams.index].__slideVideoInfo) === null || _a === void 0 ? void 0 : _a.html5)) {
378 try {
379 return videojs($videoElement.get(), this.settings.videojsOptions);
380 }
381 catch (e) {
382 console.error('lightGallery:- Make sure you have included videojs');
383 }
384 }
385 };
386 Video.prototype.gotoNextSlideOnVideoEnd = function (src, index) {
387 var _this = this;
388 var $videoElement = this.core
389 .getSlideItem(index)
390 .find('.lg-video-object')
391 .first();
392 var videoInfo = this.core.galleryItems[index].__slideVideoInfo || {};
393 if (this.settings.gotoNextSlideOnVideoEnd) {
394 if (videoInfo.html5) {
395 $videoElement.on('ended', function () {
396 _this.core.goToNextSlide();
397 });
398 }
399 else if (videoInfo.vimeo) {
400 try {
401 // https://github.com/vimeo/player.js/#ended
402 new Vimeo.Player($videoElement.get()).on('ended', function () {
403 _this.core.goToNextSlide();
404 });
405 }
406 catch (e) {
407 console.error('lightGallery:- Make sure you have included //github.com/vimeo/player.js');
408 }
409 }
410 else if (videoInfo.wistia) {
411 try {
412 window._wq = window._wq || [];
413 // @todo Event is gettign triggered multiple times
414 window._wq.push({
415 id: $videoElement.attr('id'),
416 onReady: function (video) {
417 video.bind('end', function () {
418 _this.core.goToNextSlide();
419 });
420 },
421 });
422 }
423 catch (e) {
424 console.error('lightGallery:- Make sure you have included //fast.wistia.com/assets/external/E-v1.js');
425 }
426 }
427 }
428 };
429 Video.prototype.controlVideo = function (index, action) {
430 var $videoElement = this.core
431 .getSlideItem(index)
432 .find('.lg-video-object')
433 .first();
434 var videoInfo = this.core.galleryItems[index].__slideVideoInfo || {};
435 if (!$videoElement.get())
436 return;
437 if (videoInfo.youtube) {
438 try {
439 $videoElement.get().contentWindow.postMessage("{\"event\":\"command\",\"func\":\"" + action + "Video\",\"args\":\"\"}", '*');
440 }
441 catch (e) {
442 console.error("lightGallery:- " + e);
443 }
444 }
445 else if (videoInfo.vimeo) {
446 try {
447 new Vimeo.Player($videoElement.get())[action]();
448 }
449 catch (e) {
450 console.error('lightGallery:- Make sure you have included //github.com/vimeo/player.js');
451 }
452 }
453 else if (videoInfo.html5) {
454 if (this.settings.videojs) {
455 try {
456 videojs($videoElement.get())[action]();
457 }
458 catch (e) {
459 console.error('lightGallery:- Make sure you have included videojs');
460 }
461 }
462 else {
463 $videoElement.get()[action]();
464 }
465 }
466 else if (videoInfo.wistia) {
467 try {
468 window._wq = window._wq || [];
469 // @todo Find a way to destroy wistia player instance
470 window._wq.push({
471 id: $videoElement.attr('id'),
472 onReady: function (video) {
473 video[action]();
474 },
475 });
476 }
477 catch (e) {
478 console.error('lightGallery:- Make sure you have included //fast.wistia.com/assets/external/E-v1.js');
479 }
480 }
481 };
482 Video.prototype.loadVideoOnPosterClick = function ($el, forcePlay) {
483 var _this = this;
484 // check slide has poster
485 if (!$el.hasClass('lg-video-loaded')) {
486 // check already video element present
487 if (!$el.hasClass('lg-has-video')) {
488 $el.addClass('lg-has-video');
489 var _html = void 0;
490 var _src = this.core.galleryItems[this.core.index].src;
491 var video = this.core.galleryItems[this.core.index].video;
492 if (video) {
493 _html =
494 typeof video === 'string' ? JSON.parse(video) : video;
495 }
496 var videoJsPlayer_1 = this.appendVideos($el, {
497 src: _src,
498 addClass: '',
499 index: this.core.index,
500 html5Video: _html,
501 });
502 this.gotoNextSlideOnVideoEnd(_src, this.core.index);
503 var $tempImg = $el.find('.lg-object').first().get();
504 // @todo make sure it is working
505 $el.find('.lg-video-cont').first().append($tempImg);
506 $el.addClass('lg-video-loading');
507 videoJsPlayer_1 &&
508 videoJsPlayer_1.ready(function () {
509 videoJsPlayer_1.on('loadedmetadata', function () {
510 _this.onVideoLoadAfterPosterClick($el, _this.core.index);
511 });
512 });
513 $el.find('.lg-video-object')
514 .first()
515 .on('load.lg error.lg loadedmetadata.lg', function () {
516 setTimeout(function () {
517 _this.onVideoLoadAfterPosterClick($el, _this.core.index);
518 }, 50);
519 });
520 }
521 else {
522 this.playVideo(this.core.index);
523 }
524 }
525 else if (forcePlay) {
526 this.playVideo(this.core.index);
527 }
528 };
529 Video.prototype.onVideoLoadAfterPosterClick = function ($el, index) {
530 $el.addClass('lg-video-loaded');
531 this.playVideo(index);
532 };
533 Video.prototype.destroy = function () {
534 this.core.LGel.off('.lg.video');
535 this.core.LGel.off('.video');
536 };
537 return Video;
538 }());
539
540 return Video;
541
542})));
543//# sourceMappingURL=lg-video.umd.js.map