Here is my solution to use Photoswipe with Youtube&Vimeo videos.
It is a mix of java-script libraries and solutions which I saw here at Stackoverflow and on the web.
Stylings
<link href="photoswipe.css" rel="stylesheet">
<link href="default-skin/default-skin.css" rel="stylesheet">
<style>
.gallery-viewer-play-video-btn-container {
position: relative;
cursor: pointer;
}
.gallery-viewer-play-video-btn-container button {
pointer-events: none;
position: absolute;
outline: 0;
border: none;
background-color: transparent;
padding: 0;
color: inherit;
text-align: inherit;
font-size: 100%;
font-family: inherit;
cursor: pointer;
line-height: inherit;
left: 50%;
top: 50%;
width: 68px;
height: 48px;
margin-left: -34px;
margin-top: -24px;
-moz-transition: opacity .25s cubic-bezier(0.0,0.0,0.2,1);
-webkit-transition: opacity .25s cubic-bezier(0.0,0.0,0.2,1);
transition: opacity .25s cubic-bezier(0.0,0.0,0.2,1);
}
.gallery-viewer-play-video-btn-container .ytp-large-play-button-bg {
-moz-transition: fill .1s cubic-bezier(0.4,0.0,1,1),fill-opacity .1s cubic-bezier(0.4,0.0,1,1);
-webkit-transition: fill .1s cubic-bezier(0.4,0.0,1,1),fill-opacity .1s cubic-bezier(0.4,0.0,1,1);
transition: fill .1s cubic-bezier(0.4,0.0,1,1),fill-opacity .1s cubic-bezier(0.4,0.0,1,1);
fill: #cc181e;
fill-opacity: 1;
}
.YouTubePopUp-Wrap .loading {
display: block;
position: absolute;
top: 50%;
left: 50%;
margin-top: -13px;
margin-left: -36px;
color: #fff;
}
</style>
Markup (the standard one)
<div class="pswp pswp-chat" tabindex="-1" role="dialog" aria-hidden="true">
<!-- Background of PhotoSwipe.
It's a separate element as animating opacity is faster than rgba(). -->
<div class="pswp__bg"></div>
<!-- Slides wrapper with overflow:hidden. -->
<div class="pswp__scroll-wrap">
<!-- Container that holds slides.
PhotoSwipe keeps only 3 of them in the DOM to save memory.
Don't modify these 3 pswp__item elements, data is added later on. -->
<div class="pswp__container">
<div class="pswp__item"></div>
<div class="pswp__item"></div>
<div class="pswp__item"></div>
</div>
<!-- Default (PhotoSwipeUI_Default) interface on top of sliding area. Can be changed. -->
<div class="pswp__ui pswp__ui--hidden">
<div class="pswp__top-bar">
<!-- Controls are self-explanatory. Order can be changed. -->
<div class="pswp__counter"></div>
<button class="pswp__button pswp__button--close" title="Close (Esc)"></button>
<button class="pswp__button pswp__button--fs" title="Toggle fullscreen"></button>
<button class="pswp__button pswp__button--zoom" title="Zoom in/out"></button>
<!-- Preloader demo http://codepen.io/dimsemenov/pen/yyBWoR -->
<!-- element will get class pswp__preloader--active when preloader is running -->
<div class="pswp__preloader">
<div class="pswp__preloader__icn">
<div class="pswp__preloader__cut">
<div class="pswp__preloader__donut"></div>
</div>
</div>
</div>
</div>
<div class="pswp__share-modal pswp__share-modal--hidden pswp__single-tap">
<div class="pswp__share-tooltip"></div>
</div>
<button class="pswp__button pswp__button--arrow--left" title="Previous (arrow left)">
</button>
<button class="pswp__button pswp__button--arrow--right" title="Next (arrow right)">
</button>
<div class="pswp__caption">
<div class="pswp__caption__center"></div>
</div>
</div>
</div>
</div>
Items
<div class="list">
<div class="element">
<a data-index="0" class="media" href="file58dc530580a94.jpg" target="_blank">
<img src="thumb/file58dc530580a94.jpg" itemprop="thumbnail"/>
</a>
</div>
<div class="element">
<a data-index="1" class="media" href="file58dc530580a94.jpg" target="_blank">
<img src="thumb/file58dc530580a94.jpg" itemprop="thumbnail"/>
</a>
</div>
<div class="element">
<a data-index="2" class="media" href="file58dc530580a94.jpg" target="_blank">
<img src="thumb/file58dc530580a94.jpg" itemprop="thumbnail"/>
</a>
</div>
<div class="element">
<a data-index="3" class="media" href="file58dc530580a94.jpg" target="_blank">
<img src="thumb/file58dc530580a94.jpg" itemprop="thumbnail"/>
</a>
</div>
</div>
Scripts
<script src="photoswipe.js"></script>
<script src="photoswipe-ui-default.js"></script>
<script src="jquery.min.js"></script>
<script src="jquery-ui.min.js"></script>
<script src="YouTubePopUp.jquery.js"></script>
<script src="custom.js"></script>
YouTubePopUp.jquery.js (this is a jQuery Plugin by Qassim Hassan). You need to download it as well. I've made some custom changes in it, so after downloading simply replace the js-code with mine.
/*
Name: YouTubePopUp
Description: jQuery plugin to display YouTube or Vimeo video in PopUp, responsive and retina, easy to use.
Version: 1.0.1
Plugin URL: http://wp-time.com/youtube-popup-jquery-plugin/
Written By: Qassim Hassan
Twitter: @QQQHZ
Websites: wp-time.com | qass.im | wp-plugins.in
Dual licensed under the MIT and GPL licenses:
http://www.opensource.org/licenses/mit-license.php
http://www.gnu.org/licenses/gpl.html
Copyright (c) 2016 - Qassim Hassan
Mod by MaximusBaton
*/
(function ( $ ) {
$.fn.YouTubePopUp = function(options) {
var YouTubePopUpOptions = $.extend({
autoplay : 1,
controls : 1,
cc_load_policy : 0,
iv_load_policy : 3,
rel : 0,
showinfo : 0
}, options );
$(this).on('click', function (e) {
var youtubeLink = $(this).attr("href");
if( youtubeLink.match(/(youtube.com)/) ){
var split_c = "v=";
var split_n = 1;
}
if( youtubeLink.match(/(youtu.be)/) || youtubeLink.match(/(vimeo.com\/)+[0-9]/) ){
var split_c = "/";
var split_n = 3;
}
if( youtubeLink.match(/(vimeo.com\/)+[a-zA-Z]/) ){
var split_c = "/";
var split_n = 5;
}
var getYouTubeVideoID = youtubeLink.split(split_c)[split_n];
var cleanVideoID = getYouTubeVideoID.replace(/(&)+(.*)/, "");
if( youtubeLink.match(/(youtu.be)/) || youtubeLink.match(/(youtube.com)/) ){
var videoEmbedLink = "https://www.youtube.com/embed/"+cleanVideoID+"?autoplay="+YouTubePopUpOptions.autoplay+"&controls="+ YouTubePopUpOptions.controls +"&cc_load_policy="+ YouTubePopUpOptions.cc_load_policy +"&iv_load_policy="+ YouTubePopUpOptions.iv_load_policy +"&rel="+ YouTubePopUpOptions.rel +"&showinfo="+ YouTubePopUpOptions.showinfo +"";
}
if( youtubeLink.match(/(vimeo.com\/)+[0-9]/) || youtubeLink.match(/(vimeo.com\/)+[a-zA-Z]/) ){
var videoEmbedLink = "https://player.vimeo.com/video/"+cleanVideoID+"?autoplay="+YouTubePopUpOptions.autoplay+"";
}
$("body").append('<div class="YouTubePopUp-Wrap YouTubePopUp-animation"><div class="YouTubePopUp-Content"><span class="loading">Loading...</span><span class="YouTubePopUp-Close"></span><iframe src="'+videoEmbedLink+'" allowfullscreen></iframe></div></div>');
$('.YouTubePopUp-Content iframe')[0].onload = function() {
$('.YouTubePopUp-Wrap .loading').hide();
$('.YouTubePopUp-Wrap iframe').show();
};
if( $('.YouTubePopUp-Wrap').hasClass('YouTubePopUp-animation') ){
setTimeout(function() {
$('.YouTubePopUp-Wrap').removeClass("YouTubePopUp-animation");
}, 600);
}
$(".YouTubePopUp-Wrap, .YouTubePopUp-Close").click(function(){
$.event.trigger({type : 'youtubeVideoBeforeClose', link : youtubeLink});
$(".YouTubePopUp-Wrap").addClass("YouTubePopUp-Hide").delay(515).queue(function() { $(this).remove(); });
});
$.event.trigger({type : 'youtubeVideoStarted', link : youtubeLink});
e.preventDefault();
});
$(document).keyup(function(e) {
if ( e.keyCode == 27 ){
$('.YouTubePopUp-Wrap, .YouTubePopUp-Close').click();
}
});
};
}( jQuery ));
custom.js (the main js :)
$(document).ready(function () {
var mediaList = [];
var interval,
intervalTries = 0,
maxIntervalTries = 40;
mediaList.push({
'src' : 'file58dc530580a94.jpg',
'w' : 1726,
'h' : 2506
});
mediaList.push({
'src' : 'file58dae7f57ea15.jpg',
'w' : 4032,
'h' : 3024
});
mediaList.push({
'src' : 'file58daa7b097cc2.jpg',
'w' : 3799,
'h' : 2849
});
mediaList.push({
'src' : 'file58dc530580a94.jpg',
'w' : 1000,
'h' : 667,
'videoSrc' : '//www.youtube.com/watch?v=a_Ypr_uV-mw'
});
var pswpElement = $('.pswp.pswp-chat')[0];
$(document).on("click", ".media", function(e){
e.preventDefault();
var index = $(this).data("index"),
options = {
index : index,
bgOpacity : 0.7,
overlayIcon : true,
showHideOpacity : true
},
gallery = new PhotoSwipe( pswpElement, PhotoSwipeUI_Default, mediaList, options);
gallery.init();
gallery.listen('close', function() {
removeVideo(gallery);
});
gallery.listen('beforeChange', function() {
removeVideo(gallery);
});
gallery.listen('afterChange', function() {
detectVideo(gallery.currItem);
});
gallery.listen('resize', function() {
resizeItem(gallery.currItem);
});
gallery.listen('imageLoadComplete', function(index, item) {
resizeItem(gallery.currItem);
});
detectVideo(gallery.currItem);
$(document).off('pswpTap').on('pswpTap', function(e){
var container = $(gallery.currItem.container),
img = container.find('img.youtubeClass');
if (img.length) {
if (typeof(img.data('youtubeVideoStarted')) == 'undefined') {
img.data('youtubeVideoStarted', false);
}
if (img.data('youtubeVideoStarted') === false) {
img.data('youtubeVideoStarted', true);
if (typeof(img.data('youtubeInitialed')) == 'undefined') {
img.data('youtubeInitialed', false);
}
if (img.data('youtubeInitialed') === false) {
img.data('youtubeInitialed', true);
img.YouTubePopUp();
}
if (e.detail.pointerType != 'mouse') {
img.click();
}
}
}
});
$(document).off('youtubeVideoStarted').on('youtubeVideoStarted', function(e){
var container = $(gallery.container),
img = container.find('img.youtubeClass[href="'+ e.link +'"]');
if (img.length) {
container = img.closest('.pswp__item');
if (container.length) {
var buttonContainer = container.find('.gallery-viewer-play-video-btn-container');
img.fadeOut(200);
if (buttonContainer.length) {
buttonContainer.fadeOut(200);
}
}
}
});
$(document).off('youtubeVideoBeforeClose').on('youtubeVideoBeforeClose', function(e){
var container = $(gallery.container),
img = container.find('img.youtubeClass[href="'+ e.link +'"]');
if (img.length) {
container = img.closest('.pswp__item');
if (container.length) {
var buttonContainer = container.find('.gallery-viewer-play-video-btn-container');
img.fadeIn(300);
img.data('youtubeVideoStarted', false);
if (buttonContainer.length) {
buttonContainer.fadeIn(300);
}
}
}
});
});
function resizeItem(item) {
var container = $(item.container),
children = container.children();
if (children.length > 1) {
var newWidth = $(children[ children.length - 1 ]).css('width'),
newHeight = $(children[ children.length - 1 ]).css('height');
children.css({
'width' : newWidth,
'height' : newHeight
});
}
}
function removeVideo(gallery) {
clearVideoInterval();
var container = $(gallery.container),
buttonContainers = container.find('.gallery-viewer-play-video-btn-container');
$.each(buttonContainers, function(){
var $thisButtonContainer = $(this),
container = $thisButtonContainer.closest('.pswp__item');
if (container.length) {
var img = container.find('img:not(.youtubeClass)');
$thisButtonContainer.remove();
if (img.length) {
img.show();
}
}
});
}
function detectVideo(item) {
clearVideoInterval();
if (typeof(item.videoSrc) != 'undefined') {
interval = setInterval(function(){ addVideoIframe(item); }, 100);
}
}
function clearVideoInterval() {
clearInterval(interval);
intervalTries = 0;
}
function addVideoIframe(item) {
if (intervalTries >= maxIntervalTries) {
clearVideoInterval();
return;
}
intervalTries++;
var container = $(item.container),
img = container.find('img:not(.youtubeClass)');
if (img.length) {
resizeItem(item);
var imgSrcCode = '_'+ img.attr('src'),
buttonContainer = container.find('.gallery-viewer-play-video-btn-container');
if (buttonContainer.length == 0) {
buttonContainer = $('<div class="gallery-viewer-play-video-btn-container"><button><svg height="100%" version="1.1" viewBox="0 0 68 48" width="100%"><path class="ytp-large-play-button-bg" d="m .66,37.62 c 0,0 .66,4.70 2.70,6.77 2.58,2.71 5.98,2.63 7.49,2.91 5.43,.52 23.10,.68 23.12,.68 .00,-1.3e-5 14.29,-0.02 23.81,-0.71 1.32,-0.15 4.22,-0.17 6.81,-2.89 2.03,-2.07 2.70,-6.77 2.70,-6.77 0,0 .67,-5.52 .67,-11.04 l 0,-5.17 c 0,-5.52 -0.67,-11.04 -0.67,-11.04 0,0 -0.66,-4.70 -2.70,-6.77 C 62.03,.86 59.13,.84 57.80,.69 48.28,0 34.00,0 34.00,0 33.97,0 19.69,0 10.18,.69 8.85,.84 5.95,.86 3.36,3.58 1.32,5.65 .66,10.35 .66,10.35 c 0,0 -0.55,4.50 -0.66,9.45 l 0,8.36 c .10,4.94 .66,9.45 .66,9.45 z" fill="#1f1f1e" fill-opacity="0.81"></path><path d="m 26.96,13.67 18.37,9.62 -18.37,9.55 -0.00,-19.17 z" fill="#fff"></path><path d="M 45.02,23.46 45.32,23.28 26.96,13.67 43.32,24.34 45.02,23.46 z" fill="#ccc"></path></svg></button></div>');
var clonedImg = img.clone();
clonedImg.attr('href', item.videoSrc)
.addClass('youtubeClass')
.removeClass('pswp__img')
.css({
'width' : '100%',
'height' : '100%'
});
buttonContainer.prepend( clonedImg );
}
buttonContainer.css({
'width' : img.outerWidth() +'px',
'height' : img.outerHeight() +'px'
})
.appendTo(container);
img.hide();
clearVideoInterval();
}
}
});
Have fun!