1/* 2Lightbox for Bootstrap 3 by @ashleydw 3https://github.com/ashleydw/lightbox 4 5License: https://github.com/ashleydw/lightbox/blob/master/LICENSE 6*/ 7 8 9(function() { 10 "use strict"; 11 var $, EkkoLightbox; 12 13 $ = jQuery; 14 15 EkkoLightbox = function(element, options) { 16 var content, footer, header, 17 _this = this; 18 this.options = $.extend({ 19 title: null, 20 footer: null, 21 remote: null 22 }, $.fn.ekkoLightbox.defaults, options || {}); 23 this.$element = $(element); 24 content = ''; 25 this.modal_id = this.options.modal_id ? this.options.modal_id : 'ekkoLightbox-' + Math.floor((Math.random() * 1000) + 1); 26 header = '<div class="modal-header"' + (this.options.title || this.options.always_show_close ? '' : ' style="display:none"') + '><button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button><h4 class="modal-title">' + (this.options.title || " ") + '</h4></div>'; 27 footer = '<div class="modal-footer"' + (this.options.footer ? '' : ' style="display:none"') + '>' + this.options.footer + '</div>'; 28 $(document.body).append('<div id="' + this.modal_id + '" class="ekko-lightbox modal fade" tabindex="-1"><div class="modal-dialog"><div class="modal-content">' + header + '<div class="modal-body"><div class="ekko-lightbox-container"><div></div></div></div>' + footer + '</div></div></div>'); 29 this.modal = $('#' + this.modal_id); 30 this.modal_dialog = this.modal.find('.modal-dialog').first(); 31 this.modal_content = this.modal.find('.modal-content').first(); 32 this.modal_body = this.modal.find('.modal-body').first(); 33 this.lightbox_container = this.modal_body.find('.ekko-lightbox-container').first(); 34 this.lightbox_body = this.lightbox_container.find('> div:first-child').first(); 35 this.showLoading(); 36 this.modal_arrows = null; 37 this.border = { 38 top: parseFloat(this.modal_dialog.css('border-top-width')) + parseFloat(this.modal_content.css('border-top-width')) + parseFloat(this.modal_body.css('border-top-width')), 39 right: parseFloat(this.modal_dialog.css('border-right-width')) + parseFloat(this.modal_content.css('border-right-width')) + parseFloat(this.modal_body.css('border-right-width')), 40 bottom: parseFloat(this.modal_dialog.css('border-bottom-width')) + parseFloat(this.modal_content.css('border-bottom-width')) + parseFloat(this.modal_body.css('border-bottom-width')), 41 left: parseFloat(this.modal_dialog.css('border-left-width')) + parseFloat(this.modal_content.css('border-left-width')) + parseFloat(this.modal_body.css('border-left-width')) 42 }; 43 this.padding = { 44 top: parseFloat(this.modal_dialog.css('padding-top')) + parseFloat(this.modal_content.css('padding-top')) + parseFloat(this.modal_body.css('padding-top')), 45 right: parseFloat(this.modal_dialog.css('padding-right')) + parseFloat(this.modal_content.css('padding-right')) + parseFloat(this.modal_body.css('padding-right')), 46 bottom: parseFloat(this.modal_dialog.css('padding-bottom')) + parseFloat(this.modal_content.css('padding-bottom')) + parseFloat(this.modal_body.css('padding-bottom')), 47 left: parseFloat(this.modal_dialog.css('padding-left')) + parseFloat(this.modal_content.css('padding-left')) + parseFloat(this.modal_body.css('padding-left')) 48 }; 49 this.modal.on('show.bs.modal', this.options.onShow.bind(this)).on('shown.bs.modal', function() { 50 _this.modal_shown(); 51 return _this.options.onShown.call(_this); 52 }).on('hide.bs.modal', this.options.onHide.bind(this)).on('hidden.bs.modal', function() { 53 if (_this.gallery) { 54 $(document).off('keydown.ekkoLightbox'); 55 } 56 _this.modal.remove(); 57 return _this.options.onHidden.call(_this); 58 }).modal('show', options); 59 return this.modal; 60 }; 61 62 EkkoLightbox.prototype = { 63 modal_shown: function() { 64 var video_id, 65 _this = this; 66 if (!this.options.remote) { 67 return this.error('No remote target given'); 68 } else { 69 this.gallery = this.$element.data('gallery'); 70 if (this.gallery) { 71 if (this.options.gallery_parent_selector === 'document.body' || this.options.gallery_parent_selector === '') { 72 this.gallery_items = $(document.body).find('*[data-toggle="lightbox"][data-gallery="' + this.gallery + '"]'); 73 } else { 74 this.gallery_items = this.$element.parents(this.options.gallery_parent_selector).first().find('*[data-toggle="lightbox"][data-gallery="' + this.gallery + '"]'); 75 } 76 this.gallery_index = this.gallery_items.index(this.$element); 77 $(document).on('keydown.ekkoLightbox', this.navigate.bind(this)); 78 if (this.options.directional_arrows && this.gallery_items.length > 1) { 79 this.lightbox_container.prepend('<div class="ekko-lightbox-nav-overlay"><a href="#" class="' + this.strip_stops(this.options.left_arrow_class) + '"></a><a href="#" class="' + this.strip_stops(this.options.right_arrow_class) + '"></a></div>'); 80 this.modal_arrows = this.lightbox_container.find('div.ekko-lightbox-nav-overlay').first(); 81 this.lightbox_container.find('a' + this.strip_spaces(this.options.left_arrow_class)).on('click', function(event) { 82 event.preventDefault(); 83 return _this.navigate_left(); 84 }); 85 this.lightbox_container.find('a' + this.strip_spaces(this.options.right_arrow_class)).on('click', function(event) { 86 event.preventDefault(); 87 return _this.navigate_right(); 88 }); 89 } 90 } 91 if (this.options.type) { 92 if (this.options.type === 'image') { 93 return this.preloadImage(this.options.remote, true); 94 } else if (this.options.type === 'youtube' && (video_id = this.getYoutubeId(this.options.remote))) { 95 return this.showYoutubeVideo(video_id); 96 } else if (this.options.type === 'vimeo') { 97 return this.showVimeoVideo(this.options.remote); 98 } else if (this.options.type === 'instagram') { 99 return this.showInstagramVideo(this.options.remote); 100 } else if (this.options.type === 'url') { 101 return this.showInstagramVideo(this.options.remote); 102 } else { 103 return this.error("Could not detect remote target type. Force the type using data-type=\"image|youtube|vimeo|url\""); 104 } 105 } else { 106 return this.detectRemoteType(this.options.remote); 107 } 108 } 109 }, 110 strip_stops: function(str) { 111 return str.replace(/\./g, ''); 112 }, 113 strip_spaces: function(str) { 114 return str.replace(/\s/g, ''); 115 }, 116 isImage: function(str) { 117 return str.match(/(^data:image\/.*,)|(\.(jp(e|g|eg)|gif|png|bmp|webp|svg)((\?|#).*)?$)/i); 118 }, 119 isSwf: function(str) { 120 return str.match(/\.(swf)((\?|#).*)?$/i); 121 }, 122 getYoutubeId: function(str) { 123 var match; 124 match = str.match(/^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|\&v=)([^#\&\?]*).*/); 125 if (match && match[2].length === 11) { 126 return match[2]; 127 } else { 128 return false;
129 } 130 }, 131 getVimeoId: function(str) { 132 if (str.indexOf('vimeo') > 0) { 133 return str; 134 } else { 135 return false; 136 } 137 }, 138 getInstagramId: function(str) { 139 if (str.indexOf('instagram') > 0) { 140 return str; 141 } else { 142 return false; 143 } 144 }, 145 navigate: function(event) { 146 event = event || window.event; 147 if (event.keyCode === 39 || event.keyCode === 37) { 148 if (event.keyCode === 39) { 149 return this.navigate_right(); 150 } else if (event.keyCode === 37) { 151 return this.navigate_left(); 152 } 153 } 154 }, 155 navigateTo: function(index) { 156 var next, src; 157 if (index < 0 || index > this.gallery_items.length - 1) { 158 return this; 159 } 160 this.showLoading(); 161 this.gallery_index = index; 162 this.options.onNavigate.call(this, this.gallery_index); 163 this.$element = $(this.gallery_items.get(this.gallery_index)); 164 this.updateTitleAndFooter(); 165 src = this.$element.attr('data-remote') || this.$element.attr('href'); 166 this.detectRemoteType(src, this.$element.attr('data-type') || false); 167 if (this.gallery_index + 1 < this.gallery_items.length) { 168 next = $(this.gallery_items.get(this.gallery_index + 1), false); 169 src = next.attr('data-remote') || next.attr('href'); 170 if (next.attr('data-type') === 'image' || this.isImage(src)) { 171 return this.preloadImage(src, false); 172 } 173 } 174 }, 175 navigate_left: function() { 176 if (this.gallery_items.length === 1) { 177 return; 178 } 179 if (this.gallery_index === 0) { 180 this.gallery_index = this.gallery_items.length - 1; 181 } else { 182 this.gallery_index--; 183 } 184 this.options.onNavigate.call(this, 'left', this.gallery_index); 185 return this.navigateTo(this.gallery_index); 186 }, 187 navigate_right: function() { 188 if (this.gallery_items.length === 1) { 189 return; 190 } 191 if (this.gallery_index === this.gallery_items.length - 1) { 192 this.gallery_index = 0; 193 } else { 194 this.gallery_index++; 195 } 196 this.options.onNavigate.call(this, 'right', this.gallery_index); 197 return this.navigateTo(this.gallery_index); 198 }, 199 detectRemoteType: function(src, type) { 200 var video_id; 201 if (type === 'image' || this.isImage(src)) { 202 this.options.type = 'image'; 203 return this.preloadImage(src, true); 204 } else if (type === 'youtube' || (video_id = this.getYoutubeId(src))) { 205 this.options.type = 'youtube'; 206 return this.showYoutubeVideo(video_id); 207 } else if (type === 'vimeo' || (video_id = this.getVimeoId(src))) { 208 this.options.type = 'vimeo'; 209 return this.showVimeoVideo(video_id); 210 } else if (type === 'instagram' || (video_id = this.getInstagramId(src))) { 211 this.options.type = 'instagram'; 212 return this.showInstagramVideo(video_id); 213 } else if (type === 'url' || (video_id = this.getInstagramId(src))) { 214 this.options.type = 'instagram'; 215 return this.showInstagramVideo(video_id); 216 } else { 217 this.options.type = 'url'; 218 return this.loadRemoteContent(src); 219 } 220 }, 221 updateTitleAndFooter: function() { 222 var caption, footer, header, title; 223 header = this.modal_content.find('.modal-header'); 224 footer = this.modal_content.find('.modal-footer'); 225 title = this.$element.data('title') || ""; 226 caption = this.$element.data('footer') || ""; 227 if (title || this.options.always_show_close) { 228 header.css('display', '').find('.modal-title').html(title || " "); 229 } else { 230 header.css('display', 'none'); 231 } 232 if (caption) { 233 footer.css('display', '').html(caption); 234 } else { 235 footer.css('display', 'none'); 236 } 237 return this; 238 }, 239 showLoading: function() { 240 this.lightbox_body.html('<div class="modal-loading">Loading..</div>'); 241 return this; 242 }, 243 showYoutubeVideo: function(id) { 244 var aspectRatio, height, width; 245 aspectRatio = 560 / 315; 246 width = this.$element.data('width') || 560; 247 width = this.checkDimensions(width); 248 height = width / aspectRatio; 249 this.resize(width); 250 this.lightbox_body.html('<iframe width="' + width + '" height="' + height + '" src="//www.youtube.com/embed/' + id + '?badge=0&autoplay=1&html5=1&rel=0&=modestbranding=1" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe>'); 251 this.options.onContentLoaded.call(this); 252 if (this.modal_arrows) { 253 return this.modal_arrows.css('display', 'none'); 254 } 255 }, 256 showVimeoVideo: function(id) { 257 var aspectRatio, height, width; 258 aspectRatio = 500 / 281; 259 width = this.$element.data('width') || 560; 260 width = this.checkDimensions(width); 261 height = width / aspectRatio; 262 this.resize(width); 263 this.lightbox_body.html('<iframe width="' + width + '" height="' + height + '" src="' + id + '?autoplay=1" frameborder="0" allowfullscreen></iframe>'); 264 this.options.onContentLoaded.call(this); 265 if (this.modal_arrows) { 266 return this.modal_arrows.css('display', 'none'); 267 } 268 }, 269 showInstagramVideo: function(id) { 270 var width; 271 width = this.$element.data('width') || 612; 272 width = this.checkDimensions(width); 273 this.resize(width); 274 this.lightbox_body.html('<iframe width="' + width + '" height="' + width + '" src="' + this.addTrailingSlash(id) + 'embed/" frameborder="0" allowfullscreen></iframe>'); 275 this.options.onContentLoaded.call(this); 276 if (this.modal_arrows) { 277 return this.modal_arrows.css('display', 'none'); 278 } 279 }, 280 loadRemoteContent: function(url) { 281 var disableExternalCheck, width, 282 _this = this; 283 width = this.$element.data('width') || 560; 284 this.resize(width); 285 disableExternalCheck = this.$element.data('disableExternalCheck') || false; 286 console.log(disableExternalCheck, this.isExternal(url)); 287 if (!disableExternalCheck && !this.isExternal(url)) { 288 this.lightbox_body.load(url, $.proxy(function() { 289 return _this.$element.trigger('loaded.bs.modal'); 290 })); 291 } else { 292 this.lightbox_body.html('<iframe width="' + width + '" height="' + width + '" src="' + url + '" frameborder="0" allowfullscreen></iframe>'); 293 this.options.onContentLoaded.call(this); 294 } 295 if (this.modal_arrows) { 296 return this.modal_arrows.css('display', 'block'); 297 } 298 }, 299 isExternal: function(url) { 300 var match; 301 match = url.match(/^([^:\/?#]+:)?(?:\/\/([^\/?#]*))?([^?#]+)?(\?[^#]*)?(#.*)?/); 302 if (typeof match[1] === "string" && match[1].length > 0 && match[1].toLowerCase() !== location.protocol) { 303 return true; 304 } 305 if (typeof match[2] === "string" && match[2].length > 0 && match[2].replace(new RegExp(":(" + { 306 "http:": 80, 307 "https:": 443 308 }[location.protocol] + ")?$"), "") !== location.host) { 309 return true; 310 } 311 return false;
312 }, 313 error: function(message) { 314 this.lightbox_body.html(message); 315 return this; 316 }, 317 preloadImage: function(src, onLoadShowImage) { 318 var img, 319 _this = this; 320 img = new Image(); 321 if ((onLoadShowImage == null) || onLoadShowImage === true) { 322 img.onload = function() { 323 var image; 324 image = $('<img />'); 325 image.attr('src', img.src); 326 image.addClass('img-responsive'); 327 _this.lightbox_body.html(image); 328 if (_this.modal_arrows) { 329 _this.modal_arrows.css('display', 'block'); 330 } 331 _this.resize(img.width); 332 return _this.options.onContentLoaded.call(_this); 333 }; 334 img.onerror = function() { 335 return _this.error('Failed to load image: ' + src); 336 }; 337 } 338 img.src = src; 339 return img; 340 }, 341 resize: function(width) { 342 var width_total; 343 width_total = width + this.border.left + this.padding.left + this.padding.right + this.border.right; 344 this.modal_dialog.css('width', 'auto').css('max-width', width_total); 345 this.lightbox_container.find('a').css('padding-top', function() { 346 return $(this).parent().height() / 2; 347 }); 348 return this; 349 }, 350 checkDimensions: function(width) { 351 var body_width, width_total; 352 width_total = width + this.border.left + this.padding.left + this.padding.right + this.border.right; 353 body_width = document.body.clientWidth; 354 if (width_total > body_width) { 355 width = this.modal_body.width(); 356 } 357 return width; 358 }, 359 close: function() { 360 return this.modal.modal('hide'); 361 }, 362 addTrailingSlash: function(url) { 363 if (url.substr(-1) !== '/') { 364 url += '/'; 365 } 366 return url; 367 } 368 }; 369 370 $.fn.ekkoLightbox = function(options) { 371 return this.each(function() { 372 var $this; 373 $this = $(this); 374 options = $.extend({ 375 remote: $this.attr('data-remote') || $this.attr('href'), 376 gallery_parent_selector: $this.attr('data-parent'), 377 type: $this.attr('data-type') 378 }, options, $this.data()); 379 new EkkoLightbox(this, options); 380 return this; 381 }); 382 }; 383 384 $.fn.ekkoLightbox.defaults = { 385 gallery_parent_selector: '*:not(.row)', 386 left_arrow_class: '.glyphicon .glyphicon-chevron-left', 387 right_arrow_class: '.glyphicon .glyphicon-chevron-right', 388 directional_arrows: true, 389 type: null, 390 always_show_close: true, 391 onShow: function() {}, 392 onShown: function() {}, 393 onHide: function() {}, 394 onHidden: function() {}, 395 onNavigate: function() {}, 396 onContentLoaded: function() {} 397 }; 398 399}).call(this);
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.