1/*! Lity - v2.4.1 - 2020-04-26 2 * http://sorgalla.com/lity/ 3 * Copyright (c) 2015-2020 Jan Sorgalla; Licensed MIT */ 4;(function (window, factory) { 5 if (typeof define === "function" && define.amd) { 6 define(["jquery"], function ($) { 7 return factory(window, $) 8 }) 9 } else if (typeof module === "object" && typeof module.exports === "object") { 10 module.exports = factory(window, require("jquery")) 11 } else { 12 window.lity = factory(window, window.jQuery || window.Zepto) 13 } 14})(typeof window !== "undefined" ? window : this, function (window, $) { 15 "use strict" 16 17 var document = window.document 18 19 var _win = $(window) 20 var _deferred = $.Deferred 21 var _html = $("html") 22 var _instances = [] 23 24 var _attrAriaHidden = "aria-hidden" 25 var _dataAriaHidden = "lity-" + _attrAriaHidden 26 27 var _focusableElementsSelector = 28 'a[href],area[href],input:not([disabled]),select:not([disabled]),textarea:not([disabled]),button:not([disabled]),iframe,object,embed,[contenteditable],[tabindex]:not([tabindex^="-"])' 29 30 var _defaultOptions = { 31 esc: true, 32 handler: null, 33 handlers: { 34 image: imageHandler, 35 inline: inlineHandler, 36 youtube: youtubeHandler, 37 vimeo: vimeoHandler, 38 googlemaps: googlemapsHandler, 39 facebookvideo: facebookvideoHandler, 40 iframe: iframeHandler, 41 }, 42 template: 43 '<div class="lity" role="dialog" aria-label="Dialog Window (Press escape to close)" tabindex="-1"><div class="lity-wrap" data-lity-close role="document"><div class="lity-loader" aria-hidden="true">Loading...</div><div class="lity-container"><div class="lity-content"></div><button class="lity-close" type="button" aria-label="Close (Press escape to close)" data-lity-close>×</button></div></div></div>', 44 } 45 46 var _imageRegexp = 47 /(^data:image\/)|(\.(png|jpe?g|gif|svg|webp|bmp|ico|tiff?)(\?\S*)?$)/i 48 var _youtubeRegex = 49 /(youtube(-nocookie)?\.com|youtu\.be)\/(watch\?v=|v\/|u\/|embed\/?)?([\w-]{11})(.*)?/i 50 var _vimeoRegex = /(vimeo(pro)?.com)\/(?:[^\d]+)?(\d+)\??(.*)?$/ 51 var _googlemapsRegex = 52 /((maps|www)\.)?google\.([^\/\?]+)\/?((maps\/?)?\?)(.*)/i 53 var _facebookvideoRegex = 54 /(facebook\.com)\/([a-z0-9_-]*)\/videos\/([0-9]*)(.*)?$/i 55 56 var _transitionEndEvent = (function () { 57 var el = document.createElement("div") 58 59 var transEndEventNames = { 60 WebkitTransition: "webkitTransitionEnd", 61 MozTransition: "transitionend", 62 OTransition: "oTransitionEnd otransitionend", 63 transition: "transitionend", 64 } 65 66 for (var name in transEndEventNames) { 67 if (el.style[name] !== undefined) { 68 return transEndEventNames[name] 69 } 70 } 71 72 return false 73 })() 74 75 function transitionEnd(element) { 76 var deferred = _deferred() 77 78 if (!_transitionEndEvent || !element.length) { 79 deferred.resolve() 80 } else { 81 element.one(_transitionEndEvent, deferred.resolve) 82 setTimeout(deferred.resolve, 500) 83 } 84 85 return deferred.promise() 86 } 87 88 function settings(currSettings, key, value) { 89 if (arguments.length === 1) { 90 return $.extend({}, currSettings) 91 } 92 93 if (typeof key === "string") { 94 if (typeof value === "undefined") { 95 return typeof currSettings[key] === "undefined" 96 ? null 97 : currSettings[key] 98 } 99 100 currSettings[key] = value 101 } else { 102 $.extend(currSettings, key) 103 } 104 105 return this 106 } 107 108 function parseQueryParams(params) { 109 var pairs = decodeURI(params.split("#")[0]).split("&") 110 var obj = {}, 111 p 112 113 for (var i = 0, n = pairs.length; i < n; i++) { 114 if (!pairs[i]) { 115 continue 116 } 117 118 p = pairs[i].split("=") 119 obj[p[0]] = p[1] 120 } 121 122 return obj 123 } 124 125 function appendQueryParams(url, params) { 126 return url + (url.indexOf("?") > -1 ? "&" : "?") + $.param(params) 127 } 128 129 function transferHash(originalUrl, newUrl) { 130 var pos = originalUrl.indexOf("#") 131 132 if (-1 === pos) { 133 return newUrl 134 } 135 136 if (pos > 0) { 137 originalUrl = originalUrl.substr(pos) 138 } 139 140 return newUrl + originalUrl 141 } 142 143 function error(msg) { 144 return $('<span class="lity-error"></span>').append(msg) 145 } 146 147 function imageHandler(target, instance) { 148 var desc = 149 (instance.opener() && instance.opener().data("lity-desc")) || 150 "Image with no description" 151 var img = $('<img src="' + target + '" alt="' + desc + '"/>') 152 var deferred = _deferred() 153 var failed = function () { 154 deferred.reject(error("Failed loading image")) 155 } 156 157 img 158 .on("load", function () {
159 if (this.naturalWidth === 0) { 160 return failed() 161 } 162 163 deferred.resolve(img) 164 }) 165 .on("error", failed) 166 167 return deferred.promise() 168 } 169 170 imageHandler.test = function (target) { 171 return _imageRegexp.test(target) 172 } 173 174 function inlineHandler(target, instance) { 175 var el, placeholder, hasHideClass 176 177 try { 178 el = $(target) 179 } catch (e) { 180 return false 181 } 182 183 if (!el.length) { 184 return false 185 } 186 187 placeholder = $('<i style="display:none !important"></i>') 188 hasHideClass = el.hasClass("lity-hide") 189 190 instance.element().one("lity:remove", function () { 191 placeholder.before(el).remove() 192 193 if (hasHideClass && !el.closest(".lity-content").length) { 194 el.addClass("lity-hide") 195 } 196 }) 197 198 return el.removeClass("lity-hide").after(placeholder) 199 } 200 201 function youtubeHandler(target) { 202 var matches = _youtubeRegex.exec(target) 203 204 if (!matches) { 205 return false 206 } 207 208 return iframeHandler( 209 transferHash( 210 target, 211 appendQueryParams( 212 "https://www.youtube" + 213 (matches[2] || "") + 214 ".com/embed/" + 215 matches[4], 216 $.extend( 217 { 218 autoplay: 1, 219 }, 220 parseQueryParams(matches[5] || "") 221 ) 222 ) 223 ) 224 ) 225 } 226 227 function vimeoHandler(target) { 228 var matches = _vimeoRegex.exec(target) 229 230 if (!matches) { 231 return false 232 } 233 234 return iframeHandler( 235 transferHash( 236 target, 237 appendQueryParams( 238 "https://player.vimeo.com/video/" + matches[3], 239 $.extend( 240 { 241 autoplay: 1, 242 }, 243 parseQueryParams(matches[4] || "") 244 ) 245 ) 246 ) 247 ) 248 } 249 250 function facebookvideoHandler(target) { 251 var matches = _facebookvideoRegex.exec(target) 252 253 if (!matches) { 254 return false 255 } 256 257 if (0 !== target.indexOf("http")) { 258 target = "https:" + target 259 } 260 261 return iframeHandler( 262 transferHash( 263 target, 264 appendQueryParams( 265 "https://www.facebook.com/plugins/video.php?href=" + target, 266 $.extend( 267 { 268 autoplay: 1, 269 }, 270 parseQueryParams(matches[4] || "") 271 ) 272 ) 273 ) 274 ) 275 } 276 277 function googlemapsHandler(target) { 278 var matches = _googlemapsRegex.exec(target) 279 280 if (!matches) { 281 return false 282 } 283 284 return iframeHandler( 285 transferHash( 286 target, 287 appendQueryParams( 288 "https://www.google." + matches[3] + "/maps?" + matches[6], 289 { 290 output: matches[6].indexOf("layer=c") > 0 ? "svembed" : "embed", 291 } 292 ) 293 ) 294 ) 295 } 296 297 function iframeHandler(target) { 298 return ( 299 '<div class="lity-iframe-container"><iframe frameborder="0" allowfullscreen allow="autoplay; fullscreen" src="' + 300 target + 301 '"/></div>' 302 ) 303 } 304 305 function winHeight() { 306 return document.documentElement.clientHeight 307 ? document.documentElement.clientHeight 308 : Math.round(_win.height()) 309 } 310 311 function keydown(e) { 312 var current = currentInstance() 313 314 if (!current) { 315 return 316 } 317 318 // ESC key 319 if (e.keyCode === 27 && !!current.options("esc")) { 320 current.close() 321 } 322 323 // TAB key 324 if (e.keyCode === 9) { 325 handleTabKey(e, current) 326 } 327 } 328 329 function handleTabKey(e, instance) { 330 var focusableElements = instance.element().find(_focusableElementsSelector) 331 var focusedIndex = focusableElements.index(document.activeElement) 332 333 if (e.shiftKey && focusedIndex <= 0) { 334 focusableElements.get(focusableElements.length - 1).focus() 335 e.preventDefault() 336 } else if (!e.shiftKey && focusedIndex === focusableElements.length - 1) { 337 focusableElements.get(0).focus() 338 e.preventDefault() 339 } 340 } 341 342 function resize() { 343 $.each(_instances, function (i, instance) { 344 instance.resize() 345 }) 346 } 347 348 function registerInstance(instanceToRegister) { 349 if (1 === _instances.unshift(instanceToRegister)) { 350 _html.addClass("lity-active") 351 352 _win.on({ 353 resize: resize, 354 keydown: keydown, 355 }) 356 } 357 358 $("body > *") 359 .not(instanceToRegister.element()) 360 .addClass("lity-hidden") 361 .each(function () { 362 var el = $(this) 363 364 if (undefined !== el.data(_dataAriaHidden)) { 365 return 366 } 367 368 el.data(_dataAriaHidden, el.attr(_attrAriaHidden) || null) 369 }) 370 .attr(_attrAriaHidden, "true") 371 } 372 373 function removeInstance(instanceToRemove) { 374 var show 375 376 instanceToRemove.element().attr(_attrAriaHidden, "true") 377 378 if (1 === _instances.length) { 379 _html.removeClass("lity-active") 380 381 _win.off({ 382 resize: resize, 383 keydown: keydown, 384 }) 385 } 386 387 _instances = $.grep(_instances, function (instance) { 388 return instanceToRemove !== instance 389 }) 390 391 if (!!_instances.length) {
392 show = _instances[0].element() 393 } else { 394 show = $(".lity-hidden") 395 } 396 397 show.removeClass("lity-hidden").each(function () { 398 var el = $(this), 399 oldAttr = el.data(_dataAriaHidden) 400 401 if (!oldAttr) { 402 el.removeAttr(_attrAriaHidden) 403 } else { 404 el.attr(_attrAriaHidden, oldAttr) 405 } 406 407 el.removeData(_dataAriaHidden) 408 }) 409 } 410 411 function currentInstance() { 412 if (0 === _instances.length) { 413 return null 414 } 415 416 return _instances[0] 417 } 418 419 function factory(target, instance, handlers, preferredHandler) { 420 var handler = "inline", 421 content 422 423 var currentHandlers = $.extend({}, handlers) 424 425 if (preferredHandler && currentHandlers[preferredHandler]) { 426 content = currentHandlers[preferredHandler](target, instance) 427 handler = preferredHandler 428 } else { 429 // Run inline and iframe handlers after all other handlers 430 $.each(["inline", "iframe"], function (i, name) { 431 delete currentHandlers[name] 432 433 currentHandlers[name] = handlers[name] 434 }) 435 436 $.each(currentHandlers, function (name, currentHandler) { 437 // Handler might be "removed" by setting callback to null 438 if (!currentHandler) { 439 return true 440 } 441 442 if (currentHandler.test && !currentHandler.test(target, instance)) { 443 return true 444 } 445 446 content = currentHandler(target, instance) 447 448 if (false !== content) { 449 handler = name 450 return false 451 } 452 }) 453 } 454 455 return { handler: handler, content: content || "" } 456 } 457 458 function Lity(target, options, opener, activeElement) { 459 var self = this 460 var result 461 var isReady = false 462 var isClosed = false 463 var element 464 var content 465 466 options = $.extend({}, _defaultOptions, options) 467 468 element = $(options.template) 469 470 // -- API -- 471 472 self.element = function () { 473 return element 474 } 475 476 self.opener = function () { 477 return opener 478 } 479 480 self.options = $.proxy(settings, self, options) 481 self.handlers = $.proxy(settings, self, options.handlers) 482 483 self.resize = function () { 484 if (!isReady || isClosed) { 485 return 486 } 487 488 content 489 .css("max-height", winHeight() + "px") 490 .trigger("lity:resize", [self]) 491 } 492 493 self.close = function () { 494 if (!isReady || isClosed) { 495 return 496 } 497 498 isClosed = true 499 500 removeInstance(self) 501 502 var deferred = _deferred() 503 504 // We return focus only if the current focus is inside this instance 505 if ( 506 activeElement && 507 (document.activeElement === element[0] || 508 $.contains(element[0], document.activeElement)) 509 ) { 510 try { 511 activeElement.focus() 512 } catch (e) { 513 // Ignore exceptions, eg. for SVG elements which can't be 514 // focused in IE11 515 } 516 } 517 518 content.trigger("lity:close", [self]) 519 520 element.removeClass("lity-opened").addClass("lity-closed") 521 522 transitionEnd(content.add(element)).always(function () { 523 content.trigger("lity:remove", [self]) 524 element.remove() 525 element = undefined 526 deferred.resolve() 527 }) 528 529 return deferred.promise() 530 } 531 532 // -- Initialization -- 533 534 result = factory(target, self, options.handlers, options.handler) 535 536 element 537 .attr(_attrAriaHidden, "false") 538 .addClass("lity-loading lity-opened lity-" + result.handler) 539 .appendTo("body") 540 .focus() 541 .on("click", "[data-lity-close]", function (e) { 542 if ($(e.target).is("[data-lity-close]")) { 543 self.close() 544 } 545 }) 546 .trigger("lity:open", [self]) 547 548 registerInstance(self) 549 550 $.when(result.content).always(ready) 551 552 function ready(result) { 553 content = $(result).css("max-height", winHeight() + "px") 554 555 element.find(".lity-loader").each(function () { 556 var loader = $(this) 557 558 transitionEnd(loader).always(function () { 559 loader.remove() 560 }) 561 }) 562 563 element 564 .removeClass("lity-loading") 565 .find(".lity-content") 566 .empty() 567 .append(content) 568 569 isReady = true 570 571 content.trigger("lity:ready", [self]) 572 } 573 } 574 575 function lity(target, options, opener) { 576 if (!target.preventDefault) { 577 opener = $(opener) 578 } else { 579 target.preventDefault() 580 opener = $(this) 581 target = 582 opener.data("lity-target") || opener.attr("href") || opener.attr("src") 583 } 584 585 var instance = new Lity( 586 target, 587 $.extend({}, opener.data("lity-options") || opener.data("lity"), options), 588 opener, 589 document.activeElement 590 ) 591 592 if (!target.preventDefault) { 593 return instance 594 } 595 } 596 597 lity.version = "2.4.1" 598 lity.options = $.proxy(settings, lity, _defaultOptions) 599 lity.handlers = $.proxy(settings, lity, _defaultOptions.handlers) 600 lity.current = currentInstance 601 602 $(document).on("click.lity", "[data-lity]", lity) 603 604 return lity 605})
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.