PluginProbe
Photonic Gallery & Lightbox for Flickr, SmugMug & Others / 3.34
Photonic Gallery & Lightbox for Flickr, SmugMug & Others v3.34
3.37 3.36 3.35 3.34 3.33 2.19 2.20 2.21 2.22 2.23 2.24 2.25 2.26 2.27 2.28 2.29 2.30 2.31 2.32 2.33 2.34 2.40 2.41 2.42 2.43 All 142 releases
photonic / include / js / front-end / src / Lightboxes / PhotoSwipe.js

PhotoSwipe.js in Photonic Gallery & Lightbox for Flickr, SmugMug & Others 3.34, at include/js/front-end/src/Lightboxes/PhotoSwipe.js

314 lines 12.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 import {Lightbox} from "./Lightbox";
2 import * as Util from "../Util";
3
4 export class PhotonicPhotoSwipe extends Lightbox {
5 constructor() {
6 super();
7 this.pswpSelector = '.pswp';
8 this.videoSelector = 'a.photoswipe-video, a.photoswipe-html5-video';
9 this.pswp = document.querySelector(this.pswpSelector);
10 if (this.pswp === null) {
11 this.pswp = '<!-- Root element of PhotoSwipe. Must have class pswp. -->\n' +
12 '<div class="pswp" tabindex="-1" role="dialog" aria-hidden="true">\n' +
13 '\n' +
14 ' <!-- Background of PhotoSwipe. \n' +
15 ' It\'s a separate element as animating opacity is faster than rgba(). -->\n' +
16 ' <div class="pswp__bg"></div>\n' +
17 '\n' +
18 ' <!-- Slides wrapper with overflow:hidden. -->\n' +
19 ' <div class="pswp__scroll-wrap">\n' +
20 '\n' +
21 ' <!-- Container that holds slides. \n' +
22 ' PhotoSwipe keeps only 3 of them in the DOM to save memory.\n' +
23 ' Don\'t modify these 3 pswp__item elements, data is added later on. -->\n' +
24 ' <div class="pswp__container">\n' +
25 ' <div class="pswp__item"></div>\n' +
26 ' <div class="pswp__item"></div>\n' +
27 ' <div class="pswp__item"></div>\n' +
28 ' </div>\n' +
29 '\n' +
30 ' <!-- Default (PhotoSwipeUI_Default) interface on top of sliding area. Can be changed. -->\n' +
31 ' <div class="pswp__ui pswp__ui--hidden">\n' +
32 '\n' +
33 ' <div class="pswp__top-bar">\n' +
34 ' <!-- Controls are self-explanatory. Order can be changed. -->\n' +
35 ' <div class="pswp__counter"></div>\n' +
36 ' <button class="pswp__button pswp__button--close" title="Close (Esc)"></button>\n' +
37 ' <button class="pswp__button pswp__button--share" title="Share"></button>\n' +
38 ' <button class="pswp__button pswp__button--fs" title="Toggle fullscreen"></button>\n' +
39 ' <button class="pswp__button pswp__button--zoom" title="Zoom in/out"></button>\n' +
40 '\n' +
41 ' <!-- Preloader demo https://codepen.io/dimsemenov/pen/yyBWoR -->\n' +
42 ' <!-- element will get class pswp__preloader--active when preloader is running -->\n' +
43 ' <div class="pswp__preloader">\n' +
44 ' <div class="pswp__preloader__icn">\n' +
45 ' <div class="pswp__preloader__cut">\n' +
46 ' <div class="pswp__preloader__donut"></div>\n' +
47 ' </div>\n' +
48 ' </div>\n' +
49 ' </div>\n' +
50 ' </div>\n' +
51 '\n' +
52 ' <div class="pswp__share-modal pswp__share-modal--hidden pswp__single-tap">\n' +
53 ' <div class="pswp__share-tooltip"></div> \n' +
54 ' </div>\n' +
55 '\n' +
56 ' <button class="pswp__button pswp__button--arrow--left" title="Previous (arrow left)">\n' +
57 ' </button>\n' +
58 '\n' +
59 ' <button class="pswp__button pswp__button--arrow--right" title="Next (arrow right)">\n' +
60 ' </button>\n' +
61 '\n' +
62 ' <div class="pswp__caption">\n' +
63 ' <div class="pswp__caption__center"></div>\n' +
64 ' </div>\n' +
65 '\n' +
66 ' </div>\n' +
67 '\n' +
68 ' </div>\n' +
69 '\n' +
70 '</div>';
71
72 document.body.insertAdjacentHTML('beforeend', this.pswp);
73 this.pswp = document.querySelector(this.pswpSelector);
74 }
75 };
76
77 hostedVideo(a) {
78 const html5 = a.getAttribute('href').match(new RegExp(/(\.mp4|\.webm|\.ogg)/i));
79 let css = a.classList.contains('photonic-lb');
80
81 if (html5 !== null && !css) {
82 a.classList.add(Photonic_JS.lightbox_library + "-html5-video");
83 let videos = document.querySelector('#photonic-html5-videos');
84 if (videos === null) {
85 videos = document.createElement('div');
86 videos.style.display = 'none';
87 videos.setAttribute('id', 'photonic-html5-videos');
88 document.body.appendChild(videos);
89 }
90
91 videos.insertAdjacentHTML('beforeend', '<div id="photonic-html5-video-' + this.videoIndex + '"><video controls preload="none"><source src="' + a.getAttribute('href') + '" type="video/mp4">Your browser does not support HTML5 video.</video></div>');
92
93 a.setAttribute('data-html5-href', a.getAttribute('href'));
94 a.setAttribute('href', '#photonic-html5-video-' + this.videoIndex);
95 this.videoIndex++;
96 }
97 };
98
99 changeVideoURL(element, regular, embed) {
100 element.setAttribute('href', embed);
101 };
102
103 initialize(selector, selfSelect) {
104 this.handleSolos();
105 const self = this;
106
107 self.items = {};
108 self.solos = [];
109 self.videos = [];
110
111 const containers = document.querySelectorAll('.photonic-level-1-container');
112 containers.forEach(function(container) {
113 let parent = container.closest('.photonic-stream') || container.closest('.photonic-panel');
114 // if (parent != null) {
115 let galleryId = parent.getAttribute('id');
116
117 const links = container.querySelectorAll('.photonic-lb');
118 const gallery = [];
119 links.forEach(function(link) {
120 const deep = link.getAttribute('data-photonic-deep');
121 const pid = deep.split('/');
122 let item;
123 if (link.getAttribute('data-html5-href') !== null) {
124 item = {
125 html: '<div class="photonic-video" id="ps-' + link.getAttribute('href').substring(1) + '">\n<video class="photonic" controls preload="none"><source src="' + link.getAttribute('data-html5-href') + '" type="video/mp4">Your browser does not support HTML5 videos</video>',
126 title: Util.HTMLSanitizer.SanitizeHTML(link.getAttribute('data-title'))
127 };
128 }
129 else {
130 item = {
131 src: link.getAttribute('href'),
132 w: 0,
133 h: 0,
134 title: Util.HTMLSanitizer.SanitizeHTML(link.getAttribute('data-title')),
135 pid: pid[1]
136 };
137 }
138 gallery.push(item);
139 });
140 self.items[galleryId] = gallery;
141 // }
142 });
143
144 const a = document.querySelectorAll('a.photonic-photoswipe');
145 const solos = Array.from(a).filter(elem => elem.closest('.photonic-level-1') === null);
146 solos.forEach(link => {
147 const item = {
148 src: link.getAttribute('href'),
149 w: 0,
150 h: 0,
151 title: Util.getText(link.getAttribute('data-title'))
152 };
153 self.solos.push([item]);
154 });
155
156 const videos = document.querySelectorAll(this.videoSelector);
157 videos.forEach(function(link) {
158 let item;
159 if (link.classList.contains('photoswipe-video')) { // YouTube / Vimeo
160 item = {
161 html: '<div class="photonic-video"><iframe class="pswp__video" width="640" height="480" src="' + link.getAttribute('href') + '" frameborder="0" allowfullscreen></iframe></div>'
162 };
163 }
164 else {
165 let href = link.getAttribute('href');
166 href = document.querySelector(href);
167
168 item = {
169 html: '<div class="photonic-video" id="ps-' + href.getAttribute('id') + '">\n<video class="photonic" controls preload="none"><source src="' + link.getAttribute('data-html5-href') + '" type="video/mp4">Your browser does not support HTML5 videos</video>',
170 title: Util.HTMLSanitizer.SanitizeHTML(link.getAttribute('data-title')) || Util.getText(link.getAttribute('title')) || ''
171 }
172 }
173 self.videos.push([item]);
174 });
175 };
176
177 initializeForNewContainer(containerId) {
178 this.initialize(containerId);
179 };
180
181 parsePhotoSwipeHash() {
182 const hash = window.location.hash.substring(1);
183 const params = {};
184
185 const vars = hash.split('&');
186 for (let i = 0; i < vars.length; i++) {
187 if(!vars[i]) {
188 continue;
189 }
190 const pair = vars[i].split('=');
191 if(pair.length < 2) {
192 continue;
193 }
194 params[pair[0]] = pair[1];
195 }
196
197 if (params.gid && params.gid.indexOf('photonic') !== 0) { // Not a Photonic hash
198 return {};
199 }
200
201 return params;
202 };
203
204 openPhotoSwipe(index, galleryId, fromURL, isVideo) {
205 let idx;
206 const self = this;
207 if (fromURL) {
208 const gallery = document.querySelector('#' + galleryId);
209 const a = gallery.querySelector('a[data-photonic-deep="gallery[' + galleryId + ']/' + index + '/"]');
210 idx = [...a.parentNode.children].indexOf(a);
211 }
212
213 const deepLinking = !(Photonic_JS.deep_linking === undefined || Photonic_JS.deep_linking === 'none' || galleryId === undefined || galleryId.indexOf('-stream') < 0);
214 let shareButtons = [];
215 if (!(Photonic_JS.social_media === undefined || Photonic_JS.social_media === '')) {
216 shareButtons = [
217 {id:'facebook', label:'Share on Facebook', url:'https://www.facebook.com/sharer/sharer.php?u={{url}}&title={{text}}'},
218 {id:'twitter', label:'Share on Twitter', url:'https://twitter.com/share?url={{url}}&text={{text}}'},
219 {id:'pinterest', label:'Pin it', url:'https://www.pinterest.com/pin/create/button/?url={{url}}&media={{image_url}}&description={{text}}'}
220 ];
221 }
222 shareButtons.push({id:'download', label:'Download image', url:'{{raw_image_url}}', download:true});
223
224 const options = {
225 index: (fromURL && deepLinking) ? idx : index,
226 history: deepLinking,
227 shareButtons: shareButtons,
228 loop: Photonic_JS.lightbox_loop,
229 galleryUID: galleryId,
230 galleryPIDs: deepLinking
231 };
232
233 const galleryItems = isVideo ? self.videos[index] : (galleryId !== undefined ? self.items[galleryId] : self.solos[index]);
234 const gallery = new PhotoSwipe(this.pswp, PhotoSwipeUI_Default, galleryItems, options);
235 gallery.listen('gettingData', function(i, item) {
236 if (item.src !== undefined && (item.w < 1 || item.h < 1)) { // unknown size
237 const img = new Image();
238 img.onload = function() { // will get size after load
239 item.w = this.width; // set image width
240 item.h = this.height; // set image height
241 item.needsUpdate = true;
242 gallery.updateSize(true); // reinit Items
243 };
244 img.src = item.src; // let's download image
245 }
246 else if (item.html !== undefined && (item.w < 1 || item.h < 1)) {
247 let html = document.createElement("div");
248 html.innerHTML = item.html;
249
250 const video = html.querySelector('video');
251 if (video !== null) {
252 let videoSrc = html.querySelector('source');
253 if (videoSrc !== null) {
254 videoSrc = videoSrc.getAttribute('src');
255 self.getVideoSize(videoSrc, {width: window.innerWidth, height: window.innerHeight}).then(dimensions => {
256 item.h = dimensions.newHeight;
257 item.w = dimensions.newWidth;
258
259 const videoContainer = document.querySelector(html.getAttribute('id'));
260 if (videoContainer) {
261 const containedVideo = videoContainer.querySelector('video');
262 containedVideo.width = dimensions.newWidth;
263 containedVideo.height = dimensions.newHeight;
264 }
265 });
266 }
267 }
268 }
269 });
270 gallery.init();
271 };
272
273 initializeForExisting() {
274 const self = this;
275
276 document.addEventListener('click', e => {
277 if (!(e.target instanceof Element) || !e.target.closest('a.photonic-photoswipe')) {
278 return;
279 }
280
281 e.preventDefault();
282 const clicked = e.target.closest('a.photonic-photoswipe'); //e.currentTarget;
283 const parent = clicked.closest('.photonic-stream') || clicked.closest('.photonic-panel');
284 let index;
285 if (parent !== null) {
286 const node = clicked.closest('.photonic-level-1');
287 const galleryId = parent.getAttribute('id');
288 if (node) {
289 index = [...node.parentNode.children].indexOf(node);
290 self.openPhotoSwipe(index, galleryId);
291 }
292 }
293 else {
294 const a = document.querySelectorAll('a.photonic-photoswipe');
295 const solos = Array.from(a).filter(elem => elem.closest('.photonic-level-1') === null);
296 index = solos.indexOf(clicked);
297 self.openPhotoSwipe(index, undefined);
298 }
299 });
300
301 document.addEventListener('click', e => {
302 if (!(e.target instanceof Element) || !e.target.closest(self.videoSelector)) {
303 return;
304 }
305
306 e.preventDefault();
307 const clicked = e.target.closest(self.videoSelector); //e.currentTarget;
308 const videos = document.querySelectorAll(self.videoSelector);
309 const index = Array.from(videos).indexOf(clicked);
310 self.openPhotoSwipe(index, undefined, false, true);
311 });
312 };
313 }
314