1/* global lightGallery, lgAutoplay, lgFullscreen, lgZoom, lgVideo, lgThumbnail */ 2(function () { 3 const { mergeObjects, toArray } = BreakdanceFrontend.utils; 4 5 class BreakdanceLightbox { 6 defaultOptions = { 7 type: "default", 8 items: [], 9 itemSelector: ".ee-gallery-item", 10 autoplay: false, 11 speed: { number: 3000 }, 12 autoplay_videos: false, 13 thumbnails: false, 14 animated_thumbnails: false, 15 show_download_button: false, 16 disable_autoplay_on_first_video: false, 17 watchAttrs: false, 18 }; 19 20 constructor(element, options) { 21 this.itemize = this.itemize.bind(this); 22 this.filterByGallery = this.filterByGallery.bind(this); 23 24 this.options = mergeObjects(this.defaultOptions, options); 25 this.selector = element; 26 this.element = this.queryElement(element); 27 this.itemSelector = `${this.options.itemSelector}:not(.swiper-slide-duplicate)`; 28 29 this.init(); 30 } 31 32 createGallery(options) { 33 const defaultOptions = this.getLibOptions(); 34 35 this.lightbox = lightGallery(this.element, { 36 ...defaultOptions, 37 ...options, 38 }); 39 40 this.detectDuplicateSwiperSlides(); 41 this.addThumbnailsToVideos(); 42 } 43 44 queryElement(element) { 45 if (typeof element == "string") { 46 return document.querySelector(element); 47 } 48 49 return element; 50 } 51 52 getNamespace() { 53 if (this.element.dataset.lightboxId) { 54 return this.element.dataset.lightboxId; 55 } 56 57 if (this.selector) { 58 const tokens = this.selector 59 .split("-") 60 .filter((t) => !isNaN(Number(t))) 61 .slice(0, 2); // Post ID and Node ID only. 62 63 return tokens.join('-'); 64 } 65 66 return "default"; 67 } 68 69 getLibOptions() { 70 const settings = this.options; 71 const namespace = this.getNamespace(); 72 const className = `bde-lightbox bde-lightbox-${namespace}`; 73 74 return { 75 plugins: [lgAutoplay, lgFullscreen, lgZoom, lgVideo, lgThumbnail], 76 licenseKey: "9E9C183D-14564BA5-B09B8BE0-F8B54A20", 77 addClass: className, 78 autoplay: settings.autoplay, 79 slideShowAutoplay: settings.autoplay, 80 slideShowInterval: settings.speed.number, 81 autoplayFirstVideo: !settings.disable_autoplay_on_first_video, 82 autoplayVideoOnSlide: settings.autoplay_videos, // TODO: This option is broken in the library 83 thumbnail: settings.thumbnails, 84 animateThumb: settings.animated_thumbnails, 85 zoomFromOrigin: settings.animated_thumbnails, 86 zoom: true, 87 download: settings.show_download_button, 88 mobileSettings: { 89 controls: true, 90 showCloseIcon: true, 91 } 92 }; 93 } 94 95 getExtension(url) { 96 return url.split(".").pop(); 97 } 98 99 isVideo(url) { 100 const types = ["mp4", "mov", "wmv", "avi", "mpg", "ogg", "3gp", "3g2"]; 101 const extension = this.getExtension(url); 102 return types.includes(extension); 103 } 104 105 getVideoObject(url, caption, mime) { 106 if (!this.isVideo(url)) { 107 return { 108 src: url, 109 subHtml: caption, 110 }; 111 } 112 113 if (!mime) { 114 const extension = this.getExtension(url); 115 mime = `video/${extension}`; 116 } 117 118 return { 119 video: { 120 source: [ 121 { 122 src: url, 123 type: mime, 124 }, 125 ], 126 attributes: { 127 preload: false, 128 controls: true, 129 }, 130 }, 131 subHtml: caption, 132 subHtmlUrl: "", 133 }; 134 } 135 136 filterItems(item) { 137 const isImg = item.type === "image" && item.image; 138 const isVideo = item.type === "video" && item.video; 139 return isImg || isVideo; 140 } 141 142 itemize(item) { 143 // HTML5 videos or oEmbeds. 144 if (item.type === "video") { 145 return this.getVideoObject(item.video.url, item.caption); 146 } 147 148 // Handle HTML5 videos in WP Media Input 149 if (item.image && item.image.type === "video") { 150 return this.getVideoObject( 151 item.image.url, 152 item.caption, 153 item.image.mime 154 ); 155 } 156 157 return { 158 src: item.image.url, 159 type: item.image.type, 160 thumb: item.image.sizes.thumbnail.url, 161 subHtml: item.caption, 162 }; 163 } 164 165 getDynamicItems() { 166 return this.options.items.filter(this.filterItems).map(this.itemize); 167 } 168 169 detectDuplicateSwiperSlides() { 170 // If the slide clicked is a duplicate, we'll open the original slide in the lightbox instead. 171 this.element.addEventListener("click", (event) => { 172 const isDuplicateSlide = event.target.closest( 173 ".swiper-slide-duplicate" 174 ); 175 176 if (!isDuplicateSlide) return; 177 178 event.preventDefault();
179 const index = isDuplicateSlide.getAttribute("data-swiper-slide-index"); 180 this.lightbox.openGallery(index); 181 }); 182 } 183 184 addThumbnailsToVideos() { 185 const videoPlaceholder = 186 "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMAAAACYCAAAAACXarlBAAAACXBIWXMAAC4jAAAuIwF4pT92AAAB6UlEQVR42u3ZWU+DQBSGYf//7zKaAOew2FLQqomaaF1aXFqXaMfi2qJWLwQ58f2uJnM1T84Ms7DijGcFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP4p4DjfrCbPr5zbyy5NAE784EN8r3AuW5WRBcCWF39IFJ471/dVhxYA/peAWGXYfkB/CSCpR9AcIK6nBk0CZoKRbUBcw0puFlDDLGoY8PsruWFAWYNzi4B8TV6z1plaA1w4t999Oxv1di0CrJxGPwPEwYFxQBgNJnMZX1sDxJHoXLx0ag2wGMkAAAAAAMBygM5/+EWftzNRsQKQ9KQYvaYYbJQCDQ+LvtgAhJ2bhc6rKJyNv7wNb4kJQLBX6c1FtCgbA88GYL8K8ORp/GYA1Qp0vZfXlCObgGnn1NkGTJxtwHsA/NEUejAOuN+5MT6FkuTWFqC6kWXr6b3pCuTip081OLYB0Mq7yW2isd+7m7V2AxvHad0ezz1kXWTlGTToFpMDtXKhWXjIUn35OaMScaUEAABAvYDNnwB6LQbseN8DgtS1FzBJfP0momctBri74XC0PGdj12ZA8wEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE3lEeS3kwDalXS7AAAAAElFTkSuQmCC"; 187 188 const lgItems = this.lightbox.galleryItems; 189 190 if (!lgItems) return; 191 192 const items = lgItems.map((item) => { 193 if (item.video) { 194 return { 195 ...item, 196 thumb: item.thumb || videoPlaceholder, 197 src: null, // lightGallery goes crazy if the src key is present for videos. 198 }; 199 } 200 201 return item; 202 }); 203 204 this.lightbox.refresh(items); 205 } 206 207 update(options) { 208 this.options = mergeObjects(this.defaultOptions, options); 209 this.destroy(); 210 this.init(); 211 } 212 213 destroy() { 214 if (this.lightbox) { 215 this.lightbox.destroy(); 216 this.lightbox = null; 217 } 218 } 219 220 initDynamic() { 221 const items = this.getDynamicItems(); 222 223 this.element.addEventListener("click", () => { 224 this.createGallery({ 225 dynamic: true, 226 dynamicEl: items, 227 }); 228 229 // We wrap the method in a setTimeout, so that clicking the element 230 // won't fire a resize event before the gallery is ready. 231 // 232 // By clicking the element, the property panel opens up thus decreasing 233 // the iframe's width and triggering a resize event. 234 setTimeout(() => this.lightbox.openGallery(), 5); 235 }); 236 } 237 238 getItemFromAnchor(el) { 239 const src = el.href; 240 return this.isVideo(src) ? this.getVideoObject(src) : { src }; 241 } 242 243 filterByGallery(event) { 244 const { category } = event.detail; 245 246 const selector = category === "all" 247 ? this.itemSelector 248 : toArray(this.itemSelector).filter( 249 item => item.dataset.category === category 250 ); 251 252 this.lightbox.settings.selector = selector; 253 this.lightbox.refresh(); 254 } 255 256 initFromDOM() { 257 const onClick = (event) => { 258 const isLinkALightbox = event.currentTarget.dataset.type === "lightbox"; 259 const disableAutoplay = event.currentTarget.dataset.lightboxAutoplay === "false"; 260 261 this.options.disable_autoplay_on_first_video = disableAutoplay; 262 263 if (this.options.watchAttrs && !isLinkALightbox) return; 264 265 const item = this.getItemFromAnchor(this.element); 266 267 if (this.lightbox) { 268 this.lightbox.refresh([item]); 269 } else { 270 this.createGallery({ 271 dynamic: true, 272 dynamicEl: [item] 273 }); 274 } 275 276 this.lightbox.openGallery(); 277 }; 278 279 this.element.addEventListener("click", onClick); 280 } 281 282 initDefault() { 283 this.createGallery({ 284 selector: this.itemSelector, 285 }); 286 287 this.element.addEventListener("breakdance_gallery_filtered", this.filterByGallery); 288 } 289 290 init() { 291 const { type } = this.options; 292 293 if (type === "dynamic") { 294 // Element: Lightbox Gallery 295 // Show multiple images from an array 296 this.initDynamic(); 297 } else if (type === "single") { 298 // Element: Button, Text Link, and Image (v1) 299 // Show an image from a href attribute 300 this.initFromDOM(); 301 } else { 302 // Element: Gallery 303 // Show multiple images from DOM elements with the same css class 304 this.initDefault(); 305 } 306 307 this.element.addEventListener("click", (event) => event.preventDefault()); 308 this.element.classList.add("is-lightbox-active"); 309 } 310 311 static autoload(parent = null) { 312 const element = parent ?? document; 313 // Autoload lightboxes from macros 314 const selector = 315 ".breakdance-link[data-type='lightbox']:not(.is-lightbox-active), .oxygen-link[data-type='lightbox']:not(.is-lightbox-active)"; 316 const links = element.querySelectorAll(selector); 317 318 links.forEach((link) => { 319 new this(link, { 320 type: "single", 321 watchAttrs: true, 322 }); 323 }); 324 } 325 } 326 327 BreakdanceLightbox.autoload(); 328 window.BreakdanceLightbox = BreakdanceLightbox; 329})();
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.