https://www.pasitoblanco.com/wp-content/plugins/draw-attention/public/assets/js/public.js?ver=2.1.10
1(function ($, hotspots, undefined) { 2 "use strict"; 3 4 var Leaflet = L.noConflict(); 5 6 var ua = window.navigator.userAgent, 7 isiOS = !!ua.match(/iPad/i) || !!ua.match(/iPhone/i), 8 isWebkit = !!ua.match(/WebKit/i), 9 isWebkitiOS = isiOS && isWebkit, 10 isMobileSafari = isiOS && isWebkit && !ua.match(/CriOS/i), 11 getBrowserVersion = function () { 12 var temp, 13 M = 14 ua.match( 15 /(opera|chrome|safari|firefox|msie|trident(?=\/))\/?\s*(\d+)/i, 16 ) || []; 17 18 M = M[2] ? [M[1], M[2]] : [navigator.appName, navigator.appVersion, "-?"]; 19 if ((temp = ua.match(/version\/(\d+)/i)) != null) { 20 M.splice(1, 1, temp[1]); 21 } 22 return parseInt(M[1]); 23 }; 24 25 // Store all the leaflets on the page in an array for access later 26 var leaflets = []; 27 28 // Store all image maps on the page in an object for access later 29 var imageMaps = {}; 30 31 // Store all the more info area hotspots in an object for access later 32 hotspots.infoSpots = {}; 33 34 // Intersection Observer to detect when hidden hotspots become visible 35 var hotspotVisibilityObserver = null; 36 37 const layoutsThatShowTitleOnFocus = [ 38 "left", 39 "right", 40 "bottom", 41 "top", 42 "lightbox", 43 ]; 44 45 var setupHotspotVisibilityObserver = function () { 46 if (!window.IntersectionObserver) { 47 return; // Browser doesn't support Intersection Observer 48 } 49 50 hotspotVisibilityObserver = new IntersectionObserver( 51 function (entries) { 52 entries.forEach(function (entry) { 53 if (entry.isIntersecting) { 54 // Hotspot container has become visible 55 var container = entry.target; 56 var containerJQuery = $(container); 57 58 // Check if this container was previously hidden 59 if (containerJQuery.data("was-hidden")) { 60 console.log("Hotspot container became visible:", container); 61 62 hotspots.init(); // Reinitialize hotspots 63 containerJQuery.removeData("was-hidden"); 64 } 65 } else { 66 // Hotspot container has become hidden 67 var container = entry.target; 68 var containerJQuery = $(container); 69 70 containerJQuery.data("was-hidden", true); 71 } 72 }); 73 }, 74 { 75 threshold: 0.1, 76 rootMargin: "10px", 77 }, 78 ); 79 }; 80 81 var observeHotspotContainer = function (container) { 82 if (hotspotVisibilityObserver && container.length) { 83 var containerElement = container.get(0); 84 var rect = containerElement.getBoundingClientRect(); 85 var isInitiallyHidden = 86 rect.width === 0 || 87 rect.height === 0 || 88 window.getComputedStyle(containerElement).display === "none" || 89 window.getComputedStyle(containerElement).visibility === "hidden"; 90 91 if (isInitiallyHidden) { 92 container.data("was-hidden", true); 93 } 94 95 hotspotVisibilityObserver.observe(containerElement); 96 } 97 }; 98 99 var mapSetup = function () { 100 $(".da-error").hide(); 101 $(".hotspot-info").addClass("da-hidden"); 102 103 setupHotspotVisibilityObserver(); 104 105 var images = $("img.hotspots-image, picture.hotspots-image img"); // Select images as well as images inside picture elements 106 107 images.each(function () { 108 var img = $(this); 109 110 var tester = new Image(); 111 112 tester.onload = function () { 113 markLoaded(img); 114 moreInfoSetup(img); 115 leafletSetup(img); 116 var container = img.parents(".hotspots-container"); 117 observeHotspotContainer(container); 118 }; 119 tester.src = img.attr("src"); 120 }); 121 122 if (isMobileSafari) { 123 window.onpageshow = function (event) { 124 if (event.persisted) { 125 window.location.reload(); 126 } 127 }; 128 } 129 }; 130 131 var markLoaded = function (img) { 132 img.data("status", "loaded"); 133 var container = img.parents(".hotspots-container").addClass("loaded"); 134 img.attr("aria-hidden", true); 135 }; 136 137 var stopAudioVideo = function (el) { 138 var iframe = el.querySelector("iframe[src*=youtube]"); 139 var video = el.querySelector("video"); 140 var audio = el.querySelector("audio"); 141 if (iframe) {
142 var iframeSrc = iframe.src; 143 iframe.src = iframeSrc; 144 } 145 if (video) { 146 video.pause(); 147 } 148 if (audio) { 149 audio.pause(); 150 } 151 }; 152 153 var moreInfoSetup = function (img) { 154 var container = img.parents(".hotspots-container"); 155 156 if (container.data("layout") == "tooltip") { 157 return; 158 } 159 160 if (container.data("layout") == "lightbox") { 161 lightboxSetup(container, img); 162 return; 163 } 164 165 infoboxSetup(container, img); 166 }; 167 168 var infoboxSetup = function (container, img) { 169 var initial = container.find(".hotspot-initial"); 170 var content = container.find(".hotspots-placeholder"); 171 initial.addClass("visible"); 172 container.on("active.responsilight inactive.responsilight", function (e) { 173 var data = $(e.target).data("areaData"); 174 var info; 175 if (e.type === "active") { 176 info = $(data.href); 177 } else { 178 info = initial; 179 } 180 181 var visibleContent = content.children(".visible"); 182 stopAudioVideo(visibleContent.get(0)); 183 visibleContent.removeClass("visible"); 184 info.removeClass("da-hidden").addClass("visible").appendTo(content); 185 186 // Check for an embedded video player 187 var video = info.find(".wp-video"); 188 if (video.length) { 189 if (!info.data("video-resized")) { 190 info.data("video-resized", true); 191 window.dispatchEvent(new Event("resize")); 192 } 193 } 194 }); 195 }; 196 197 var lightboxSetup = function (container, img) { 198 container.on("active.responsilight", function (e) { 199 var data = $(e.target).data("areaData"), 200 info = $(data.href), 201 container = info.parent(), 202 target = $(e.target), 203 currentLightbox = $(".featherlight"); 204 205 if (e.type === "active" && currentLightbox.length === 0) { 206 $.featherlight('<div class="hotspot-info"></div>', { 207 closeLabel: drawattentionData.closeLabel, 208 closeSpeed: 250, 209 closeOnEsc: false, 210 afterContent: function () { 211 var content = $(".featherlight-inner"), 212 lb = $(".featherlight-content"), 213 mapNo = img.data("id"), 214 lightboxContainer = $(".featherlight"); 215 216 info.appendTo(content).show(); 217 lb.addClass("lightbox-" + mapNo); 218 219 // Apply accessibility attributes 220 var hotspotTitle = 221 info.find(".hotspot-title").text() || data.title || ""; 222 lightboxContainer.attr({ 223 tabindex: "-1", 224 role: "dialog", 225 "aria-modal": "true", 226 "aria-label": hotspotTitle, 227 }); 228 229 // Fix accessibility issue - links not focusable by keyboard 230 var untabbables = info.find("a[tabindex=-1]"); 231 untabbables.attr("tabindex", 0); 232 233 setTimeout(function () { 234 var img = content.find("img"), 235 contentHeight = content.get(0).scrollHeight, 236 imgHeight = img.height(), 237 lbHeight = lb.outerHeight(); 238 239 if (contentHeight > lbHeight) { 240 var diff = contentHeight - lbHeight + 50, 241 newHeight = imgHeight - diff, 242 minHeight = $(window).innerHeight() / 2; 243 244 newHeight = newHeight < minHeight ? minHeight : newHeight; 245 246 var naturalHeight = img.prop("naturalHeight"); 247 248 if (newHeight < naturalHeight) { 249 img.css({ width: "auto" }); 250 img.animate( 251 { 252 height: newHeight, 253 }, 254 200, 255 ); 256 } 257 } 258 }, 100); 259 260 lightboxAnchorLinks(content, target); 261 lightboxTrapFocus(); 262 window.dispatchEvent(new Event("resize")); // Trigger window resize event for [video] shortcode JS 263 }, 264 afterOpen: function () { 265 $("body").on("keyup", documentEsc); 266 }, 267 afterClose: function () { 268 target.removeClass("hotspot-active"); 269 $("body").off("keyup", documentEsc); 270 }, 271 beforeClose: function () { 272 stopAudioVideo(document.querySelector(".featherlight-content")); 273 setTimeout(function () { 274 info.hide().appendTo(container); 275 }, 500); // delay hiding content and moving it back outside the lightbox 276 }, 277 }); 278 } 279 }); 280 }; 281 282 var documentEsc = function (e) { 283 if (e.keyCode === 27) { 284 $.featherlight.current().close(); 285 } 286 }; 287 288 var lightboxAnchorLinks = function (content, hotspot) { 289 var links = content.find('.hotspot-content a[href^="#"]'); 290 links.on("click", function (e) { 291 e.preventDefault(); 292 var targetEl = $(e.target.hash); 293 var current = $.featherlight.current(); 294 if (!current) return; 295 current.afterClose = function () { 296 hotspot.removeClass("hotspot-active"); 297 $("html").removeClass("with-featherlight"); 298 $("html, body").animate( 299 { 300 scrollTop: targetEl.offset().top, 301 }, 302 500, 303 ); 304 }; 305 current.close(); 306 }); 307 }; 308 309 var lightboxTrapFocus = function () { 310 var lightbox = $(".featherlight"); 311 var focusableElements = lightbox.find(
312 'a[href], area[href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), [tabindex]:not([tabindex="-1"])', 313 ); 314 315 if (focusableElements.length === 0) { 316 return; 317 } 318 319 var firstFocusable = focusableElements.first(); 320 var lastFocusable = focusableElements.last(); 321 322 // Set initial focus to the lightbox container 323 lightbox.focus(); 324 325 lightbox.on("keydown.focustrap", function (e) { 326 if (e.key !== "Tab" && e.keyCode !== 9) { 327 return; 328 } 329 330 if (e.shiftKey) { 331 if ( 332 document.activeElement === firstFocusable.get(0) || 333 document.activeElement === lightbox.get(0) 334 ) { 335 e.preventDefault(); 336 lastFocusable.focus(); 337 } 338 } else { 339 if (document.activeElement === lastFocusable.get(0)) { 340 e.preventDefault(); 341 firstFocusable.focus(); 342 } 343 } 344 }); 345 346 // Clean up when lightbox closes 347 lightbox.on("closed.featherlight", function () { 348 lightbox.off("keydown.focustrap"); 349 }); 350 }; 351 352 var showTooltip = function (shape, areaData) { 353 var container = $(shape._map._container); 354 var content = $(areaData.href).html(); 355 356 var tip = Leaflet.responsivePopup({ 357 autoPan: false, 358 closeButton: areaData.trigger == "click", 359 hasTip: container.width() > 840, 360 maxHeight: container.height() * 0.9, 361 offset: new Leaflet.Point(0, 0), 362 }); 363 364 tip.setContent(content); 365 shape.bindPopup(tip); 366 367 if (areaData.trigger === "click") { 368 shape.on("click", function (e) { 369 if (shape._path.classList.contains("hotspot-active")) { 370 shape.closePopup(); 371 } else { 372 shape.openPopup(); 373 } 374 }); 375 } else { 376 shape.on("mouseover", function () { 377 shape.openPopup(); 378 }); 379 shape.on("mouseout", function () { 380 shape.closePopup(); 381 }); 382 } 383 384 container.on("click", function (e) { 385 e.stopPropagation(); 386 }); 387 $(document).on("click", function (e) { 388 shape.closePopup(); 389 shape._path.classList.remove("hotspot-active"); 390 }); 391 }; 392 393 var leafletSetup = function (img) { 394 var id = img.data("id"); 395 var container = $( 396 '<div id="hotspots-map-container-' + 397 id + 398 '" class="hotspots-map-container"></div>', 399 ); 400 var imgWidth = img.width(); 401 var imgHeight = img.height(); 402 403 container.css({ 404 width: imgWidth + "px", 405 height: imgHeight + "px", 406 }); 407 img.after(container); 408 409 // Check to be sure the container is on the page 410 // To prevent errors when loaded in Elementor popup 411 var containerTest = $("#hotspots-map-container-" + id); 412 if (!containerTest.length) { 413 return; 414 } 415 416 var map = Leaflet.map("hotspots-map-container-" + id, { 417 attributionControl: false, 418 boxZoom: false, 419 crs: Leaflet.CRS.Simple, 420 doubleClickZoom: false, 421 dragging: false, 422 keyboard: false, 423 minZoom: -20, 424 scrollWheelZoom: false, 425 // tap: !isWebkitiOS, 426 tap: true, 427 touchZoom: false, 428 zoomControl: false, 429 zoomSnap: 0, 430 }); 431 432 var domImg = img.get(0); 433 var natHeight = domImg.naturalHeight; 434 var natWidth = domImg.naturalWidth; 435 img.data("natW", natWidth); 436 img.data("natH", natHeight); 437 var bounds = [ 438 [0, 0], 439 [natHeight, natWidth], 440 ]; 441 var imageAlt = img.attr("alt") || img.data("image-title") || ""; 442 var imageLayer = Leaflet.imageOverlay(img.attr("src"), bounds, { 443 alt: imageAlt, 444 }).addTo(map); 445 map.fitBounds(bounds); 446 447 leaflets.push({ 448 map: map, 449 img: img, 450 }); 451 452 drawSpots(img, map); 453 }; 454 455 var showContextMenu = function (shape, areaData, e) { 456 var hash = areaData.href; 457 var container = $(shape._map._container); 458 459 if (!hash) { 460 return; 461 } 462 463 $(".da-address-wrapper").remove(); 464 465 var windowAddress = window.location.href.split("#")[0]; 466 var shapeAddress = windowAddress + hash; 467 var div = $('<div class="da-address-wrapper"></div>') 468 .css({ 469 left: e.originalEvent.pageX + "px", 470 top: e.originalEvent.pageY + "px", 471 }) 472 .append("<p>" + shapeAddress + "</p>") 473 .append('<span class="da-address-close">×</span>') 474 .appendTo(document.body); 475 476 div.find(".da-address-close").on("click", function () { 477 div.remove(); 478 }); 479 }; 480 481 var drawSpots = function (img, map) { 482 var id = img.data("id"); 483 484 /* If the image has a usemap attribute, detach the map and store it in the imageMaps object */ 485 if (img[0].hasAttribute("usemap")) { 486 var mapName = img.attr("usemap").replace("#", ""); 487 var imageMap = $('map[name="' + mapName + '"]'); 488 imageMaps[id] = imageMap.detach(); 489 img.removeAttr("usemap"); 490 } else { 491 /* Else we've already removed the image map, so we just need to get it */ 492 var imageMap = imageMaps[id]; 493 } 494 495 var areas = imageMap.find("area"); 496 var container = img.parents(".hotspots-container"); 497 498 areas.each(function () { 499 var area = $(this); 500 var shape = area.attr("shape"); 501 var coords = area.attr("coords").split(","); 502 var areaData = {
503 style: area.data("color-scheme") 504 ? area.data("color-scheme") 505 : "default", 506 title: area.attr("title"), 507 href: area.attr("href"), 508 spot: area.data("id"), 509 target: area.attr("target"), 510 action: area.data("action"), 511 layout: container.data("layout"), 512 trigger: container.data("trigger"), 513 }; 514 switch (shape) { 515 case "circle": 516 renderCircle(coords, map, img, areaData); 517 break; 518 case "rect": 519 renderPoly(coords, map, img, areaData); 520 break; 521 case "polygon": 522 renderPoly(coords, map, img, areaData); 523 break; 524 case "poly": // Leaving this here for backward compatibility 525 renderPoly(coords, map, img, areaData); 526 break; 527 } 528 }); 529 // A11y fixes after all the spots are drawn 530 a11yFixes(img, map); 531 532 // Link to area after all the spots are drawn 533 hotspots.linkToArea(); 534 }; 535 536 var renderCircle = function (coords, map, img, areaData) { 537 var x = coords[0]; 538 var y = img.data("natH") - coords[1]; 539 var rad = coords[2]; 540 var circle = Leaflet.circle([y, x], { 541 radius: rad, 542 className: "hotspot-" + areaData.style, 543 title: areaData.title, 544 }); 545 546 circle.on("add", function (e) { 547 var $circle = $(e.target.getElement()); 548 $circle.data("areaData", areaData); 549 $circle.attr("tabindex", "0"); 550 $circle.attr("aria-label", areaData.title); 551 $circle.attr("name", areaData.title); 552 }); 553 554 circle.addTo(map); 555 556 // If this is a more info hotspot, add it to the infoSpots object 557 if (areaData.href.charAt(0) === "#") { 558 var spotName = areaData.href.replace("#", ""); 559 hotspots.infoSpots[spotName] = circle; 560 } 561 562 shapeEvents(circle, areaData); 563 }; 564 565 var renderPoly = function (coords, map, img, areaData) { 566 var xCoords = []; 567 var yCoords = []; 568 for (var i = 0; i < coords.length; i++) { 569 if (i % 2 == 0) { 570 xCoords.push(coords[i]); 571 } else { 572 yCoords.push(coords[i]); 573 } 574 } 575 576 var polyCoords = yCoords.map(function (coord, index) { 577 return [img.data("natH") - coord, xCoords[index]]; 578 }); 579 580 var poly = Leaflet.polygon(polyCoords, { 581 className: "hotspot-" + areaData.style, 582 title: areaData.title, 583 }); 584 585 // Attach the area data to the path as soon as it's added to the map, a11y attributes 586 poly.on("add", function (e) { 587 var $poly = $(e.target.getElement()); 588 $poly.data("areaData", areaData); 589 $poly.attr("tabindex", "0"); 590 $poly.attr("aria-label", areaData.title); 591 $poly.attr("name", areaData.title); 592 }); 593 594 poly.addTo(map); 595 596 // If this is a more info hotspot, add it to the infoSpots object 597 if (areaData.href.charAt(0) === "#") { 598 var spotName = areaData.href.replace("#", ""); 599 hotspots.infoSpots[spotName] = poly; 600 } 601 602 shapeEvents(poly, areaData); 603 }; 604 605 var shapeOver = function (shape, areaData, e) { 606 var $shape = $(e.target.getElement()); 607 $shape.trigger("over.responsilight"); 608 if ( 609 areaData.trigger === "hover" && 610 (e.type !== "touchstart") & (e.type !== "keypress") 611 ) { 612 $shape.addClass("hotspot-active"); 613 $shape.trigger("active.responsilight"); 614 } 615 }; 616 617 var shapeOut = function (shape, areaData, e) { 618 var $shape = $(e.target.getElement()); 619 $shape.trigger("out.responsilight"); 620 if (areaData.trigger === "hover" && e.type !== "keypress") { 621 $shape.removeClass("hotspot-active"); 622 $shape.trigger("inactive.responsilight"); 623 // If mouse user, blur hover spots when mouse moves out 624 if (e.type === "mouseout") { 625 $shape.trigger("blur"); 626 } 627 } 628 }; 629 630 var shapeClick = function (shape, areaData, e) { 631 var $shape = $(e.target.getElement()); 632 $shape.trigger("areaClick.responsilight"); 633 if ( 634 areaData.trigger === "hover" && 635 e.type !== "touchstart" && 636 e.type !== "keypress" && 637 !isMobileSafari 638 ) { 639 return; 640 } 641 $shape.toggleClass("hotspot-active"); 642 if ($shape.hasClass("hotspot-active")) { 643 $shape.trigger("active.responsilight"); 644 } else { 645 $shape.trigger("inactive.responsilight"); 646 } 647 var oldActive = $shape.siblings(".hotspot-active"); 648 if (oldActive.length) { 649 oldActive.removeClass("hotspot-active"); 650 } 651 }; 652 653 /** 654 * Very Custom logic to just handle displaying the popup on focus 655 * Why we had to do it this way: 656 * shape.on('focus') doesn't fire similar to the other events 657 * openPopup() would steal the focus and it's hard to then rely on focusout on shape to remove the popup, cause the focusout would fire right after calling openPopup() 658 * closePopup() would also programmatically control/alter the tab behavior and that is another problem 659 * 660 */ 661 var maybeDisplayPopupOnFocus = function (shape, areaData, nativeEvent) { 662 if (areaData.trigger !== "hover") return; 663 if (areaData.layout !== "tooltip") return; 664 665 var $shape = $(nativeEvent.target); 666 if ($shape.hasClass("hotspot-active")) { 667 return; 668 } 669 670 $shape.addClass("hotspot-active"); 671 $shape.trigger("over.responsilight"); 672 shape.openPopup(); 673 674 setTimeout(() => { 675 const activeElement = document.activeElement; 676 if (!activeElement.classList.contains("leaflet-rrose-content")) { 677 return; 678 }
679 $shape.focus(); 680 681 const closePopupAfterFocusIsLost = (e) => { 682 shape.closePopup(); 683 $shape.removeClass("hotspot-active"); 684 $shape.trigger("out.responsilight"); 685 686 $shape.off("focusout", closePopupAfterFocusIsLost); 687 }; 688 $shape.on("focusout", closePopupAfterFocusIsLost); 689 }, 0); 690 }; 691 692 /** 693 * Left, right, top, bottom & lightbox layout + click trigger 694 * Display Title on focus 695 */ 696 var maybeDisplayTitleOnFocusForLayout = function ( 697 shape, 698 areaData, 699 nativeEvent, 700 ) { 701 if (nativeEvent.type !== "focus") return; 702 if (areaData.trigger !== "click") return; 703 if (!layoutsThatShowTitleOnFocus.includes(areaData.layout)) return; 704 705 const target = nativeEvent.target; 706 target.dispatchEvent(new MouseEvent("mouseover", { bubbles: true })); 707 target.addEventListener("focusout", function handleFocusOut(e) { 708 target.dispatchEvent(new MouseEvent("mouseout", { bubbles: true })); 709 target.removeEventListener("focusout", handleFocusOut); 710 }); 711 }; 712 713 var shapeEvents = function (shape, areaData) { 714 // Handle URL spots 715 if (areaData.action == "url") { 716 if (areaData.title) { 717 shape.bindTooltip(areaData.title); 718 } 719 shape.on("click", function (e) { 720 if (areaData.target == "_new" && !isMobileSafari) { 721 // new window 722 window.open(areaData.href, "_blank"); 723 } else { 724 // same window 725 var first = areaData.href.charAt(0); 726 var targetElem; 727 try { 728 targetElem = first === "#" ? $(areaData.href) : null; 729 } catch (error) { 730 targetElem = null; 731 } 732 if (targetElem && targetElem.length) { 733 // hash link to existing target 734 $("html, body").animate( 735 { 736 scrollTop: targetElem.offset().top - 50, 737 }, 738 750, 739 function () { 740 // callback after scrolling 741 history.pushState({}, "", areaData.href); 742 }, 743 ); 744 } else { 745 window.location = areaData.href; 746 } 747 } 748 }); 749 return; 750 } 751 752 // Show right-click context menu for logged-in admins only 753 if (drawattentionData.isLoggedIn && drawattentionData.isAdmin) { 754 shape.on("contextmenu", function (e) { 755 showContextMenu(shape, areaData, e); 756 }); 757 } 758 759 // Handle tooltip spots 760 if (areaData.layout === "tooltip") { 761 showTooltip(shape, areaData); 762 } 763 764 // Add styled tooltip to all non-hover areas 765 if ( 766 areaData.action === "url" || 767 (areaData.trigger === "click" && areaData.layout !== "tooltip") 768 ) { 769 if (areaData.title) { 770 shape.bindTooltip(areaData.title); 771 } 772 } 773 774 // Handle all other spots 775 var moved = false; 776 777 shape.on( 778 "touchstart touchmove touchend click mouseover mouseout keypress focus blur", 779 function (e) { 780 switch (e.type) { 781 case "touchstart": 782 moved = false; 783 break; 784 case "touchmove": 785 moved = true; 786 break; 787 case "touchend": 788 if (moved) { 789 return; 790 } 791 shapeOver(shape, areaData, e); 792 shapeClick(shape, areaData, e); 793 break; 794 case "click": 795 shapeClick(shape, areaData, e); 796 break; 797 case "keypress": 798 var key = e.originalEvent.which; 799 if (key == 13 || key == 32) { 800 e.originalEvent.preventDefault(); 801 shapeClick(shape, areaData, e); 802 } 803 break; 804 case "mouseover": 805 if (!isMobileSafari || (isMobileSafari && getBrowserVersion < 13)) { 806 shapeOver(shape, areaData, e); 807 } 808 if (isMobileSafari && !(getBrowserVersion() >= 12)) { 809 shapeClick(shape, areaData, e); 810 } 811 break; 812 case "focus": 813 shapeOver(shape, areaData, e); 814 break; 815 case "blur": 816 shapeOut(shape, areaData, e); 817 break; 818 case "mouseout": 819 shapeOut(shape, areaData, e); 820 break; 821 } 822 }, 823 ); 824 825 $(shape._path).on("focus", function (nativeEvent) { 826 maybeDisplayPopupOnFocus(shape, areaData, nativeEvent); 827 maybeDisplayTitleOnFocusForLayout(shape, areaData, nativeEvent); 828 }); 829 }; 830 831 var a11yFixes = function (img, map) { 832 let svg = img 833 .siblings(".leaflet-container") 834 .find(".leaflet-overlay-pane svg"); 835 let id = img.data("id"); 836 837 // Add title and description to SVG 838 svg.prepend( 839 '<desc id="img-desc-' + 840 id + 841 '">' + 842 img.data("image-description") + 843 "</desc>", 844 ); 845 svg.prepend( 846 '<title id="img-title-' + 847 id + 848 '">' + 849 img.data("image-title") + 850 "</title>", 851 ); 852 853 // Use title and desc to describe the svg 854 svg.attr("aria-labelledby", "img-title-" + id); 855 svg.attr("aria-describedby", "img-desc-" + id); 856 857 // Make svg screen reader traversable 858 svg.attr("role", "group"); 859 860 // Create a traversable list
861 var group = svg.find("g").attr("role", "list"); 862 group.children().attr("role", "listitem"); 863 864 // Handle tooltips for the map 865 map.on("popupopen", function (popup) { 866 // shift focus to the popup when it opens 867 $(popup.popup._container) 868 .find(".leaflet-rrose-content") 869 .attr("tabindex", "-1") 870 .focus(); 871 872 // move the close button to the end of the popup content so screen readers reach it 873 // after the main popup content, not before 874 var close = $(popup.popup._container) 875 .find(".leaflet-rrose-close-button") 876 .detach(); 877 close.attr("aria-label", "Close item"); 878 $(popup.popup._container).append(close); 879 880 $(document).on("keydown", function (e) { 881 if (e.which == 27) { 882 map.closePopup(); 883 } 884 }); 885 }); 886 887 // return focus to the icon we started from before opening the pop up 888 map.on("popupclose", function (popup) { 889 $(document).off("keydown"); 890 $(popup.popup._source._path).focus(); 891 }); 892 }; 893 894 hotspots.linkToArea = function () { 895 // Called after the shapes are drawn 896 var hash = window.location.hash; 897 if (!hash) return; 898 899 var spotName = hash.replace("#", ""); 900 if (!hotspots.infoSpots.hasOwnProperty(spotName)) return; 901 902 Object.keys(hotspots.infoSpots).forEach(function (key) { 903 hotspots.infoSpots[key].closeTooltip(); 904 }); 905 906 const spot = hotspots.infoSpots[spotName]; 907 908 if (!spot._path.classList.contains("hotspot-active")) { 909 spot.fire("click"); 910 } 911 912 scrollIntoViewIfNeeded(spot._map?.getContainer()); 913 }; 914 915 hotspots.setup = function () { 916 mapSetup(); 917 }; 918 919 hotspots.resizeTimer = null; 920 hotspots.resizing = false; 921 922 hotspots.init = function () { 923 // For backward compatibility - resets the size of the leaflet on demand 924 leaflets.forEach(function (item) { 925 var isLoaded = item.img.data("status") === "loaded"; 926 927 if (!isLoaded) { 928 return; 929 } 930 931 item.img.next(".hotspots-map-container").css({ 932 width: item.img.width() + "px", 933 height: item.img.height() + "px", 934 }); 935 item.map.invalidateSize(true); 936 item.map.fitBounds([ 937 [0, 0], 938 [item.img.data("natH"), item.img.data("natW")], 939 ]); 940 }); 941 }; 942 943 hotspots.compatibilityFixes = function () { 944 if (window.Foundation) { 945 /* Fix for Foundation firing tag change event indiscriminately when some items are clicked on the page */ 946 $(window).on("change.zf.tabs", function (e) { 947 if (e.target.tagName !== "INPUT") { 948 hotspots.init(); 949 } 950 }); 951 } 952 953 $(window).on("pageloaded load", function () { 954 /* Listen for pageloaded and load events on the window */ 955 hotspots.init(); 956 }); 957 958 $(window).on("et_hashchange", function () { 959 /* Listen for Divi hashchange */ 960 setTimeout(function () { 961 hotspots.init(); 962 }, 1000); 963 }); 964 965 $(".ult_tabs").on("click", ".ult_tab a", function () { 966 /* Ultimate tabs */ 967 setTimeout(function () { 968 hotspots.init(); 969 }, 2000); 970 }); 971 972 $( 973 "a[data-vc-accordion], .et_pb_tabs .et_pb_tabs_controls li, .et_pb_toggle_title", 974 ).on("click", function () { 975 /* Divi tabs, accordion, toggle */ 976 setTimeout(function () { 977 hotspots.init(); 978 }, 1000); 979 }); 980 $(".vc_tta-tabs-container").on("click", ".vc_tta-tab", function () { 981 /* Visual composer tabs */ 982 setTimeout(function () { 983 hotspots.init(); 984 }, 1000); 985 }); 986 987 $(".ui-tabs-anchor, .nav-tabs > li").on("click", function () { 988 /* UI Tabs */ 989 setTimeout(function () { 990 hotspots.init(); 991 }, 750); 992 }); 993 994 $(".fl-accordion-button").on("click", function () { 995 /* Beaver Builder accordion */ 996 setTimeout(function () { 997 hotspots.init(); 998 }, 500); 999 }); 1000 1001 $(".responsive-tabs").on( 1002 "click", 1003 ".responsive-tabs__list__item", 1004 function () { 1005 /* Responsive tabs */ 1006 hotspots.init(); 1007 }, 1008 ); 1009 1010 $(".elementor-tabs").on("click", ".elementor-tab-title", function () { 1011 /* Elementor tabs */ 1012 hotspots.init(); 1013 }); 1014 1015 $(".fl-tabs").on("click", "a.fl-tabs-label", function () { 1016 /* Beaver Builder tabs */ 1017 hotspots.init(); 1018 }); 1019 1020 $(".uabb-adv-accordion-button .uabb-tabs").on("click", function () { 1021 /* Ultimate Beaver Builder addons accordion and tabs */ 1022 setTimeout(function () { 1023 hotspots.init(); 1024 }, 250); 1025 }); 1026 $(".w-tabs-item").on("click", function () { 1027 /* Custom Woocommerce tabs */ 1028 setTimeout(function () { 1029 hotspots.init(); 1030 }, 1000); 1031 }); 1032 }; 1033})(jQuery, (window.hotspots = window.hotspots || {})); 1034 1035jQuery(function () { 1036 hotspots.setup(); 1037 hotspots.compatibilityFixes(); 1038}); 1039 1040jQuery(document).on("elementor/popup/show", function () { 1041 hotspots.setup(); 1042 hotspots.compatibilityFixes(); 1043}); 1044 1045jQuery(window).on("resize orientationchange", function (e) { 1046 var $window = jQuery(this); 1047 if (!hotspots.resizing) { 1048 $window.trigger("resizeStart.responsilight"); 1049 hotspots.resizing = true; 1050 } 1051 clearTimeout(hotspots.resizeTimer); 1052 hotspots.resizeTimer = setTimeout(function () { 1053 hotspots.init(); 1054 $window.trigger("resizeComplete.responsilight"); 1055 hotspots.resizing = false;
1056 }, 250); 1057}); 1058 1059jQuery(window).on("hashchange", function () { 1060 hotspots.linkToArea(); 1061}); 1062 1063window.onerror = function (errorMsg, url, lineNumber) { 1064 // This should be a fun little experiement! 1065 var errorBox = jQuery(".da-error").show(); 1066 if (errorBox.length) { 1067 var contents = errorBox.html(); 1068 errorBox.html( 1069 contents + 1070 "<br/><br/><strong>Error:</strong> " + 1071 errorMsg + 1072 "<br/>Line " + 1073 lineNumber + 1074 ": " + 1075 url, 1076 ); 1077 } 1078 return false; 1079}; 1080 1081/* Fix for Elementor bug - duplicating DA images when popup opens */ 1082jQuery(document).on("elementor/popup/show", () => { 1083 setTimeout(function () { 1084 var imageContainers = jQuery(".hotspots-image-container"); 1085 imageContainers.each(function () { 1086 var extraMapContainers = jQuery(this) 1087 .find(".hotspots-map-container:not(:first)") 1088 .remove(); // find all but the first one and remove them 1089 }); 1090 }, 250); 1091}); 1092 1093function scrollIntoViewIfNeeded(el, options = {}) { 1094 if (!el) return; 1095 const rect = el.getBoundingClientRect(); 1096 1097 const fullyVisible = 1098 rect.top >= 0 && 1099 rect.left >= 0 && 1100 rect.bottom <= 1101 (window.innerHeight || document.documentElement.clientHeight) && 1102 rect.right <= (window.innerWidth || document.documentElement.clientWidth); 1103 1104 if (!fullyVisible) { 1105 el.scrollIntoView(options); 1106 } 1107}
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.