1/******************************************************************************* 2 * Copyright 2019 Adobe 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 ******************************************************************************/ 16 17/** 18 * Element.matches() 19 * https://developer.mozilla.org/enUS/docs/Web/API/Element/matches#Polyfill 20 */ 21if (!Element.prototype.matches) { 22 Element.prototype.matches = Element.prototype.msMatchesSelector || Element.prototype.webkitMatchesSelector; 23} 24 25// eslint-disable-next-line valid-jsdoc 26/** 27 * Element.closest() 28 * https://developer.mozilla.org/enUS/docs/Web/API/Element/closest#Polyfill 29 */ 30if (!Element.prototype.closest) { 31 Element.prototype.closest = function(s) { 32 "use strict"; 33 var el = this; 34 if (!document.documentElement.contains(el)) { 35 return null; 36 } 37 do { 38 if (el.matches(s)) { 39 return el; 40 } 41 el = el.parentElement || el.parentNode; 42 } while (el !== null && el.nodeType === 1); 43 return null; 44 }; 45} 46 47/******************************************************************************* 48 * Copyright 2019 Adobe 49 * 50 * Licensed under the Apache License, Version 2.0 (the "License"); 51 * you may not use this file except in compliance with the License. 52 * You may obtain a copy of the License at 53 * 54 * http://www.apache.org/licenses/LICENSE-2.0 55 * 56 * Unless required by applicable law or agreed to in writing, software 57 * distributed under the License is distributed on an "AS IS" BASIS, 58 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 59 * See the License for the specific language governing permissions and 60 * limitations under the License. 61 ******************************************************************************/ 62(function() { 63 "use strict"; 64 65 var containerUtils = window.CQ && window.CQ.CoreComponents && window.CQ.CoreComponents.container && window.CQ.CoreComponents.container.utils ? window.CQ.CoreComponents.container.utils : undefined; 66 if (!containerUtils) { 67 // eslint-disable-next-line no-console 68 console.warn("Accordion: container utilities at window.CQ.CoreComponents.container.utils are not available. This can lead to missing features. Ensure the core.wcm.components.commons.site.container client library is included on the page."); 69 } 70 var dataLayerEnabled; 71 var dataLayer; 72 var dataLayerName; 73 var delay = 100; 74 75 var NS = "cmp"; 76 var IS = "accordion"; 77 78 var keyCodes = { 79 ENTER: 13, 80 SPACE: 32, 81 END: 35, 82 HOME: 36, 83 ARROW_LEFT: 37, 84 ARROW_UP: 38, 85 ARROW_RIGHT: 39, 86 ARROW_DOWN: 40 87 }; 88 89 var selectors = { 90 self: "[data-" + NS + '-is="' + IS + '"]' 91 }; 92
93 var cssClasses = { 94 button: { 95 disabled: "cmp-accordion__button--disabled", 96 expanded: "cmp-accordion__button--expanded" 97 }, 98 panel: { 99 hidden: "cmp-accordion__panel--hidden", 100 expanded: "cmp-accordion__panel--expanded" 101 } 102 }; 103 104 var dataAttributes = { 105 item: { 106 expanded: "data-cmp-expanded" 107 } 108 }; 109 110 var properties = { 111 /** 112 * Determines whether a single accordion item is forced to be expanded at a time. 113 * Expanding one item will collapse all others. 114 * 115 * @memberof Accordion 116 * @type {Boolean} 117 * @default false 118 */ 119 "singleExpansion": { 120 "default": false, 121 "transform": function(value) { 122 return !(value === null || typeof value === "undefined"); 123 } 124 } 125 }; 126 127 /** 128 * Accordion Configuration. 129 * 130 * @typedef {Object} AccordionConfig Represents an Accordion configuration 131 * @property {HTMLElement} element The HTMLElement representing the Accordion 132 * @property {Object} options The Accordion options 133 */ 134 135 /** 136 * Accordion. 137 * 138 * @class Accordion 139 * @classdesc An interactive Accordion component for toggling panels of related content 140 * @param {AccordionConfig} config The Accordion configuration 141 */ 142 function Accordion(config) { 143 var that = this; 144 145 if (config && config.element) { 146 init(config); 147 } 148 149 /** 150 * Initializes the Accordion. 151 * 152 * @private 153 * @param {AccordionConfig} config The Accordion configuration 154 */ 155 function init(config) { 156 that._config = config; 157 158 // prevents multiple initialization 159 config.element.removeAttribute("data-" + NS + "-is"); 160 161 setupProperties(config.options); 162 cacheElements(config.element); 163 164 if (that._elements["item"]) { 165 // ensures multiple element types are arrays. 166 that._elements["item"] = Array.isArray(that._elements["item"]) ? that._elements["item"] : [that._elements["item"]]; 167 that._elements["button"] = Array.isArray(that._elements["button"]) ? that._elements["button"] : [that._elements["button"]]; 168 that._elements["panel"] = Array.isArray(that._elements["panel"]) ? that._elements["panel"] : [that._elements["panel"]]; 169 170 if (that._properties.singleExpansion) { 171 var expandedItems = getExpandedItems(); 172 // multiple expanded items annotated, display the last item open. 173 if (expandedItems.length > 1) { 174 toggle(expandedItems.length - 1); 175 } 176 } 177 178 refreshItems(); 179 bindEvents(); 180 scrollToDeepLinkIdInAccordion(); 181 } 182 if (window.Granite && window.Granite.author && window.Granite.author.MessageChannel) { 183 /* 184 * Editor message handling: 185 * - subscribe to "cmp.panelcontainer" message requests sent by the editor frame 186 * - check that the message data panel container type is correct and that the id (path) matches this specific Accordion component 187 * - if so, route the "navigate" operation to enact a navigation of the Accordion based on index data 188 */ 189 window.CQ.CoreComponents.MESSAGE_CHANNEL = window.CQ.CoreComponents.MESSAGE_CHANNEL || new window.Granite.author.MessageChannel("cqauthor", window); 190 window.CQ.CoreComponents.MESSAGE_CHANNEL.subscribeRequestMessage("cmp.panelcontainer", function(message) { 191 if (message.data && message.data.type === "cmp-accordion" && message.data.id === that._elements.self.dataset["cmpPanelcontainerId"]) { 192 if (message.data.operation === "navigate") { 193 // switch to single expansion mode when navigating in edit mode. 194 var singleExpansion = that._properties.singleExpansion; 195 that._properties.singleExpansion = true; 196 toggle(message.data.index); 197 198 // revert to the configured state. 199 that._properties.singleExpansion = singleExpansion; 200 } 201 } 202 }); 203 } 204 } 205 206 /**
207 * Displays the panel containing the element that corresponds to the deep link in the URI fragment 208 * and scrolls the browser to this element. 209 */ 210 function scrollToDeepLinkIdInAccordion() { 211 if (containerUtils) { 212 var deepLinkItemIdx = containerUtils.getDeepLinkItemIdx(that, "item", "item"); 213 if (deepLinkItemIdx > -1) { 214 var deepLinkItem = that._elements["item"][deepLinkItemIdx]; 215 if (deepLinkItem && !deepLinkItem.hasAttribute(dataAttributes.item.expanded)) { 216 // if single expansion: close all accordion items 217 if (that._properties.singleExpansion) { 218 for (var j = 0; j < that._elements["item"].length; j++) { 219 if (that._elements["item"][j].hasAttribute(dataAttributes.item.expanded)) { 220 setItemExpanded(that._elements["item"][j], false, true); 221 } 222 } 223 } 224 // expand the accordion item containing the deep link 225 setItemExpanded(deepLinkItem, true, true); 226 } 227 var hashId = window.location.hash.substring(1); 228 if (hashId) { 229 var hashItem = document.querySelector("[id='" + hashId + "']"); 230 if (hashItem) { 231 hashItem.scrollIntoView(); 232 } 233 } 234 } 235 } 236 } 237 238 /** 239 * Caches the Accordion elements as defined via the {@code data-accordion-hook="ELEMENT_NAME"} markup API. 240 * 241 * @private 242 * @param {HTMLElement} wrapper The Accordion wrapper element 243 */ 244 function cacheElements(wrapper) { 245 that._elements = {}; 246 that._elements.self = wrapper; 247 var hooks = that._elements.self.querySelectorAll("[data-" + NS + "-hook-" + IS + "]"); 248 249 for (var i = 0; i < hooks.length; i++) { 250 var hook = hooks[i]; 251 if (hook.closest("." + NS + "-" + IS) === that._elements.self) { // only process own accordion elements 252 var capitalized = IS; 253 capitalized = capitalized.charAt(0).toUpperCase() + capitalized.slice(1); 254 var key = hook.dataset[NS + "Hook" + capitalized]; 255 if (that._elements[key]) { 256 if (!Array.isArray(that._elements[key])) { 257 var tmp = that._elements[key]; 258 that._elements[key] = [tmp]; 259 } 260 that._elements[key].push(hook); 261 } else { 262 that._elements[key] = hook; 263 } 264 } 265 } 266 } 267 268 /** 269 * Sets up properties for the Accordion based on the passed options. 270 * 271 * @private 272 * @param {Object} options The Accordion options 273 */ 274 function setupProperties(options) { 275 that._properties = {}; 276 277 for (var key in properties) { 278 if (Object.prototype.hasOwnProperty.call(properties, key)) { 279 var property = properties[key]; 280 var value = null; 281 282 if (options && options[key] != null) { 283 value = options[key]; 284 285 // transform the provided option 286 if (property && typeof property.transform === "function") { 287 value = property.transform(value); 288 } 289 } 290 291 if (value === null) { 292 // value still null, take the property default 293 value = properties[key]["default"]; 294 } 295 296 that._properties[key] = value; 297 } 298 } 299 } 300 301 /** 302 * Binds Accordion event handling. 303 * 304 * @private 305 */ 306 function bindEvents() { 307 window.addEventListener("hashchange", scrollToDeepLinkIdInAccordion, false); 308 var buttons = that._elements["button"]; 309 if (buttons) { 310 for (var i = 0; i < buttons.length; i++) { 311 (function(index) { 312 buttons[i].addEventListener("click", function(event) { 313 toggle(index); 314 focusButton(index); 315 }); 316 buttons[i].addEventListener("keydown", function(event) { 317 onButtonKeyDown(event, index); 318 }); 319 })(i); 320 } 321 } 322 } 323 324 /** 325 * Handles button keydown events. 326 * 327 * @private 328 * @param {Object} event The keydown event 329 * @param {Number} index The index of the button triggering the event 330 */ 331 function onButtonKeyDown(event, index) { 332 var lastIndex = that._elements["button"].length - 1; 333 334 switch (event.keyCode) { 335 case keyCodes.ARROW_LEFT: 336 case keyCodes.ARROW_UP: 337 event.preventDefault(); 338 if (index > 0) { 339 focusButton(index - 1); 340 } 341 break; 342 case keyCodes.ARROW_RIGHT: 343 case keyCodes.ARROW_DOWN: 344 event.preventDefault(); 345 if (index < lastIndex) { 346 focusButton(index + 1); 347 } 348 break; 349 case keyCodes.HOME: 350 event.preventDefault(); 351 focusButton(0); 352 break; 353 case keyCodes.END: 354 event.preventDefault(); 355 focusButton(lastIndex); 356 break;
357 case keyCodes.ENTER: 358 case keyCodes.SPACE: 359 event.preventDefault(); 360 toggle(index); 361 focusButton(index); 362 break; 363 default: 364 return; 365 } 366 } 367 368 /** 369 * General handler for toggle of an item. 370 * 371 * @private 372 * @param {Number} index The index of the item to toggle 373 */ 374 function toggle(index) { 375 var item = that._elements["item"][index]; 376 if (item) { 377 if (that._properties.singleExpansion) { 378 // ensure only a single item is expanded if single expansion is enabled. 379 for (var i = 0; i < that._elements["item"].length; i++) { 380 if (that._elements["item"][i] !== item) { 381 var expanded = getItemExpanded(that._elements["item"][i]); 382 if (expanded) { 383 setItemExpanded(that._elements["item"][i], false); 384 } 385 } 386 } 387 } 388 setItemExpanded(item, !getItemExpanded(item)); 389 390 if (dataLayerEnabled) { 391 var accordionId = that._elements.self.id; 392 var expandedItems = getExpandedItems() 393 .map(function(item) { 394 return getDataLayerId(item); 395 }); 396 397 var uploadPayload = { component: {} }; 398 uploadPayload.component[accordionId] = { shownItems: expandedItems }; 399 400 var removePayload = { component: {} }; 401 removePayload.component[accordionId] = { shownItems: undefined }; 402 403 dataLayer.push(removePayload); 404 dataLayer.push(uploadPayload); 405 } 406 } 407 } 408 409 /** 410 * Sets an item's expanded state based on the provided flag and refreshes its internals. 411 * 412 * @private 413 * @param {HTMLElement} item The item to mark as expanded, or not expanded 414 * @param {Boolean} expanded true to mark the item expanded, false otherwise 415 * @param {Boolean} keepHash true to keep the hash in the URL, false to update it 416 */ 417 function setItemExpanded(item, expanded, keepHash) { 418 if (expanded) { 419 item.setAttribute(dataAttributes.item.expanded, ""); 420 var index = that._elements["item"].indexOf(item); 421 if (!keepHash && containerUtils) { 422 containerUtils.updateUrlHash(that, "item", index); 423 } 424 if (dataLayerEnabled) { 425 dataLayer.push({ 426 event: "cmp:show", 427 eventInfo: { 428 path: "component." + getDataLayerId(item) 429 } 430 }); 431 } 432 433 } else { 434 item.removeAttribute(dataAttributes.item.expanded); 435 if (!keepHash && containerUtils) { 436 containerUtils.removeUrlHash(); 437 } 438 if (dataLayerEnabled) { 439 dataLayer.push({ 440 event: "cmp:hide", 441 eventInfo: { 442 path: "component." + getDataLayerId(item) 443 } 444 }); 445 } 446 } 447 refreshItem(item); 448 } 449 450 /** 451 * Gets an item's expanded state. 452 * 453 * @private 454 * @param {HTMLElement} item The item for checking its expanded state 455 * @returns {Boolean} true if the item is expanded, false otherwise 456 */ 457 function getItemExpanded(item) { 458 return item && item.dataset && item.dataset["cmpExpanded"] !== undefined; 459 } 460 461 /** 462 * Refreshes an item based on its expanded state. 463 * 464 * @private 465 * @param {HTMLElement} item The item to refresh 466 */ 467 function refreshItem(item) { 468 var expanded = getItemExpanded(item); 469 if (expanded) { 470 expandItem(item); 471 } else { 472 collapseItem(item); 473 } 474 } 475 476 /** 477 * Refreshes all items based on their expanded state. 478 * 479 * @private 480 */ 481 function refreshItems() { 482 for (var i = 0; i < that._elements["item"].length; i++) { 483 refreshItem(that._elements["item"][i]); 484 } 485 } 486 487 /** 488 * Returns all expanded items. 489 * 490 * @private 491 * @returns {HTMLElement[]} The expanded items 492 */ 493 function getExpandedItems() { 494 var expandedItems = []; 495 496 for (var i = 0; i < that._elements["item"].length; i++) { 497 var item = that._elements["item"][i]; 498 var expanded = getItemExpanded(item); 499 if (expanded) { 500 expandedItems.push(item); 501 } 502 } 503 504 return expandedItems; 505 } 506 507 /** 508 * Annotates the item and its internals with 509 * the necessary style and accessibility attributes to indicate it is expanded. 510 * 511 * @private 512 * @param {HTMLElement} item The item to annotate as expanded 513 */ 514 function expandItem(item) { 515 var index = that._elements["item"].indexOf(item); 516 if (index > -1) { 517 var button = that._elements["button"][index]; 518 var panel = that._elements["panel"][index];
519 button.classList.add(cssClasses.button.expanded); 520 // used to fix some known screen readers issues in reading the correct state of the 'aria-expanded' attribute 521 // e.g. https://bugs.webkit.org/show_bug.cgi?id=210934 522 setTimeout(function() { 523 button.setAttribute("aria-expanded", true); 524 }, delay); 525 panel.classList.add(cssClasses.panel.expanded); 526 panel.classList.remove(cssClasses.panel.hidden); 527 panel.setAttribute("aria-hidden", false); 528 } 529 } 530 531 /** 532 * Annotates the item and its internals with 533 * the necessary style and accessibility attributes to indicate it is not expanded. 534 * 535 * @private 536 * @param {HTMLElement} item The item to annotate as not expanded 537 */ 538 function collapseItem(item) { 539 var index = that._elements["item"].indexOf(item); 540 if (index > -1) { 541 var button = that._elements["button"][index]; 542 var panel = that._elements["panel"][index]; 543 button.classList.remove(cssClasses.button.expanded); 544 // used to fix some known screen readers issues in reading the correct state of the 'aria-expanded' attribute 545 // e.g. https://bugs.webkit.org/show_bug.cgi?id=210934 546 setTimeout(function() { 547 button.setAttribute("aria-expanded", false); 548 }, delay); 549 panel.classList.add(cssClasses.panel.hidden); 550 panel.classList.remove(cssClasses.panel.expanded); 551 panel.setAttribute("aria-hidden", true); 552 } 553 } 554 555 /** 556 * Focuses the button at the provided index. 557 * 558 * @private 559 * @param {Number} index The index of the button to focus 560 */ 561 function focusButton(index) { 562 var button = that._elements["button"][index]; 563 button.focus(); 564 } 565 } 566 567 /** 568 * Reads options data from the Accordion wrapper element, defined via {@code data-cmp-*} data attributes. 569 * 570 * @private 571 * @param {HTMLElement} element The Accordion element to read options data from 572 * @returns {Object} The options read from the component data attributes 573 */ 574 function readData(element) { 575 var data = element.dataset; 576 var options = []; 577 var capitalized = IS; 578 capitalized = capitalized.charAt(0).toUpperCase() + capitalized.slice(1); 579 var reserved = ["is", "hook" + capitalized]; 580 581 for (var key in data) { 582 if (Object.prototype.hasOwnProperty.call(data, key)) { 583 var value = data[key]; 584 585 if (key.indexOf(NS) === 0) { 586 key = key.slice(NS.length); 587 key = key.charAt(0).toLowerCase() + key.substring(1); 588 589 if (reserved.indexOf(key) === -1) { 590 options[key] = value; 591 } 592 } 593 } 594 } 595 596 return options; 597 } 598 599 /** 600 * Parses the dataLayer string and returns the ID 601 * 602 * @private 603 * @param {HTMLElement} item the accordion item 604 * @returns {String} dataLayerId or undefined 605 */ 606 function getDataLayerId(item) { 607 if (item) { 608 if (item.dataset.cmpDataLayer) { 609 return Object.keys(JSON.parse(item.dataset.cmpDataLayer))[0]; 610 } else { 611 return item.id; 612 } 613 } 614 return null; 615 } 616 617 /** 618 * Document ready handler and DOM mutation observers. Initializes Accordion components as necessary. 619 * 620 * @private 621 */ 622 function onDocumentReady() { 623 dataLayerEnabled = document.body.hasAttribute("data-cmp-data-layer-enabled"); 624 if (dataLayerEnabled) { 625 dataLayerName = document.body.getAttribute("data-cmp-data-layer-name") || "adobeDataLayer"; 626 dataLayer = window[dataLayerName] = window[dataLayerName] || []; 627 } 628 629 var elements = document.querySelectorAll(selectors.self); 630 for (var i = 0; i < elements.length; i++) { 631 new Accordion({ element: elements[i], options: readData(elements[i]) }); 632 } 633 634 var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver; 635 var body = document.querySelector("body"); 636 var observer = new MutationObserver(function(mutations) { 637 mutations.forEach(function(mutation) { 638 // needed for IE 639 var nodesArray = [].slice.call(mutation.addedNodes); 640 if (nodesArray.length > 0) { 641 nodesArray.forEach(function(addedNode) { 642 if (addedNode.querySelectorAll) { 643 var elementsArray = [].slice.call(addedNode.querySelectorAll(selectors.self)); 644 elementsArray.forEach(function(element) { 645 new Accordion({ element: element, options: readData(element) }); 646 }); 647 } 648 }); 649 } 650 }); 651 }); 652 653 observer.observe(body, { 654 subtree: true, 655 childList: true, 656 characterData: true 657 }); 658 } 659 660 if (document.readyState !== "loading") { 661 onDocumentReady(); 662 } else { 663 document.addEventListener("DOMContentLoaded", onDocumentReady); 664 } 665 666 if (containerUtils) { 667 window.addEventListener("load", containerUtils.scrollToAnchor, false); 668 } 669 670}()); 671 672 673/******************************************************************************* 674 * Copyright 2018 Adobe 675 * 676 * Licensed under the Apache License, Version 2.0 (the "License");
677 * you may not use this file except in compliance with the License. 678 * You may obtain a copy of the License at 679 * 680 * http://www.apache.org/licenses/LICENSE2.0 681 * 682 * Unless required by applicable law or agreed to in writing, software 683 * distributed under the License is distributed on an "AS IS" BASIS, 684 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 685 * See the License for the specific language governing permissions and 686 * limitations under the License. 687 ******************************************************************************/ 688 689/** 690 * Element.matches() 691 * https://developer.mozilla.org/enUS/docs/Web/API/Element/matches#Polyfill 692 */ 693if (!Element.prototype.matches) { 694 Element.prototype.matches = Element.prototype.msMatchesSelector || Element.prototype.webkitMatchesSelector; 695} 696 697// eslint-disable-next-line valid-jsdoc 698/** 699 * Element.closest() 700 * https://developer.mozilla.org/enUS/docs/Web/API/Element/closest#Polyfill 701 */ 702if (!Element.prototype.closest) { 703 Element.prototype.closest = function(s) { 704 "use strict"; 705 var el = this; 706 if (!document.documentElement.contains(el)) { 707 return null; 708 } 709 do { 710 if (el.matches(s)) { 711 return el; 712 } 713 el = el.parentElement || el.parentNode; 714 } while (el !== null && el.nodeType === 1); 715 return null; 716 }; 717} 718 719/******************************************************************************* 720 * Copyright 2018 Adobe 721 * 722 * Licensed under the Apache License, Version 2.0 (the "License"); 723 * you may not use this file except in compliance with the License. 724 * You may obtain a copy of the License at 725 * 726 * http://www.apache.org/licenses/LICENSE-2.0 727 * 728 * Unless required by applicable law or agreed to in writing, software 729 * distributed under the License is distributed on an "AS IS" BASIS, 730 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 731 * See the License for the specific language governing permissions and 732 * limitations under the License. 733 ******************************************************************************/ 734/* global 735 CQ 736 */ 737(function() { 738 "use strict"; 739 740 var containerUtils = window.CQ && window.CQ.CoreComponents && window.CQ.CoreComponents.container && window.CQ.CoreComponents.container.utils ? window.CQ.CoreComponents.container.utils : undefined; 741 if (!containerUtils) { 742 // eslint-disable-next-line no-console 743 console.warn("Tabs: container utilities at window.CQ.CoreComponents.container.utils are not available. This can lead to missing features. Ensure the core.wcm.components.commons.site.container client library is included on the page."); 744 } 745 var dataLayerEnabled; 746 var dataLayer; 747 var dataLayerName; 748 749 var NS = "cmp"; 750 var IS = "tabs"; 751 752 var keyCodes = { 753 END: 35, 754 HOME: 36, 755 ARROW_LEFT: 37, 756 ARROW_UP: 38, 757 ARROW_RIGHT: 39, 758 ARROW_DOWN: 40 759 }; 760 761 var selectors = { 762 self: "[data-" + NS + '-is="' + IS + '"]', 763 active: { 764 tab: "cmp-tabs__tab--active", 765 tabpanel: "cmp-tabs__tabpanel--active" 766 } 767 }; 768 769 /** 770 * Tabs Configuration 771 * 772 * @typedef {Object} TabsConfig Represents a Tabs configuration 773 * @property {HTMLElement} element The HTMLElement representing the Tabs 774 * @property {Object} options The Tabs options 775 */ 776 777 /** 778 * Tabs 779 * 780 * @class Tabs 781 * @classdesc An interactive Tabs component for navigating a list of tabs 782 * @param {TabsConfig} config The Tabs configuration 783 */ 784 function Tabs(config) { 785 var that = this; 786 787 if (config && config.element) { 788 init(config); 789 } 790 791 /** 792 * Initializes the Tabs 793 * 794 * @private 795 * @param {TabsConfig} config The Tabs configuration 796 */ 797 function init(config) { 798 that._config = config; 799 800 // prevents multiple initialization 801 config.element.removeAttribute("data-" + NS + "-is"); 802 803 cacheElements(config.element); 804 that._active = getActiveIndex(that._elements["tab"]); 805 806 if (that._elements.tabpanel) { 807 refreshActive(); 808 bindEvents(); 809 scrollToDeepLinkIdInTabs(); 810 } 811 812 if (window.Granite && window.Granite.author && window.Granite.author.MessageChannel) { 813 /* 814 * Editor message handling: 815 * - subscribe to "cmp.panelcontainer" message requests sent by the editor frame
816 * - check that the message data panel container type is correct and that the id (path) matches this specific Tabs component 817 * - if so, route the "navigate" operation to enact a navigation of the Tabs based on index data 818 */ 819 CQ.CoreComponents.MESSAGE_CHANNEL = CQ.CoreComponents.MESSAGE_CHANNEL || new window.Granite.author.MessageChannel("cqauthor", window); 820 CQ.CoreComponents.MESSAGE_CHANNEL.subscribeRequestMessage("cmp.panelcontainer", function(message) { 821 if (message.data && message.data.type === "cmp-tabs" && message.data.id === that._elements.self.dataset["cmpPanelcontainerId"]) { 822 if (message.data.operation === "navigate") { 823 navigate(message.data.index); 824 } 825 } 826 }); 827 } 828 } 829 830 /** 831 * Displays the panel containing the element that corresponds to the deep link in the URI fragment 832 * and scrolls the browser to this element. 833 */ 834 function scrollToDeepLinkIdInTabs() { 835 if (containerUtils) { 836 var deepLinkItemIdx = containerUtils.getDeepLinkItemIdx(that, "tab", "tabpanel"); 837 if (deepLinkItemIdx > -1) { 838 var deepLinkItem = that._elements["tab"][deepLinkItemIdx]; 839 if (deepLinkItem && that._elements["tab"][that._active].id !== deepLinkItem.id) { 840 navigateAndFocusTab(deepLinkItemIdx, true); 841 } 842 var hashId = window.location.hash.substring(1); 843 if (hashId) { 844 var hashItem = document.querySelector("[id='" + hashId + "']"); 845 if (hashItem) { 846 hashItem.scrollIntoView(); 847 } 848 } 849 } 850 } 851 } 852 853 /** 854 * Returns the index of the active tab, if no tab is active returns 0 855 * 856 * @param {Array} tabs Tab elements 857 * @returns {Number} Index of the active tab, 0 if none is active 858 */ 859 function getActiveIndex(tabs) { 860 if (tabs) { 861 for (var i = 0; i < tabs.length; i++) { 862 if (tabs[i].classList.contains(selectors.active.tab)) { 863 return i; 864 } 865 } 866 } 867 return 0; 868 } 869 870 /** 871 * Caches the Tabs elements as defined via the {@code data-tabs-hook="ELEMENT_NAME"} markup API 872 * 873 * @private 874 * @param {HTMLElement} wrapper The Tabs wrapper element 875 */ 876 function cacheElements(wrapper) { 877 that._elements = {}; 878 that._elements.self = wrapper; 879 var hooks = that._elements.self.querySelectorAll("[data-" + NS + "-hook-" + IS + "]"); 880 881 for (var i = 0; i < hooks.length; i++) { 882 var hook = hooks[i]; 883 if (hook.closest("." + NS + "-" + IS) === that._elements.self) { // only process own tab elements 884 var capitalized = IS; 885 capitalized = capitalized.charAt(0).toUpperCase() + capitalized.slice(1); 886 var key = hook.dataset[NS + "Hook" + capitalized]; 887 if (that._elements[key]) { 888 if (!Array.isArray(that._elements[key])) { 889 var tmp = that._elements[key]; 890 that._elements[key] = [tmp]; 891 } 892 that._elements[key].push(hook); 893 } else { 894 that._elements[key] = hook; 895 } 896 } 897 } 898 } 899 900 /** 901 * Binds Tabs event handling 902 * 903 * @private 904 */ 905 function bindEvents() { 906 window.addEventListener("hashchange", scrollToDeepLinkIdInTabs, false); 907 var tabs = that._elements["tab"]; 908 if (tabs) { 909 for (var i = 0; i < tabs.length; i++) { 910 (function(index) { 911 tabs[i].addEventListener("click", function(event) { 912 navigateAndFocusTab(index); 913 }); 914 tabs[i].addEventListener("keydown", function(event) { 915 onKeyDown(event); 916 }); 917 })(i); 918 } 919 } 920 } 921 922 /** 923 * Handles tab keydown events 924 * 925 * @private 926 * @param {Object} event The keydown event 927 */ 928 function onKeyDown(event) { 929 var index = that._active; 930 var lastIndex = that._elements["tab"].length - 1; 931 932 switch (event.keyCode) { 933 case keyCodes.ARROW_LEFT: 934 case keyCodes.ARROW_UP: 935 event.preventDefault(); 936 if (index > 0) { 937 navigateAndFocusTab(index - 1); 938 } 939 break; 940 case keyCodes.ARROW_RIGHT: 941 case keyCodes.ARROW_DOWN: 942 event.preventDefault(); 943 if (index < lastIndex) { 944 navigateAndFocusTab(index + 1); 945 } 946 break; 947 case keyCodes.HOME: 948 event.preventDefault(); 949 navigateAndFocusTab(0); 950 break; 951 case keyCodes.END: 952 event.preventDefault(); 953 navigateAndFocusTab(lastIndex); 954 break; 955 default: 956 return; 957 } 958 } 959 960 /** 961 * Refreshes the tab markup based on the current {@code Tabs#_active} index 962 * 963 * @private 964 */ 965 function refreshActive() { 966 var tabpanels = that._elements["tabpanel"]; 967 var tabs = that._elements["tab"]; 968 969 if (tabpanels) { 970 if (Array.isArray(tabpanels)) { 971 for (var i = 0; i < tabpanels.length; i++) { 972 if (i === parseInt(that._active)) { 973 tabpanels[i].classList.add(selectors.active.tabpanel); 974 tabpanels[i].removeAttribute("aria-hidden"); 975 tabs[i].classList.add(selectors.active.tab); 976 tabs[i].setAttribute("aria-selected", true); 977 tabs[i].setAttribute("tabindex", "0"); 978 } else { 979 tabpanels[i].classList.remove(selectors.active.tabpanel); 980 tabpanels[i].setAttribute("aria-hidden", true); 981 tabs[i].classList.remove(selectors.active.tab); 982 tabs[i].setAttribute("aria-selected", false); 983 tabs[i].setAttribute("tabindex", "-1"); 984 } 985 } 986 } else { 987 // only one tab 988 tabpanels.classList.add(selectors.active.tabpanel); 989 tabs.classList.add(selectors.active.tab); 990 } 991 } 992 } 993 994 /** 995 * Focuses the element and prevents scrolling the element into view 996 * 997 * @param {HTMLElement} element Element to focus 998 */ 999 function focusWithoutScroll(element) { 1000 var x = window.scrollX || window.pageXOffset; 1001 var y = window.scrollY || window.pageYOffset; 1002 element.focus(); 1003 window.scrollTo(x, y); 1004 } 1005 1006 /** 1007 * Navigates to the tab at the provided index 1008 * 1009 * @private 1010 * @param {Number} index The index of the tab to navigate to 1011 */ 1012 function navigate(index) { 1013 that._active = index; 1014 refreshActive(); 1015 } 1016 1017 /** 1018 * Navigates to the item at the provided index and ensures the active tab gains focus 1019 * 1020 * @private 1021 * @param {Number} index The index of the item to navigate to 1022 * @param {Boolean} keepHash true to keep the hash in the URL, false to update it 1023 */ 1024 function navigateAndFocusTab(index, keepHash) { 1025 var exActive = that._active; 1026 if (!keepHash && containerUtils) { 1027 containerUtils.updateUrlHash(that, "tab", index); 1028 } 1029 navigate(index); 1030 focusWithoutScroll(that._elements["tab"][index]); 1031 1032 if (dataLayerEnabled) { 1033 1034 var activeItem = getDataLayerId(that._elements.tabpanel[index]); 1035 var exActiveItem = getDataLayerId(that._elements.tabpanel[exActive]); 1036 1037 dataLayer.push({ 1038 event: "cmp:show", 1039 eventInfo: { 1040 path: "component." + activeItem 1041 } 1042 }); 1043 1044 dataLayer.push({ 1045 event: "cmp:hide", 1046 eventInfo: { 1047 path: "component." + exActiveItem 1048 } 1049 }); 1050 1051 var tabsId = that._elements.self.id; 1052 var uploadPayload = { component: {} }; 1053 uploadPayload.component[tabsId] = { shownItems: [activeItem] }; 1054 1055 var removePayload = { component: {} }; 1056 removePayload.component[tabsId] = { shownItems: undefined }; 1057 1058 dataLayer.push(removePayload); 1059 dataLayer.push(uploadPayload); 1060 } 1061 } 1062 } 1063 1064 /**
1065 * Reads options data from the Tabs wrapper element, defined via {@code data-cmp-*} data attributes 1066 * 1067 * @private 1068 * @param {HTMLElement} element The Tabs element to read options data from 1069 * @returns {Object} The options read from the component data attributes 1070 */ 1071 function readData(element) { 1072 var data = element.dataset; 1073 var options = []; 1074 var capitalized = IS; 1075 capitalized = capitalized.charAt(0).toUpperCase() + capitalized.slice(1); 1076 var reserved = ["is", "hook" + capitalized]; 1077 1078 for (var key in data) { 1079 if (Object.prototype.hasOwnProperty.call(data, key)) { 1080 var value = data[key]; 1081 1082 if (key.indexOf(NS) === 0) { 1083 key = key.slice(NS.length); 1084 key = key.charAt(0).toLowerCase() + key.substring(1); 1085 1086 if (reserved.indexOf(key) === -1) { 1087 options[key] = value; 1088 } 1089 } 1090 } 1091 } 1092 1093 return options; 1094 } 1095 1096 /** 1097 * Parses the dataLayer string and returns the ID 1098 * 1099 * @private 1100 * @param {HTMLElement} item the accordion item 1101 * @returns {String} dataLayerId or undefined 1102 */ 1103 function getDataLayerId(item) { 1104 if (item) { 1105 if (item.dataset.cmpDataLayer) { 1106 return Object.keys(JSON.parse(item.dataset.cmpDataLayer))[0]; 1107 } else { 1108 return item.id; 1109 } 1110 } 1111 return null; 1112 } 1113 1114 /** 1115 * Document ready handler and DOM mutation observers. Initializes Tabs components as necessary. 1116 * 1117 * @private 1118 */ 1119 function onDocumentReady() { 1120 dataLayerEnabled = document.body.hasAttribute("data-cmp-data-layer-enabled"); 1121 if (dataLayerEnabled) { 1122 dataLayerName = document.body.getAttribute("data-cmp-data-layer-name") || "adobeDataLayer"; 1123 dataLayer = window[dataLayerName] = window[dataLayerName] || []; 1124 } 1125 1126 var elements = document.querySelectorAll(selectors.self); 1127 for (var i = 0; i < elements.length; i++) { 1128 new Tabs({ element: elements[i], options: readData(elements[i]) }); 1129 } 1130 1131 var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver; 1132 var body = document.querySelector("body"); 1133 var observer = new MutationObserver(function(mutations) { 1134 mutations.forEach(function(mutation) { 1135 // needed for IE 1136 var nodesArray = [].slice.call(mutation.addedNodes); 1137 if (nodesArray.length > 0) { 1138 nodesArray.forEach(function(addedNode) { 1139 if (addedNode.querySelectorAll) { 1140 var elementsArray = [].slice.call(addedNode.querySelectorAll(selectors.self)); 1141 elementsArray.forEach(function(element) { 1142 new Tabs({ element: element, options: readData(element) }); 1143 }); 1144 } 1145 }); 1146 } 1147 }); 1148 }); 1149 1150 observer.observe(body, { 1151 subtree: true, 1152 childList: true, 1153 characterData: true 1154 }); 1155 } 1156 1157 if (document.readyState !== "loading") { 1158 onDocumentReady(); 1159 } else { 1160 document.addEventListener("DOMContentLoaded", onDocumentReady); 1161 } 1162 1163 if (containerUtils) { 1164 window.addEventListener("load", containerUtils.scrollToAnchor, false); 1165 } 1166 1167}()); 1168 1169 1170/******************************************************************************* 1171 * Copyright 2018 Adobe 1172 * 1173 * Licensed under the Apache License, Version 2.0 (the "License"); 1174 * you may not use this file except in compliance with the License. 1175 * You may obtain a copy of the License at 1176 * 1177 * http://www.apache.org/licenses/LICENSE2.0 1178 * 1179 * Unless required by applicable law or agreed to in writing, software 1180 * distributed under the License is distributed on an "AS IS" BASIS, 1181 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1182 * See the License for the specific language governing permissions and 1183 * limitations under the License. 1184 ******************************************************************************/ 1185 1186/** 1187 * Element.matches() 1188 * https://developer.mozilla.org/enUS/docs/Web/API/Element/matches#Polyfill 1189 */ 1190if (!Element.prototype.matches) { 1191 Element.prototype.matches = Element.prototype.msMatchesSelector || Element.prototype.webkitMatchesSelector; 1192} 1193 1194// eslint-disable-next-line valid-jsdoc 1195/** 1196 * Element.closest() 1197 * https://developer.mozilla.org/enUS/docs/Web/API/Element/closest#Polyfill 1198 */ 1199if (!Element.prototype.closest) { 1200 Element.prototype.closest = function(s) { 1201 "use strict"; 1202 var el = this; 1203 if (!document.documentElement.contains(el)) { 1204 return null; 1205 } 1206 do { 1207 if (el.matches(s)) { 1208 return el; 1209 } 1210 el = el.parentElement || el.parentNode; 1211 } while (el !== null && el.nodeType === 1); 1212 return null; 1213 }; 1214} 1215 1216/******************************************************************************* 1217 * Copyright 2018 Adobe 1218 * 1219 * Licensed under the Apache License, Version 2.0 (the "License");
1220 * you may not use this file except in compliance with the License. 1221 * You may obtain a copy of the License at 1222 * 1223 * http://www.apache.org/licenses/LICENSE-2.0 1224 * 1225 * Unless required by applicable law or agreed to in writing, software 1226 * distributed under the License is distributed on an "AS IS" BASIS, 1227 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1228 * See the License for the specific language governing permissions and 1229 * limitations under the License. 1230 ******************************************************************************/ 1231/* global 1232 CQ 1233 */ 1234(function() { 1235 "use strict"; 1236 1237 var containerUtils = window.CQ && window.CQ.CoreComponents && window.CQ.CoreComponents.container && window.CQ.CoreComponents.container.utils ? window.CQ.CoreComponents.container.utils : undefined; 1238 if (!containerUtils) { 1239 // eslint-disable-next-line no-console 1240 console.warn("Tabs: container utilities at window.CQ.CoreComponents.container.utils are not available. This can lead to missing features. Ensure the core.wcm.components.commons.site.container client library is included on the page."); 1241 } 1242 var dataLayerEnabled; 1243 var dataLayer; 1244 1245 var NS = "cmp"; 1246 var IS = "tabs"; 1247 1248 var keyCodes = { 1249 END: 35, 1250 HOME: 36, 1251 ARROW_LEFT: 37, 1252 ARROW_UP: 38, 1253 ARROW_RIGHT: 39, 1254 ARROW_DOWN: 40 1255 }; 1256 1257 var selectors = { 1258 self: "[data-" + NS + '-is="' + IS + '"]', 1259 active: { 1260 tab: "cmp-tabs__tab--active", 1261 tabpanel: "cmp-tabs__tabpanel--active" 1262 } 1263 }; 1264 1265 /** 1266 * Tabs Configuration 1267 * 1268 * @typedef {Object} TabsConfig Represents a Tabs configuration 1269 * @property {HTMLElement} element The HTMLElement representing the Tabs 1270 * @property {Object} options The Tabs options 1271 */ 1272 1273 /** 1274 * Tabs 1275 * 1276 * @class Tabs 1277 * @classdesc An interactive Tabs component for navigating a list of tabs 1278 * @param {TabsConfig} config The Tabs configuration 1279 */ 1280 function Tabs(config) { 1281 var that = this; 1282 1283 if (config && config.element) { 1284 init(config); 1285 } 1286 1287 /** 1288 * Initializes the Tabs 1289 * 1290 * @private 1291 * @param {TabsConfig} config The Tabs configuration 1292 */ 1293 function init(config) { 1294 // debugger; 1295 that._config = config; 1296 1297 // prevents multiple initialization 1298 config.element.removeAttribute("data-" + NS + "-is"); 1299 1300 cacheElements(config.element); 1301 that._active = getActiveIndex(that._elements["tab"]); 1302 1303 if (that._elements.tabpanel) { 1304 // debugger; 1305 refreshActive(); 1306 bindEvents(); 1307 scrollToDeepLinkIdInTabs(); 1308 } 1309 1310 if (window.Granite && window.Granite.author && window.Granite.author.MessageChannel) { 1311 /* 1312 * Editor message handling: 1313 * - subscribe to "cmp.panelcontainer" message requests sent by the editor frame 1314 * - check that the message data panel container type is correct and that the id (path) matches this specific Tabs component 1315 * - if so, route the "navigate" operation to enact a navigation of the Tabs based on index data 1316 */ 1317 CQ.CoreComponents.MESSAGE_CHANNEL = CQ.CoreComponents.MESSAGE_CHANNEL || new window.Granite.author.MessageChannel("cqauthor", window); 1318 CQ.CoreComponents.MESSAGE_CHANNEL.subscribeRequestMessage("cmp.panelcontainer", function(message) { 1319 if (message.data && message.data.type === "cmp-tabs" && message.data.id === that._elements.self.dataset["cmpPanelcontainerId"]) { 1320 if (message.data.operation === "navigate") { 1321 navigate(message.data.index); 1322 } 1323 } 1324 }); 1325 } 1326 } 1327 1328 /** 1329 * Displays the panel containing the element that corresponds to the deep link in the URI fragment 1330 * and scrolls the browser to this element. 1331 */ 1332 function scrollToDeepLinkIdInTabs() { 1333 // debugger; 1334 if (containerUtils) { 1335 var deepLinkItemIdx = containerUtils.getDeepLinkItemIdx(that, "tab", "tabpanel"); 1336 if (deepLinkItemIdx > -1) { 1337 var deepLinkItem = that._elements["tab"][deepLinkItemIdx]; 1338 if (deepLinkItem && that._elements["tab"][that._active].id !== deepLinkItem.id) { 1339 navigateAndFocusTab(deepLinkItemIdx, true); 1340 } 1341 var hashId = window.location.hash.substring(1); 1342 if (hashId) { 1343 var hashItem = document.querySelector("[id='" + hashId + "']"); 1344 if (hashItem) { 1345 hashItem.scrollIntoView(); 1346 } 1347 } 1348 } 1349 } 1350 } 1351 1352 /** 1353 * Returns the index of the active tab, if no tab is active returns 0 1354 * 1355 * @param {Array} tabs Tab elements 1356 * @returns {Number} Index of the active tab, 0 if none is active 1357 */ 1358 function getActiveIndex(tabs) { 1359 if (tabs) { 1360 for (var i = 0; i < tabs.length; i++) { 1361 if (tabs[i].classList.contains(selectors.active.tab) && tabs[i].classList.contains("nav-link h-100 active")) { 1362 return i; 1363 } 1364 } 1365 } 1366 return 0; 1367 } 1368 1369 /** 1370 * Caches the Tabs elements as defined via the {@code data-tabs-hook="ELEMENT_NAME"} markup API 1371 * 1372 * @private 1373 * @param {HTMLElement} wrapper The Tabs wrapper element 1374 */ 1375 function cacheElements(wrapper) { 1376 that._elements = {}; 1377 that._elements.self = wrapper; 1378 // var hooks = that._elements.self.querySelectorAll("[data-" + NS + "-hook-" + IS + "]"); 1379 var all = that._elements.self.getElementsByTagName("*"); 1380 var hooks = []; 1381 1382 for (var i = 0; i < all.length; i++) { 1383 var el = all[i]; 1384 if (el.hasAttribute("data-" + NS + "-hook-" + IS)) { 1385 hooks.push(el); 1386 } 1387 } 1388 1389 for (var i = 0; i < hooks.length; i++) { 1390 var hook = hooks[i]; 1391 if (hook.closest("." + NS + "-" + IS) === that._elements.self) { // only process own tab elements 1392 var capitalized = IS; 1393 capitalized = capitalized.charAt(0).toUpperCase() + capitalized.slice(1); 1394 var key = hook.dataset[NS + "Hook" + capitalized]; 1395 if (that._elements[key]) { 1396 if (!Array.isArray(that._elements[key])) { 1397 var tmp = that._elements[key]; 1398 that._elements[key] = [tmp]; 1399 } 1400 that._elements[key].push(hook); 1401 } else { 1402 that._elements[key] = hook; 1403 } 1404 } 1405 } 1406 } 1407 1408 /** 1409 * Binds Tabs event handling 1410 * 1411 * @private 1412 */ 1413 function bindEvents() { 1414 window.addEventListener("hashchange", scrollToDeepLinkIdInTabs, false); 1415 var tabs = that._elements["tab"]; 1416 if (tabs) { 1417 for (var i = 0; i < tabs.length; i++) { 1418 (function(index) { 1419 tabs[i].addEventListener("click", function(event) { 1420 navigateAndFocusTab(index); 1421 }); 1422 tabs[i].addEventListener("keydown", function(event) { 1423 onKeyDown(event); 1424 }); 1425 })(i); 1426 } 1427 } 1428 } 1429 1430 /** 1431 * Handles tab keydown events 1432 * 1433 * @private 1434 * @param {Object} event The keydown event 1435 */ 1436 function onKeyDown(event) { 1437 var index = that._active; 1438 var lastIndex = that._elements["tab"].length - 1; 1439 1440 switch (event.keyCode) { 1441 case keyCodes.ARROW_LEFT: 1442 case keyCodes.ARROW_UP: 1443 event.preventDefault(); 1444 if (index > 0) { 1445 navigateAndFocusTab(index - 1); 1446 } 1447 break; 1448 case keyCodes.ARROW_RIGHT: 1449 case keyCodes.ARROW_DOWN: 1450 event.preventDefault(); 1451 if (index < lastIndex) { 1452 navigateAndFocusTab(index + 1); 1453 } 1454 break; 1455 case keyCodes.HOME: 1456 event.preventDefault(); 1457 navigateAndFocusTab(0); 1458 break; 1459 case keyCodes.END: 1460 event.preventDefault(); 1461 navigateAndFocusTab(lastIndex); 1462 break; 1463 default: 1464 return; 1465 } 1466 } 1467 1468 /** 1469 * Refreshes the tab markup based on the current {@code Tabs#_active} index 1470 * 1471 * @private 1472 */ 1473 function refreshActive() { 1474 var tabpanels = that._elements["tabpanel"]; 1475 var tabs = that._elements["tab"]; 1476 1477 if (tabpanels) { 1478 if (Array.isArray(tabpanels)) { 1479 for (var i = 0; i < tabpanels.length; i++) { 1480 if (i === parseInt(that._active)) { 1481 tabpanels[i].classList.add(selectors.active.tabpanel); 1482 tabpanels[i].removeAttribute("aria-hidden"); 1483 tabs[i].classList.add(selectors.active.tab); 1484 tabs[i].classList.add("active"); 1485 tabs[i].setAttribute("aria-selected", true); 1486 tabs[i].setAttribute("tabindex", "0"); 1487 } else { 1488 tabpanels[i].classList.remove(selectors.active.tabpanel); 1489 tabpanels[i].setAttribute("aria-hidden", true); 1490 tabs[i].classList.remove(selectors.active.tab); 1491 tabs[i].classList.remove("active"); 1492 tabs[i].setAttribute("aria-selected", false); 1493 tabs[i].setAttribute("tabindex", "-1"); 1494 } 1495 } 1496 } else { 1497 // only one tab 1498 tabpanels.classList.add(selectors.active.tabpanel); 1499 tabs.classList.add(selectors.active.tab); 1500 } 1501 } 1502 } 1503 1504 /** 1505 * Focuses the element and prevents scrolling the element into view 1506 * 1507 * @param {HTMLElement} element Element to focus 1508 */ 1509 function focusWithoutScroll(element) { 1510 var x = window.scrollX || window.pageXOffset; 1511 var y = window.scrollY || window.pageYOffset; 1512 element.focus(); 1513 window.scrollTo(x, y); 1514 } 1515 1516 /** 1517 * Navigates to the tab at the provided index 1518 * 1519 * @private 1520 * @param {Number} index The index of the tab to navigate to 1521 */ 1522 function navigate(index) { 1523 that._active = index; 1524 refreshActive(); 1525 } 1526 1527 /** 1528 * Navigates to the item at the provided index and ensures the active tab gains focus 1529 * 1530 * @private 1531 * @param {Number} index The index of the item to navigate to 1532 * @param {Boolean} keepHash true to keep the hash in the URL, false to update it 1533 */ 1534 function navigateAndFocusTab(index, keepHash) { 1535 //debugger; 1536 var exActive = that._active; 1537 if (!keepHash && containerUtils) { 1538 containerUtils.updateUrlHash(that, "tab", index); 1539 } 1540 navigate(index); 1541 focusWithoutScroll(that._elements["tab"][index]); 1542 1543 if (dataLayerEnabled) { 1544 1545 var activeItem = getDataLayerId(that._elements.tabpanel[index]); 1546 var exActiveItem = getDataLayerId(that._elements.tabpanel[exActive]); 1547 1548 dataLayer.push({ 1549 event: "cmp:show", 1550 eventInfo: { 1551 path: "component." + activeItem 1552 } 1553 }); 1554 1555 dataLayer.push({ 1556 event: "cmp:hide", 1557 eventInfo: { 1558 path: "component." + exActiveItem 1559 } 1560 }); 1561 1562 var tabsId = that._elements.self.id; 1563 var uploadPayload = { component: {} }; 1564 uploadPayload.component[tabsId] = { shownItems: [activeItem] }; 1565 1566 var removePayload = { component: {} }; 1567 removePayload.component[tabsId] = { shownItems: undefined }; 1568 1569 dataLayer.push(removePayload); 1570 dataLayer.push(uploadPayload); 1571 } 1572 } 1573 } 1574 1575 /**
1576 * Reads options data from the Tabs wrapper element, defined via {@code data-cmp-*} data attributes 1577 * 1578 * @private 1579 * @param {HTMLElement} element The Tabs element to read options data from 1580 * @returns {Object} The options read from the component data attributes 1581 */ 1582 function readData(element) { 1583 var data = element.dataset; 1584 var options = []; 1585 var capitalized = IS; 1586 capitalized = capitalized.charAt(0).toUpperCase() + capitalized.slice(1); 1587 var reserved = ["is", "hook" + capitalized]; 1588 1589 for (var key in data) { 1590 if (Object.prototype.hasOwnProperty.call(data, key)) { 1591 var value = data[key]; 1592 1593 if (key.indexOf(NS) === 0) { 1594 key = key.slice(NS.length); 1595 key = key.charAt(0).toLowerCase() + key.substring(1); 1596 1597 if (reserved.indexOf(key) === -1) { 1598 options[key] = value; 1599 } 1600 } 1601 } 1602 } 1603 1604 return options; 1605 } 1606 1607 /** 1608 * Parses the dataLayer string and returns the ID 1609 * 1610 * @private 1611 * @param {HTMLElement} item the accordion item 1612 * @returns {String} dataLayerId or undefined 1613 */ 1614 function getDataLayerId(item) { 1615 if (item) { 1616 if (item.dataset.cmpDataLayer) { 1617 try { 1618 return Object.keys(JSON.parse(item.dataset.cmpDataLayer))[0]; 1619 } catch (e) { 1620 console.error("Errore nel parsing di cmpDataLayer:", e); 1621 return null; 1622 } 1623 } else { 1624 return item.id; 1625 } 1626 } 1627 return null; 1628 } 1629 1630 /** 1631 * Document ready handler and DOM mutation observers. Initializes Tabs components as necessary. 1632 * 1633 * @private 1634 */ 1635 function onDocumentReady() { 1636 dataLayerEnabled = document.body.hasAttribute("data-cmp-data-layer-enabled"); 1637 dataLayer = (dataLayerEnabled) ? window.adobeDataLayer = window.adobeDataLayer || [] : undefined; 1638 1639 // var elements = document.querySelectorAll(selectors.self); 1640 var all = document.getElementsByTagName("*"); 1641 var elements = []; 1642 1643 for (var i = 0; i < all.length; i++) { 1644 var el = all[i]; 1645 if (el.hasAttribute("data-" + NS + "-hook-" + IS)) { 1646 elements.push(el); 1647 } 1648 } 1649 for (var i = 0; i < elements.length; i++) { 1650 new Tabs({ element: elements[i], options: readData(elements[i]) }); 1651 } 1652 1653 var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver; 1654 // var body = document.querySelector("body"); 1655 var body = document.getElementsByTagName("body")[0]; 1656 var observer = new MutationObserver(function(mutations) { 1657 mutations.forEach(function(mutation) { 1658 // needed for IE 1659 var nodesArray = [].slice.call(mutation.addedNodes); 1660 if (nodesArray.length > 0) { 1661 nodesArray.forEach(function(addedNode) { 1662 if (addedNode instanceof Element) { 1663 var all = addedNode.getElementsByTagName("*"); 1664 var elements = []; 1665 1666 for (var i = 0; i < all.length; i++) { 1667 var el = all[i]; 1668 if (el.hasAttribute("data-" + NS + "-hook-" + IS)) { 1669 elements.push(el); 1670 } 1671 } 1672 var elementsArray = [].slice.call(elements); 1673 elementsArray.forEach(function(element) { 1674 new Tabs({ element: element, options: readData(element) }); 1675 }); 1676 } 1677 }); 1678 } 1679 }); 1680 }); 1681 1682 observer.observe(body, { 1683 subtree: true, 1684 childList: true, 1685 characterData: true 1686 }); 1687 1688 // debugger; 1689 let tabAnchorWithHash = window.location.hash; 1690 let tabAnchor = tabAnchorWithHash.replace('#', ""); 1691 let tabDivAnchor = tabAnchor.replace("-tab", "") 1692 let li = $('[role=tablist]').children() 1693 let anchorDivs = $('div[id*=tabsCustom][id*=item]') 1694 1695 1696 1697 if (tabAnchorWithHash) { 1698 $(li).each(function (i, li) { 1699 $(anchorDivs, li).each(function (ii, divs) { 1700 if ($(li).attr('id') == tabAnchor && $(divs).attr('id') == tabDivAnchor) { 1701 $(li).children().attr('class', 'nav-link h-100 cmp-tabs__tab cmp-tabs__tab--active') 1702 $(divs).attr('class', 'cmp-tabs__tabpanel cmp-tabs__tabpanel--active') 1703 } else { 1704 $(li).children().attr('class', 'nav-link h-100 cmp-tabs__tab') 1705 $(divs).attr('class', 'cmp-tabs__tabpanel') 1706 } 1707 }) 1708 }) 1709 } 1710 } 1711 1712 if (document.readyState !== "loading") { 1713 onDocumentReady(); 1714 } else { 1715 document.addEventListener("DOMContentLoaded", onDocumentReady); 1716 } 1717 1718 if (containerUtils) { 1719 window.addEventListener("load", containerUtils.scrollToAnchor, false); 1720 } 1721 1722}()); 1723 1724/******************************************************************************* 1725 * Copyright 2022 Adobe 1726 * 1727 * Licensed under the Apache License, Version 2.0 (the "License");
1728 * you may not use this file except in compliance with the License. 1729 * You may obtain a copy of the License at 1730 * 1731 * http://www.apache.org/licenses/LICENSE-2.0 1732 * 1733 * Unless required by applicable law or agreed to in writing, software 1734 * distributed under the License is distributed on an "AS IS" BASIS, 1735 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1736 * See the License for the specific language governing permissions and 1737 * limitations under the License. 1738 ******************************************************************************/ 1739(function(document) { 1740 "use strict"; 1741 1742 window.CMP = window.CMP || {}; 1743 window.CMP.utils = (function() { 1744 var NS = "cmp"; 1745 1746 /** 1747 * Reads options data from the Component wrapper element, defined via {@code data-cmp-*} data attributes 1748 * 1749 * @param {HTMLElement} element The component element to read options data from 1750 * @param {String} is The component identifier 1751 * @returns {String[]} The options read from the component data attributes 1752 */ 1753 var readData = function(element, is) { 1754 var data = element.dataset; 1755 var options = []; 1756 var capitalized = is; 1757 capitalized = capitalized.charAt(0).toUpperCase() + capitalized.slice(1); 1758 var reserved = ["is", "hook" + capitalized]; 1759 1760 for (var key in data) { 1761 if (Object.prototype.hasOwnProperty.call(data, key)) { 1762 var value = data[key]; 1763 1764 if (key.indexOf(NS) === 0) { 1765 key = key.slice(NS.length); 1766 key = key.charAt(0).toLowerCase() + key.substring(1); 1767 1768 if (reserved.indexOf(key) === -1) { 1769 options[key] = value; 1770 } 1771 } 1772 } 1773 } 1774 return options; 1775 }; 1776 1777 /** 1778 * Set up the final properties of a component by evaluating the transform function or fall back to the default value on demand 1779 * @param {String[]} options the options to transform 1780 * @param {Object} properties object of properties of property functions 1781 * @returns {Object} transformed properties 1782 */ 1783 var setupProperties = function(options, properties) { 1784 var transformedProperties = {}; 1785 1786 for (var key in properties) { 1787 if (Object.prototype.hasOwnProperty.call(properties, key)) { 1788 var property = properties[key]; 1789 if (options && options[key] != null) { 1790 if (property && typeof property.transform === "function") { 1791 transformedProperties[key] = property.transform(options[key]); 1792 } else { 1793 transformedProperties[key] = options[key]; 1794 } 1795 } else { 1796 transformedProperties[key] = properties[key]["default"]; 1797 } 1798 } 1799 } 1800 return transformedProperties; 1801 }; 1802 1803 1804 return { 1805 readData: readData, 1806 setupProperties: setupProperties 1807 }; 1808 }()); 1809}(window.document)); 1810 1811/******************************************************************************* 1812 * Copyright 2018 Adobe 1813 * 1814 * Licensed under the Apache License, Version 2.0 (the "License"); 1815 * you may not use this file except in compliance with the License. 1816 * You may obtain a copy of the License at 1817 * 1818 * http://www.apache.org/licenses/LICENSE-2.0 1819 * 1820 * Unless required by applicable law or agreed to in writing, software 1821 * distributed under the License is distributed on an "AS IS" BASIS, 1822 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1823 * See the License for the specific language governing permissions and 1824 * limitations under the License. 1825 ******************************************************************************/ 1826(function() { 1827 "use strict"; 1828 1829 var containerUtils = window.CQ && window.CQ.CoreComponents && window.CQ.CoreComponents.c
1829ontainer && window.CQ.CoreComponents.container.utils ? window.CQ.CoreComponents.container.utils : undefined; 1830 if (!containerUtils) { 1831 // eslint-disable-next-line no-console 1832 console.warn("Tabs: container utilities at window.CQ.CoreComponents.container.utils are not available. This can lead to missing features. Ensure the core.wcm.components.commons.site.container client library is included on the page."); 1833 } 1834 var dataLayerEnabled; 1835 var dataLayer; 1836 var dataLayerName; 1837 1838 var NS = "cmp"; 1839 var IS = "carousel"; 1840 1841 var keyCodes = { 1842 SPACE: 32, 1843 END: 35, 1844 HOME: 36, 1845 ARROW_LEFT: 37, 1846 ARROW_UP: 38, 1847 ARROW_RIGHT: 39, 1848 ARROW_DOWN: 40 1849 }; 1850 1851 var selectors = { 1852 self: "[data-" + NS + '-is="' + IS + '"]' 1853 }; 1854 1855 var properties = { 1856 /** 1857 * Determines whether the Carousel will automatically transition between slides 1858 * 1859 * @memberof Carousel 1860 * @type {Boolean} 1861 * @default false 1862 */ 1863 "autoplay": { 1864 "default": false, 1865 "transform": function(value) { 1866 return !(value === null || typeof value === "undefined"); 1867 } 1868 }, 1869 /** 1870 * Duration (in milliseconds) before automatically transitioning to the next slide 1871 * 1872 * @memberof Carousel 1873 * @type {Number} 1874 * @default 5000 1875 */ 1876 "delay": { 1877 "default": 5000, 1878 "transform": function(value) { 1879 value = parseFloat(value); 1880 return !isNaN(value) ? value : null; 1881 } 1882 }, 1883 /** 1884 * Determines whether automatic pause on hovering the carousel is disabled 1885 * 1886 * @memberof Carousel 1887 * @type {Boolean} 1888 * @default false 1889 */ 1890 "autopauseDisabled": { 1891 "default": false, 1892 "transform": function(value) { 1893 return !(value === null || typeof value === "undefined"); 1894 } 1895 } 1896 }; 1897 1898 /** 1899 * Carousel Configuration 1900 * 1901 * @typedef {Object} CarouselConfig Represents a Carousel configuration 1902 * @property {HTMLElement} element The HTMLElement representing the Carousel 1903 * @property {*[]} options The Carousel options 1904 */ 1905 1906 /** 1907 * Carousel 1908 * 1909 * @class Carousel 1910 * @classdesc An interactive Carousel component for navigating a list of generic items 1911 * @param {CarouselConfig} config The Carousel configuration 1912 */ 1913 function Carousel(config) { 1914 var that = this; 1915 1916 if (config && config.element) { 1917 init(config); 1918 } 1919 1920 /** 1921 * Initializes the Carousel 1922 * 1923 * @private 1924 * @param {CarouselConfig} config The Carousel configuration 1925 */ 1926 function init(config) { 1927 that._config = config; 1928 1929 // prevents multiple initialization 1930 config.element.removeAttribute("data-" + NS + "-is"); 1931 1932 setupProperties(config.options); 1933 cacheElements(config.element); 1934 1935 that._active = 0; 1936 that._paused = false; 1937 1938 if (that._elements.item) { 1939 initializeActive(); 1940 bindEvents(); 1941 resetAutoplayInterval(); 1942 refreshPlayPauseActions(); 1943 scrollToDeepLinkIdInCarousel(); 1944 } 1945 1946 // TODO: This section is only relevant in edit mode and should move to the editor clientLib 1947 if (window.Granite && window.Granite.author && window.Granite.author.MessageChannel) { 1948 /* 1949 * Editor message handling: 1950 * - subscribe to "cmp.panelcontainer" message requests sent by the editor frame 1951 * - check that the message data panel container type is correct and that the id (path) matches this specific Carousel component 1952 * - if so, route the "navigate" operation to enact a navigation of the Carousel based on index data 1953 */ 1954 window.CQ = window.CQ || {}; 1955 window.CQ.CoreComponents = window.CQ.CoreComponents || {}; 1956 window.CQ.CoreComponents.MESSAGE_CHANNEL = window.CQ.CoreComponents.MESSAGE_CHANNEL || new window.Granite.author.MessageChannel("cqauthor", window); 1957 window.CQ.CoreComponents.MESSAGE_CHANNEL.subscribeRequestMessage("cmp.panelcontainer", function(message) { 1958 if (message.data && message.data.type === "cmp-carousel" && message.data.id === that._elements.self.dataset["cmpPanelcontainerId"]) { 1959 if (message.data.operation === "navigate") { 1960 navigate(message.data.index); 1961 } 1962 } 1963 }); 1964 } 1965 } 1966 1967 /**
1968 * Displays the slide containing the element that corresponds to the deep link in the URI fragment 1969 * and scrolls the browser to this element. 1970 */ 1971 function scrollToDeepLinkIdInCarousel() { 1972 if (containerUtils) { 1973 var deepLinkItemIdx = containerUtils.getDeepLinkItemIdx(that, "item", "item"); 1974 if (deepLinkItemIdx > -1) { 1975 var deepLinkItem = that._elements["item"][deepLinkItemIdx]; 1976 if (deepLinkItem && that._elements["item"][that._active].id !== deepLinkItem.id) { 1977 navigateAndFocusIndicator(deepLinkItemIdx, true); 1978 // pause the carousel auto-rotation 1979 pause(); 1980 } 1981 var hashId = window.location.hash.substring(1); 1982 if (hashId) { 1983 var hashItem = document.querySelector("[id='" + hashId + "']"); 1984 if (hashItem) { 1985 hashItem.scrollIntoView(); 1986 } 1987 } 1988 } 1989 } 1990 } 1991 1992 /** 1993 * Caches the Carousel elements as defined via the {@code data-carousel-hook="ELEMENT_NAME"} markup API 1994 * 1995 * @private 1996 * @param {HTMLElement} wrapper The Carousel wrapper element 1997 */ 1998 function cacheElements(wrapper) { 1999 that._elements = {}; 2000 that._elements.self = wrapper; 2001 var hooks = that._elements.self.querySelectorAll("[data-" + NS + "-hook-" + IS + "]"); 2002 2003 for (var i = 0; i < hooks.length; i++) { 2004 var hook = hooks[i]; 2005 var capitalized = IS; 2006 capitalized = capitalized.charAt(0).toUpperCase() + capitalized.slice(1); 2007 var key = hook.dataset[NS + "Hook" + capitalized]; 2008 if (that._elements[key]) { 2009 if (!Array.isArray(that._elements[key])) { 2010 var tmp = that._elements[key]; 2011 that._elements[key] = [tmp]; 2012 } 2013 that._elements[key].push(hook); 2014 } else { 2015 that._elements[key] = hook; 2016 } 2017 } 2018 } 2019 2020 /** 2021 * Sets up properties for the Carousel based on the passed options. 2022 * 2023 * @private 2024 * @param {Object} options The Carousel options 2025 */ 2026 function setupProperties(options) { 2027 that._properties = {}; 2028 2029 for (var key in properties) { 2030 if (Object.prototype.hasOwnProperty.call(properties, key)) { 2031 var property = properties[key]; 2032 var value = null; 2033 2034 if (options && options[key] != null) { 2035 value = options[key]; 2036 2037 // transform the provided option 2038 if (property && typeof property.transform === "function") { 2039 value = property.transform(value); 2040 } 2041 } 2042 2043 if (value === null) { 2044 // value still null, take the property default 2045 value = properties[key]["default"]; 2046 } 2047 2048 that._properties[key] = value; 2049 } 2050 } 2051 } 2052 2053 /** 2054 * Binds Carousel event handling 2055 * 2056 * @private 2057 */ 2058 function bindEvents() { 2059 window.addEventListener("hashchange", scrollToDeepLinkIdInCarousel, false); 2060 if (that._elements["previous"]) { 2061 that._elements["previous"].addEventListener("click", function() { 2062 var index = getPreviousIndex(); 2063 navigate(index); 2064 if (dataLayerEnabled) { 2065 dataLayer.push({ 2066 event: "cmp:show", 2067 eventInfo: { 2068 path: "component." + getDataLayerId(that._elements.item[index]) 2069 } 2070 }); 2071 } 2072 }); 2073 } 2074 2075 if (that._elements["next"]) { 2076 that._elements["next"].addEventListener("click", function() { 2077 var index = getNextIndex(); 2078 navigate(index); 2079 if (dataLayerEnabled) { 2080 dataLayer.push({ 2081 event: "cmp:show", 2082 eventInfo: { 2083 path: "component." + getDataLayerId(that._elements.item[index]) 2084 } 2085 }); 2086 } 2087 }); 2088 } 2089 2090 var indicators = that._elements["indicator"]; 2091 if (indicators) { 2092 for (var i = 0; i < indicators.length; i++) { 2093 (function(index) { 2094 indicators[i].addEventListener("click", function(event) { 2095 navigateAndFocusIndicator(index); 2096 // pause the carousel auto-rotation 2097 pause(); 2098 }); 2099 })(i); 2100 } 2101 } 2102 2103 if (that._elements["pause"]) { 2104 if (that._properties.autoplay) { 2105 that._elements["pause"].addEventListener("click", onPauseClick); 2106 } 2107 } 2108 2109 if (that._elements["play"]) { 2110 if (that._properties.autoplay) { 2111 that._elements["play"].addEventListener("click", onPlayClick); 2112 } 2113 } 2114 2115 that._elements.self.addEventListener("keydown", onKeyDown); 2116 2117 if (!that._properties.autopauseDisabled) { 2118 that._elements.self.addEventListener("mouseenter", onMouseEnter); 2119 that._elements.self.addEventListener("mouseleave", onMouseLeave); 2120 } 2121 2122 // for accessibility we pause animation when a element get focused 2123 var items = that._elements["item"]; 2124 if (items) { 2125 for (var j = 0; j < items.length; j++) { 2126 items[j].addEventListener("focusin", onMouseEnter); 2127 items[j].addEventListener("focusout", onMouseLeave); 2128 } 2129 } 2130 } 2131 2132 /**
2133 * Handles carousel keydown events 2134 * 2135 * @private 2136 * @param {Object} event The keydown event 2137 */ 2138 function onKeyDown(event) { 2139 var index = that._active; 2140 var lastIndex = that._elements["indicator"].length - 1; 2141 2142 switch (event.keyCode) { 2143 case keyCodes.ARROW_LEFT: 2144 case keyCodes.ARROW_UP: 2145 event.preventDefault(); 2146 if (index > 0) { 2147 navigateAndFocusIndicator(index - 1); 2148 } 2149 break; 2150 case keyCodes.ARROW_RIGHT: 2151 case keyCodes.ARROW_DOWN: 2152 event.preventDefault(); 2153 if (index < lastIndex) { 2154 navigateAndFocusIndicator(index + 1); 2155 } 2156 break; 2157 case keyCodes.HOME: 2158 event.preventDefault(); 2159 navigateAndFocusIndicator(0); 2160 break; 2161 case keyCodes.END: 2162 event.preventDefault(); 2163 navigateAndFocusIndicator(lastIndex); 2164 break; 2165 case keyCodes.SPACE: 2166 if (that._properties.autoplay && (event.target !== that._elements["previous"] && event.target !== that._elements["next"])) { 2167 event.preventDefault(); 2168 if (!that._paused) { 2169 pause(); 2170 } else { 2171 play(); 2172 } 2173 } 2174 if (event.target === that._elements["pause"]) { 2175 that._elements["play"].focus(); 2176 } 2177 if (event.target === that._elements["play"]) { 2178 that._elements["pause"].focus(); 2179 } 2180 break; 2181 default: 2182 return; 2183 } 2184 } 2185 2186 /** 2187 * Handles carousel mouseenter events 2188 * 2189 * @private 2190 * @param {Object} event The mouseenter event 2191 */ 2192 function onMouseEnter(event) { 2193 clearAutoplayInterval(); 2194 } 2195 2196 /** 2197 * Handles carousel mouseleave events 2198 * 2199 * @private 2200 * @param {Object} event The mouseleave event 2201 */ 2202 function onMouseLeave(event) { 2203 resetAutoplayInterval(); 2204 } 2205 2206 /** 2207 * Handles pause element click events 2208 * 2209 * @private 2210 * @param {Object} event The click event 2211 */ 2212 function onPauseClick(event) { 2213 pause(); 2214 that._elements["play"].focus(); 2215 } 2216 2217 /** 2218 * Handles play element click events 2219 * 2220 * @private 2221 * @param {Object} event The click event 2222 */ 2223 function onPlayClick() { 2224 play(); 2225 that._elements["pause"].focus(); 2226 } 2227 2228 /** 2229 * Pauses the playing of the Carousel. Sets {@code Carousel#_paused} marker. 2230 * Only relevant when autoplay is enabled 2231 * 2232 * @private 2233 */ 2234 function pause() { 2235 that._paused = true; 2236 clearAutoplayInterval(); 2237 refreshPlayPauseActions(); 2238 } 2239 2240 /** 2241 * Enables the playing of the Carousel. Sets {@code Carousel#_paused} marker. 2242 * Only relevant when autoplay is enabled 2243 * 2244 * @private 2245 */ 2246 function play() { 2247 that._paused = false; 2248 2249 // If the Carousel is hovered, don't begin auto transitioning until the next mouse leave event 2250 var hovered = false; 2251 if (that._elements.self.parentElement) { 2252 hovered = that._elements.self.parentElement.querySelector(":hover") === that._elements.self; 2253 } 2254 if (that._properties.autopauseDisabled || !hovered) { 2255 resetAutoplayInterval(); 2256 } 2257 2258 refreshPlayPauseActions(); 2259 } 2260 2261 /** 2262 * Refreshes the play/pause action markup based on the {@code Carousel#_paused} state 2263 * 2264 * @private 2265 */ 2266 function refreshPlayPauseActions() {
2267 setActionDisabled(that._elements["pause"], that._paused); 2268 setActionDisabled(that._elements["play"], !that._paused); 2269 } 2270 2271 /** 2272 * Initialize {@code Carousel#_active} based on the active item of the carousel. 2273 */ 2274 function initializeActive() { 2275 var items = that._elements["item"]; 2276 if (items && Array.isArray(items)) { 2277 for (var i = 0; i < items.length; i++) { 2278 if (items[i].classList.contains("cmp-carousel__item--active")) { 2279 that._active = i; 2280 break; 2281 } 2282 } 2283 } 2284 } 2285 2286 /** 2287 * Refreshes the item markup based on the current {@code Carousel#_active} index 2288 * 2289 * @private 2290 */ 2291 function refreshActive() { 2292 var items = that._elements["item"]; 2293 var indicators = that._elements["indicator"]; 2294 2295 if (items) { 2296 if (Array.isArray(items)) { 2297 for (var i = 0; i < items.length; i++) { 2298 if (i === parseInt(that._active)) { 2299 items[i].classList.add("cmp-carousel__item--active"); 2300 items[i].removeAttribute("aria-hidden"); 2301 indicators[i].classList.add("cmp-carousel__indicator--active"); 2302 indicators[i].setAttribute("aria-selected", true); 2303 indicators[i].setAttribute("tabindex", "0"); 2304 } else { 2305 items[i].classList.remove("cmp-carousel__item--active"); 2306 items[i].setAttribute("aria-hidden", true); 2307 indicators[i].classList.remove("cmp-carousel__indicator--active"); 2308 indicators[i].setAttribute("aria-selected", false); 2309 indicators[i].setAttribute("tabindex", "-1"); 2310 } 2311 } 2312 } else { 2313 // only one item 2314 items.classList.add("cmp-carousel__item--active"); 2315 indicators.classList.add("cmp-carousel__indicator--active"); 2316 } 2317 } 2318 } 2319 2320 /** 2321 * Focuses the element and prevents scrolling the element into view 2322 * 2323 * @param {HTMLElement} element Element to focus 2324 */ 2325 function focusWithoutScroll(element) { 2326 var x = window.scrollX || window.pageXOffset; 2327 var y = window.scrollY || window.pageYOffset; 2328 element.focus(); 2329 window.scrollTo(x, y); 2330 } 2331 2332 /** 2333 * Retrieves the next active index, with looping 2334 * 2335 * @private 2336 * @returns {Number} Index of the next carousel item 2337 */ 2338 function getNextIndex() { 2339 return that._active === (that._elements["item"].length - 1) ? 0 : that._active + 1; 2340 } 2341 2342 /** 2343 * Retrieves the previous active index, with looping 2344 * 2345 * @private 2346 * @returns {Number} Index of the previous carousel item 2347 */ 2348 function getPreviousIndex() { 2349 return that._active === 0 ? (that._elements["item"].length - 1) : that._active - 1; 2350 } 2351 2352 /** 2353 * Navigates to the item at the provided index 2354 * 2355 * @private 2356 * @param {Number} index The index of the item to navigate to 2357 * @param {Boolean} keepHash true to keep the hash in the URL, false to update it 2358 */ 2359 function navigate(index, keepHash) { 2360 if (index < 0 || index > (that._elements["item"].length - 1)) { 2361 return; 2362 } 2363 2364 that._active = index; 2365 refreshActive(); 2366 2367 if (!keepHash && containerUtils) { 2368 containerUtils.updateUrlHash(that, "item", index); 2369 } 2370 2371 if (dataLayerEnabled) { 2372 var carouselId = that._elements.self.id; 2373 var activeItem = getDataLayerId(that._elements.item[index]); 2374 var updatePayload = { component: {} }; 2375 updatePayload.component[carouselId] = { shownItems: [activeItem] }; 2376 2377 var removePayload = { component: {} }; 2378 removePayload.component[carouselId] = { shownItems: undefined }; 2379 2380 dataLayer.push(removePayload); 2381 dataLayer.push(updatePayload); 2382 } 2383 2384 // reset the autoplay transition interval following navigation, if not already hovering the carousel
2385 if (that._elements.self.parentElement) { 2386 if (that._elements.self.parentElement.querySelector(":hover") !== that._elements.self) { 2387 resetAutoplayInterval(); 2388 } 2389 } 2390 } 2391 2392 /** 2393 * Navigates to the item at the provided index and ensures the active indicator gains focus 2394 * 2395 * @private 2396 * @param {Number} index The index of the item to navigate to 2397 * @param {Boolean} keepHash true to keep the hash in the URL, false to update it 2398 */ 2399 function navigateAndFocusIndicator(index, keepHash) { 2400 navigate(index, keepHash); 2401 focusWithoutScroll(that._elements["indicator"][index]); 2402 2403 if (dataLayerEnabled) { 2404 dataLayer.push({ 2405 event: "cmp:show", 2406 eventInfo: { 2407 path: "component." + getDataLayerId(that._elements.item[index]) 2408 } 2409 }); 2410 } 2411 } 2412 2413 /** 2414 * Starts/resets automatic slide transition interval 2415 * 2416 * @private 2417 */ 2418 function resetAutoplayInterval() { 2419 if (that._paused || !that._properties.autoplay) { 2420 return; 2421 } 2422 clearAutoplayInterval(); 2423 that._autoplayIntervalId = window.setInterval(function() { 2424 if (document.visibilityState && document.hidden) { 2425 return; 2426 } 2427 var indicators = that._elements["indicators"]; 2428 if (indicators !== document.activeElement && indicators.contains(document.activeElement)) { 2429 // if an indicator has focus, ensure we switch focus following navigation 2430 navigateAndFocusIndicator(getNextIndex(), true); 2431 } else { 2432 navigate(getNextIndex(), true); 2433 } 2434 }, that._properties.delay); 2435 } 2436 2437 /** 2438 * Clears/pauses automatic slide transition interval 2439 * 2440 * @private 2441 */ 2442 function clearAutoplayInterval() { 2443 window.clearInterval(that._autoplayIntervalId); 2444 that._autoplayIntervalId = null; 2445 } 2446 2447 /** 2448 * Sets the disabled state for an action and toggles the appropriate CSS classes 2449 * 2450 * @private 2451 * @param {HTMLElement} action Action to disable 2452 * @param {Boolean} [disable] {@code true} to disable, {@code false} to enable 2453 */ 2454 function setActionDisabled(action, disable) { 2455 if (!action) { 2456 return; 2457 } 2458 if (disable !== false) { 2459 action.disabled = true; 2460 action.classList.add("cmp-carousel__action--disabled"); 2461 } else { 2462 action.disabled = false; 2463 action.classList.remove("cmp-carousel__action--disabled"); 2464 } 2465 } 2466 } 2467 2468 /** 2469 * Parses the dataLayer string and returns the ID 2470 * 2471 * @private 2472 * @param {HTMLElement} item the accordion item 2473 * @returns {String} dataLayerId or undefined 2474 */ 2475 function getDataLayerId(item) { 2476 if (item) { 2477 if (item.dataset.cmpDataLayer) { 2478 return Object.keys(JSON.parse(item.dataset.cmpDataLayer))[0]; 2479 } else { 2480 return item.id; 2481 } 2482 } 2483 return null; 2484 } 2485 2486 /** 2487 * Document ready handler and DOM mutation observers. Initializes Carousel components as necessary. 2488 * 2489 * @private 2490 */ 2491 function onDocumentReady() { 2492 dataLayerEnabled = document.body.hasAttribute("data-cmp-data-layer-enabled"); 2493 if (dataLayerEnabled) { 2494 dataLayerName = document.body.getAttribute("data-cmp-data-layer-name") || "adobeDataLayer"; 2495 dataLayer = window[dataLayerName] = window[dataLayerName] || []; 2496 } 2497 2498 var elements = document.querySelectorAll(selectors.self); 2499 for (var i = 0; i < elements.length; i++) { 2500 new Carousel({ element: elements[i], options: CMP.utils.readData(elements[i], IS) }); 2501 } 2502 2503 var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver; 2504 var body = document.querySelector("body"); 2505 var observer = new MutationObserver(function(mutations) { 2506 mutations.forEach(function(mutation) { 2507 // needed for IE 2508 var nodesArray = [].slice.call(mutation.addedNodes); 2509 if (nodesArray.length > 0) { 2510 nodesArray.forEach(function(addedNode) { 2511 if (addedNode.querySelectorAll) { 2512 var elementsArray = [].slice.call(addedNode.querySelectorAll(selectors.self)); 2513 elementsArray.forEach(function(element) { 2514 new Carousel({ element: element, options: CMP.utils.readData(element, IS) }); 2515 }); 2516 } 2517 }); 2518 } 2519 }); 2520 }); 2521 2522 observer.observe(body, { 2523 subtree: true, 2524 childList: true, 2525 characterData: true 2526 }); 2527 } 2528 2529 var documentReady = document.readyState !== "loading" ? Promise.resolve() : new Promise(function(resolve) { 2530 document.addEventListener("DOMContentLoaded", resolve); 2531 }); 2532 Promise.all([documentReady]).then(onDocumentReady); 2533 2534 if (containerUtils) { 2535 window.addEventListener("load", containerUtils.scrollToAnchor, false); 2536 } 2537 2538}()); 2539 2540 2541/******************************************************************************* 2542 * Copyright 2022 Adobe 2543 * 2544 * Licensed under the Apache License, Version 2.0 (the "License");
2545 * you may not use this file except in compliance with the License. 2546 * You may obtain a copy of the License at 2547 * 2548 * http://www.apache.org/licenses/LICENSE-2.0 2549 * 2550 * Unless required by applicable law or agreed to in writing, software 2551 * distributed under the License is distributed on an "AS IS" BASIS, 2552 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 2553 * See the License for the specific language governing permissions and 2554 * limitations under the License. 2555 ******************************************************************************/ 2556(function(document) { 2557 "use strict"; 2558 2559 window.CMP = window.CMP || {}; 2560 window.CMP.utils = (function() { 2561 var NS = "cmp"; 2562 2563 /** 2564 * Reads options data from the Component wrapper element, defined via {@code data-cmp-*} data attributes 2565 * 2566 * @param {HTMLElement} element The component element to read options data from 2567 * @param {String} is The component identifier 2568 * @returns {String[]} The options read from the component data attributes 2569 */ 2570 var readData = function(element, is) { 2571 var data = element.dataset; 2572 var options = []; 2573 var capitalized = is; 2574 capitalized = capitalized.charAt(0).toUpperCase() + capitalized.slice(1); 2575 var reserved = ["is", "hook" + capitalized]; 2576 2577 for (var key in data) { 2578 if (Object.prototype.hasOwnProperty.call(data, key)) { 2579 var value = data[key]; 2580 2581 if (key.indexOf(NS) === 0) { 2582 key = key.slice(NS.length); 2583 key = key.charAt(0).toLowerCase() + key.substring(1); 2584 2585 if (reserved.indexOf(key) === -1) { 2586 options[key] = value; 2587 } 2588 } 2589 } 2590 } 2591 return options; 2592 }; 2593 2594 /** 2595 * Set up the final properties of a component by evaluating the transform function or fall back to the default value on demand 2596 * @param {String[]} options the options to transform 2597 * @param {Object} properties object of properties of property functions 2598 * @returns {Object} transformed properties 2599 */ 2600 var setupProperties = function(options, properties) { 2601 var transformedProperties = {}; 2602 2603 for (var key in properties) { 2604 if (Object.prototype.hasOwnProperty.call(properties, key)) { 2605 var property = properties[key]; 2606 if (options && options[key] != null) { 2607 if (property && typeof property.transform === "function") { 2608 transformedProperties[key] = property.transform(options[key]); 2609 } else { 2610 transformedProperties[key] = options[key]; 2611 } 2612 } else { 2613 transformedProperties[key] = properties[key]["default"]; 2614 } 2615 } 2616 } 2617 return transformedProperties; 2618 }; 2619 2620 2621 return { 2622 readData: readData, 2623 setupProperties: setupProperties 2624 }; 2625 }()); 2626}(window.document)); 2627 2628/******************************************************************************* 2629 * Copyright 2022 Adobe 2630 * 2631 * Licensed under the Apache License, Version 2.0 (the "License"); 2632 * you may not use this file except in compliance with the License. 2633 * You may obtain a copy of the License at 2634 * 2635 * http://www.apache.org/licenses/LICENSE-2.0 2636 * 2637 * Unless required by applicable law or agreed to in writing, software 2638 * distributed under the License is distributed on an "AS IS" BASIS, 2639 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 2640 * See the License for the specific language governing permissions and 2641 * limitations under the License. 2642 ******************************************************************************/ 2643(function(document) { 2644 "use strict"; 2645 2646 window.CMP = window.CMP || {}; 2647 window.CMP.image = window.CMP.image || {}; 2648 window.CMP.image.dynamicMedia = (function() { 2649 var autoSmartCrops = {}; 2650 var SRC_URI_TEMPLATE_WIDTH_VAR = "{.width}"; 2651 var SRC_URI_TEMPLATE_DPR_VAR = "{dpr}";
2652 var SRC_URI_DPR_OFF = "dpr=off"; 2653 var SRC_URI_DPR_ON = "dpr=on,{dpr}"; 2654 var dpr = window.devicePixelRatio || 1; 2655 var config = { 2656 minWidth: 20 2657 }; 2658 2659 /** 2660 * get auto smart crops from dm 2661 * @param {String} src the src uri 2662 * @returns {{}} the smart crop json object 2663 */ 2664 var getAutoSmartCrops = function(src) { 2665 var request = new XMLHttpRequest(); 2666 var url = src.split(SRC_URI_TEMPLATE_WIDTH_VAR)[0] + "?req=set,json"; 2667 request.open("GET", url, false); 2668 request.onload = function() { 2669 if (request.status >= 200 && request.status < 400) { 2670 // success status 2671 var responseText = request.responseText; 2672 var rePayload = new RegExp(/^(?:\/\*jsonp\*\/)?\s*([^()]+)\(([\s\S]+),\s*"[0-9]*"\);?$/gmi); 2673 var rePayloadJSON = new RegExp(/^{[\s\S]*}$/gmi); 2674 var resPayload = rePayload.exec(responseText); 2675 var payload; 2676 if (resPayload) { 2677 var payloadStr = resPayload[2]; 2678 if (rePayloadJSON.test(payloadStr)) { 2679 payload = JSON.parse(payloadStr); 2680 } 2681 2682 } 2683 // check "relation" - only in case of smartcrop preset 2684 if (payload && payload.set.relation && payload.set.relation.length > 0) { 2685 for (var i = 0; i < payload.set.relation.length; i++) { 2686 autoSmartCrops[parseInt(payload.set.relation[i].userdata.SmartCropWidth)] = 2687 ":" + payload.set.relation[i].userdata.SmartCropDef; 2688 } 2689 } 2690 } else { 2691 // error status 2692 } 2693 }; 2694 request.send(); 2695 return autoSmartCrops; 2696 }; 2697 2698 /** 2699 * Build and return the srcset value based on the available auto smart crops 2700 * @param {String} src the src uri 2701 * @param {Object} smartCrops the smart crops object 2702 * @returns {String} the srcset 2703 */ 2704 var getSrcSet = function(src, smartCrops) { 2705 var srcset; 2706 var keys = Object.keys(smartCrops); 2707 if (keys.length > 0) { 2708 srcset = []; 2709 for (var key in autoSmartCrops) { 2710 srcset.push(src.replace(SRC_URI_TEMPLATE_WIDTH_VAR, smartCrops[key]) + " " + key + "w"); 2711 } 2712 } 2713 return srcset.join(","); 2714 }; 2715 2716 /** 2717 * Get the optimal width based on the available sizes 2718 * @param {[Number]} sizes the available sizes 2719 * @param {Number} width the element width 2720 * @returns {String} the optimal width 2721 */ 2722 function getOptimalWidth(sizes, width) { 2723 var len = sizes.length; 2724 var key = 0; 2725 2726 while ((key < len - 1) && (sizes[key] < width)) { 2727 key++; 2728 } 2729 2730 return sizes[key] !== undefined ? sizes[key].toString() : width; 2731 } 2732 2733 /** 2734 * Get the width of an element or parent element if the width is smaller than the minimum width 2735 * @param {HTMLElement} component the image component 2736 * @param {HTMLElement | Node} parent the parent element 2737 * @returns {Number} the width of the element 2738 */ 2739 var getWidth = function(component, parent) { 2740 var width = component.offsetWidth; 2741 while (width < config.minWidth && parent && !component._autoWidth) { 2742 width = parent.offsetWidth; 2743 parent = parent.parentNode; 2744 } 2745 return width; 2746 }; 2747 2748 /** 2749 * Set the src and srcset attribute for a Dynamic Media Image which auto smart crops enabled. 2750 * @param {HTMLElement} component the image component 2751 * @param {{}} properties the component properties 2752 */ 2753 var setDMAttributes = function(component, properties) { 2754 // for v3 we first have to turn the dpr on
2755 var src = properties.src.replace(SRC_URI_DPR_OFF, SRC_URI_DPR_ON); 2756 src = src.replace(SRC_URI_TEMPLATE_DPR_VAR, dpr); 2757 var smartCrops = {}; 2758 var width; 2759 if (properties["smartcroprendition"] === "SmartCrop:Auto") { 2760 smartCrops = getAutoSmartCrops(src); 2761 } 2762 var hasWidths = (properties.widths && properties.widths.length > 0) || Object.keys(smartCrops).length > 0; 2763 if (hasWidths) { 2764 var image = component.querySelector("img"); 2765 var elemWidth = getWidth(component, component.parentNode); 2766 if (properties["smartcroprendition"] === "SmartCrop:Auto") { 2767 image.setAttribute("srcset", CMP.image.dynamicMedia.getSrcSet(src, smartCrops)); 2768 width = getOptimalWidth(Object.keys(smartCrops, elemWidth)); 2769 image.setAttribute("src", CMP.image.dynamicMedia.getSrc(src, smartCrops[width])); 2770 } else { 2771 width = getOptimalWidth(properties.widths, elemWidth); 2772 image.setAttribute("src", CMP.image.dynamicMedia.getSrc(src, width)); 2773 } 2774 } 2775 }; 2776 2777 /** 2778 * Get the src attribute based on the optimal width 2779 * @param {String} src the src uri 2780 * @param {String} width the element width 2781 * @returns {String} the final src attribute 2782 */ 2783 var getSrc = function(src, width) { 2784 if (src.indexOf(SRC_URI_TEMPLATE_WIDTH_VAR) > -1) { 2785 src = src.replace(SRC_URI_TEMPLATE_WIDTH_VAR, width); 2786 } 2787 return src; 2788 }; 2789 2790 2791 return { 2792 getAutoSmartCrops: getAutoSmartCrops, 2793 getSrcSet: getSrcSet, 2794 getSrc: getSrc, 2795 setDMAttributes: setDMAttributes, 2796 getWidth: getWidth 2797 }; 2798 }()); 2799 document.dispatchEvent(new CustomEvent("core.wcm.components.commons.site.image.dynamic-media.loaded")); 2800}(window.document)); 2801 2802/******************************************************************************* 2803 * Copyright 2022 Adobe 2804 * 2805 * Licensed under the Apache License, Version 2.0 (the "License"); 2806 * you may not use this file except in compliance with the License. 2807 * You may obtain a copy of the License at 2808 * 2809 * http://www.apache.org/licenses/LICENSE-2.0 2810 * 2811 * Unless required by applicable law or agreed to in writing, software 2812 * distributed under the License is distributed on an "AS IS" BASIS, 2813 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 2814 * See the License for the specific language governing permissions and 2815 * limitations under the License. 2816 ******************************************************************************/ 2817(function(document) { 2818 2819 "use strict"; 2820 2821 window.CMP = window.CMP || {}; 2822 window.CMP.image = window.CMP.image || {}; 2823 window.CMP.image.v3 = (function() { 2824 var IS = "image"; 2825 2826 var selectors = { 2827 self: "[data-cmp-hook-image='imageV3']" 2828 }; 2829 2830 var properties = { 2831 "widths": { 2832 "default": [], 2833 "transform": function(value) { 2834 var widths = []; 2835 value.split(",").forEach(function(item) { 2836 item = parseFloat(item); 2837 if (!isNaN(item)) { 2838 widths.push(item); 2839 } 2840 }); 2841 return widths; 2842 } 2843 }, 2844 "dmimage": { 2845 "default": false, 2846 "transform": function(value) { 2847 return !(value === null || typeof value === "undefined"); 2848 } 2849 }, 2850 "src": { 2851 "transform": function(value) { 2852 return decodeURIComponent(value); 2853 } 2854 }, 2855 "smartcroprendition": "" 2856 }; 2857 2858 function Image(config) { 2859 var that = this; 2860 /** 2861 * Init the image if the image is from dynamic media 2862 * @param {HTMLElement} component the image component 2863 */ 2864 that.initImage = function(component) { 2865 var options = CMP.utils.readData(component, IS); 2866 that._properties = CMP.utils.setupProperties(options, properties); 2867 if (that._properties.dmimage) { 2868 // use encoded src for dynamic media 2869 that._properties.src = options["src"]; 2870 CMP.image.dynamicMedia.setDMAttributes(component, that._properties); 2871 } 2872 }; 2873 that.initImage(config.element); 2874 } 2875 2876 return { 2877 init: function() { 2878 var elements = document.querySelectorAll(selectors.self); 2879 for (var i = 0; i < elements.length; i++) { 2880 new Image({ element: elements[i], options: CMP.utils.readData(elements[i], IS) }); 2881 } 2882 2883 var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver; 2884 var body = document.querySelector("body"); 2885 var observer = new MutationObserver(function(mutations) { 2886 mutations.forEach(function(mutation) { 2887 // needed for IE 2888 var nodesArray = [].slice.call(mutation.addedNodes); 2889 if (nodesArray.length > 0) { 2890 nodesArray.forEach(function(addedNode) { 2891 if (addedNode.querySelectorAll) { 2892 var elementsArray = [].slice.call(addedNode.querySelectorAll(selectors.self)); 2893 elementsArray.forEach(function(element) { 2894 new Image({ element: element, options: CMP.utils.readData(element, IS) }); 2895 }); 2896 } 2897 }); 2898 } 2899 }); 2900 }); 2901 2902 observer.observe(body, { 2903 subtree: true, 2904 childList: true, 2905 characterData: true 2906 }); 2907 } 2908 }; 2909 }()); 2910 2911 var documentReady = document.readyState !== "loading" ? Promise.resolve() : new Promise(function(resolve) { 2912 document.addEventListener("DOMContentLoaded", resolve); 2913 }); 2914 Promise.all([documentReady]).then(window.CMP.image.v3.init); 2915}(window.document)); 2916 2917 2918/******************************************************************************* 2919 * Copyright 2022 Adobe 2920 * 2921 * Licensed under the Apache License, Version 2.0 (the "License");
2922 * you may not use this file except in compliance with the License. 2923 * You may obtain a copy of the License at 2924 * 2925 * http://www.apache.org/licenses/LICENSE-2.0 2926 * 2927 * Unless required by applicable law or agreed to in writing, software 2928 * distributed under the License is distributed on an "AS IS" BASIS, 2929 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 2930 * See the License for the specific language governing permissions and 2931 * limitations under the License. 2932 ******************************************************************************/ 2933(function() { 2934 "use strict"; 2935 2936 var NS = "cmp"; 2937 var IS = "search"; 2938 2939 var DELAY = 300; // time before fetching new results when the user is typing a search string 2940 var LOADING_DISPLAY_DELAY = 300; // minimum time during which the loading indicator is displayed 2941 var PARAM_RESULTS_OFFSET = "resultsOffset"; 2942 2943 var keyCodes = { 2944 TAB: 9, 2945 ENTER: 13, 2946 ESCAPE: 27, 2947 ARROW_UP: 38, 2948 ARROW_DOWN: 40 2949 }; 2950 2951 var selectors = { 2952 self: "[data-" + NS + '-is="' + IS + '"]', 2953 item: { 2954 self: "[data-" + NS + "-hook-" + IS + '="item"]', 2955 title: "[data-" + NS + "-hook-" + IS + '="itemTitle"]', 2956 focused: "." + NS + "-search__item--is-focused" 2957 } 2958 }; 2959 2960 var properties = { 2961 /** 2962 * The minimum required length of the search term before results are fetched. 2963 * 2964 * @memberof Search 2965 * @type {Number} 2966 * @default 3 2967 */ 2968 minLength: { 2969 "default": 3, 2970 transform: function(value) { 2971 value = parseFloat(value); 2972 return isNaN(value) ? null : value; 2973 } 2974 }, 2975 /** 2976 * The maximal number of results fetched by a search request. 2977 * 2978 * @memberof Search 2979 * @type {Number} 2980 * @default 10 2981 */ 2982 resultsSize: { 2983 "default": 10, 2984 transform: function(value) { 2985 value = parseFloat(value); 2986 return isNaN(value) ? null : value; 2987 } 2988 } 2989 }; 2990 2991 var idCount = 0; 2992 2993 function readData(element) { 2994 var data = element.dataset; 2995 var options = []; 2996 var capitalized = IS; 2997 capitalized = capitalized.charAt(0).toUpperCase() + capitalized.slice(1); 2998 var reserved = ["is", "hook" + capitalized]; 2999 3000 for (var key in data) { 3001 if (Object.prototype.hasOwnProperty.call(data, key)) { 3002 var value = data[key]; 3003 3004 if (key.indexOf(NS) === 0) { 3005 key = key.slice(NS.length); 3006 key = key.charAt(0).toLowerCase() + key.substring(1); 3007 3008 if (reserved.indexOf(key) === -1) { 3009 options[key] = value; 3010 } 3011 } 3012 } 3013 } 3014 3015 return options; 3016 } 3017 3018 function toggleShow(element, show) { 3019 if (element) { 3020 if (show !== false) { 3021 element.style.display = "block"; 3022 element.setAttribute("aria-hidden", false); 3023 } else { 3024 element.style.display = "none"; 3025 element.setAttribute("aria-hidden", true); 3026 } 3027 } 3028 } 3029 3030 function serialize(form) { 3031 var query = []; 3032 if (form && form.elements) { 3033 for (var i = 0; i < form.elements.length; i++) { 3034 var node = form.elements[i]; 3035 if (!node.disabled && node.name) { 3036 var param = [node.name, encodeURIComponent(node.value)]; 3037 query.push(param.join("=")); 3038 } 3039 } 3040 } 3041 return query.join("&"); 3042 } 3043 3044 function mark(node, regex) { 3045 if (!node || !regex) { 3046 return; 3047 } 3048 3049 // text nodes 3050 if (node.nodeType === 3) { 3051 var nodeValue = node.nodeValue; 3052 var match = regex.exec(nodeValue); 3053 3054 if (nodeValue && match) { 3055 var element = document.createElement("mark"); 3056 element.className = NS + "-search__item-mark"; 3057 element.appendChild(document.createTextNode(match[0])); 3058 3059 var after = node.splitText(match.index); 3060 after.nodeValue = after.nodeValue.substring(match[0].length); 3061 node.parentNode.insertBefore(element, after); 3062 } 3063 } else if (node.hasChildNodes()) { 3064 for (var i = 0; i < node.childNodes.length; i++) { 3065 // recurse 3066 mark(node.childNodes[i], regex); 3067 } 3068 } 3069 } 3070 3071 function localizeMessage(searchElementId, message, values = []) { 3072 const i18nMessages = JSON.parse(document.querySelector("#" + searchElementId).getAttribute("data-i18n-messages")); 3073 let translation = i18nMessages[message]; 3074 // Insert values 3075 if (values.length > 0) { 3076 translation = translation.replace(/{(\d+)}/g, function(match, index) { 3077 return typeof values[index] !== "undefined" ? values[index] : match; 3078 }); 3079 } 3080 return translation; 3081 } 3082 3083 // useful for Accessibility, helping users with low vision and users with cognitive disabilities to identify the change in results 3084 function updateSearchResultsStatusMessageElement(searchElementId, totalResults) { 3085 var searchResultsStatusMessage = document.querySelector("#" + searchElementId + "> .cmp_search__info"); 3086 searchResultsStatusMessage.style.visibility = "visible"; 3087 var searchResultsFoundMessage = localizeMessage(searchElementId, totalResults === 1 ? "{0} result" : "{0} results", [totalResults]); 3088 var searchResultsNotFoundMessage = localizeMessage(searchElementId, "No results"); 3089 searchResultsStatusMessage.innerText = totalResults > 0 ? searchResultsFoundMessage : searchResultsNotFoundMessage; 3090 } 3091 3092 function Search(config) { 3093 if (config.element) { 3094 // prevents multiple initialization 3095 config.element.removeAttribute("data-" + NS + "-is"); 3096 } 3097 3098 this._cacheElements(config.element); 3099 this._setupProperties(config.options); 3100 3101 this._action = this._elements.form.getAttribute("action"); 3102 this._resultsOffset = 0; 3103 this._hasMoreResults = true; 3104 3105 this._elements.input.addEventListener("input", this._onInput.bind(this)); 3106 this._elements.input.addEventListener("focus", this._onInput.bind(this)); 3107 this._elements.input.addEventListener("keydown", this._onKeydown.bind(this)); 3108 this._elements.clear.addEventListener("click", this._onClearClick.bind(this)); 3109 document.addEventListener("click", this._onDocumentClick.bind(this)); 3110 this._elements.results.addEventListener("scroll", this._onScroll.bind(this)); 3111 3112 this._makeAccessible(); 3113 } 3114 3115 Search.prototype._displayResults = function() { 3116 if (this._elements.input.value.length === 0) { 3117 toggleShow(this._elements.clear, false); 3118 this._cancelResults(); 3119 } else if (this._elements.input.value.length < this._properties.minLength) { 3120 toggleShow(this._elements.clear, true); 3121 } else { 3122 this._updateResults(); 3123 toggleShow(this._elements.clear, true); 3124 } 3125 }; 3126 3127 Search.prototype._onScroll = function(event) { 3128 // fetch new results when the results to be scrolled down are less than the visible results 3129 if (this._elements.results.scrollTop + 2 * this._elements.results.clientHeight >= this._elements.results.scrollHeight) { 3130 this._resultsOffset += this._properties.resultsSize; 3131 this._displayResults(); 3132 } 3133 }; 3134 3135 Search.prototype._onInput = function(event) { 3136 var self = this; 3137 self._cancelResults(); 3138 // start searching when the search term reaches the minimum length 3139 this._timeout = setTimeout(function() { 3140 self._displayResults(); 3141 }, DELAY); 3142 }; 3143 3144 Search.prototype._onKeydown = function(event) { 3145 var self = this; 3146 3147 switch (event.keyCode) { 3148 case keyCodes.TAB: 3149 if (self._resultsOpen()) { 3150 toggleShow(self._elements.results, false); 3151 self._elements.input.setAttribute("aria-expanded", "false"); 3152 this._hideSearchResultsStatusMessage(); 3153 } 3154 break;
3155 case keyCodes.ENTER: 3156 event.preventDefault(); 3157 if (self._resultsOpen()) { 3158 var focused = self._elements.results.querySelector(selectors.item.focused); 3159 if (focused) { 3160 focused.click(); 3161 } 3162 } 3163 break; 3164 case keyCodes.ESCAPE: 3165 self._cancelResults(); 3166 break; 3167 case keyCodes.ARROW_UP: 3168 if (self._resultsOpen()) { 3169 event.preventDefault(); 3170 self._stepResultFocus(true); 3171 } 3172 break; 3173 case keyCodes.ARROW_DOWN: 3174 if (self._resultsOpen()) { 3175 event.preventDefault(); 3176 self._stepResultFocus(); 3177 } else { 3178 // test the input and if necessary fetch and display the results 3179 self._onInput(); 3180 } 3181 break; 3182 default: 3183 return; 3184 } 3185 }; 3186 3187 Search.prototype._onClearClick = function(event) { 3188 event.preventDefault(); 3189 this._elements.input.value = ""; 3190 toggleShow(this._elements.clear, false); 3191 toggleShow(this._elements.results, false); 3192 this._elements.input.setAttribute("aria-expanded", "false"); 3193 this._hideSearchResultsStatusMessage(); 3194 }; 3195 3196 Search.prototype._onDocumentClick = function(event) { 3197 var inputContainsTarget = this._elements.input.contains(event.target); 3198 var resultsContainTarget = this._elements.results.contains(event.target); 3199 3200 if (!(inputContainsTarget || resultsContainTarget)) { 3201 toggleShow(this._elements.results, false); 3202 this._elements.input.setAttribute("aria-expanded", "false"); 3203 this._hideSearchResultsStatusMessage(); 3204 } 3205 }; 3206 3207 Search.prototype._resultsOpen = function() { 3208 return this._elements.results.style.display !== "none"; 3209 }; 3210 3211 Search.prototype._makeAccessible = function() { 3212 var id = NS + "-search-results-" + idCount; 3213 this._elements.input.setAttribute("aria-owns", id); 3214 this._elements.results.id = id; 3215 idCount++; 3216 }; 3217 3218 Search.prototype._generateItems = function(data, results) { 3219 var self = this; 3220 3221 data.forEach(function(item) { 3222 var el = document.createElement("span"); 3223 el.innerHTML = self._elements.itemTemplate.innerHTML; 3224 el.querySelectorAll(selectors.item.title)[0].appendChild(document.createTextNode(item.title)); 3225 el.querySelectorAll(selectors.item.self)[0].setAttribute("href", self._safeHref(item.url)); 3226 results.innerHTML += el.innerHTML; 3227 }); 3228 }; 3229 3230 Search.prototype._safeHref = function(href) { 3231 var a = document.createElement("a"); 3232 a.href = href; 3233 return a.pathname; 3234 }; 3235 3236 Search.prototype._markResults = function() { 3237 var nodeList = this._elements.results.querySelectorAll(selectors.item.self); 3238 var escapedTerm = this._elements.input.value.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"); 3239 var regex = new RegExp("(" + escapedTerm + ")", "gi"); 3240 3241 for (var i = this._resultsOffset - 1; i < nodeList.length; ++i) { 3242 var result = nodeList[i]; 3243 mark(result, regex); 3244 } 3245 }; 3246 3247 Search.prototype._stepResultFocus = function(reverse) { 3248 var results = this._elements.results.querySelectorAll(selectors.item.self); 3249 var focused = this._elements.results.querySelector(selectors.item.focused); 3250 var newFocused; 3251 var index = Array.prototype.indexOf.call(results, focused); 3252 var focusedCssClass = NS + "-search__item--is-focused"; 3253 3254 if (results.length > 0) { 3255 3256 if (!reverse) { 3257 // highlight the next result 3258 if (index < 0) { 3259 results[0].classList.add(focusedCssClass); 3260 results[0].setAttribute("aria-selected", "true"); 3261 } else if (index + 1 < results.length) { 3262 results[index].classList.remove(focusedCssClass); 3263 results[index].setAttribute("aria-selected", "false"); 3264 results[index + 1].classList.add(focusedCssClass); 3265 results[index + 1].setAttribute("aria-selected", "true"); 3266 } 3267 3268 // if the last visible result is partially hidden, scroll up until it's completely visible 3269 newFocused = this._elements.results.querySelector(selectors.item.focused); 3270 if (newFocused) { 3271 var bottomHiddenHeight = newFocused.offsetTop + newFocused.offsetHeight - this._elements.results.scrollTop - this._elements.results.clientHeight; 3272 if (bottomHiddenHeight > 0) { 3273 this._elements.results.scrollTop += bottomHiddenHeight; 3274 } else { 3275 this._onScroll(); 3276 } 3277 } 3278 3279 } else { 3280 // highlight the previous result 3281 if (index >= 1) { 3282 results[index].classList.remove(focusedCssClass); 3283 results[index].setAttribute("aria-selected", "false"); 3284 results[index - 1].classList.add(focusedCssClass); 3285 results[index - 1].setAttribute("aria-selected", "true"); 3286 } 3287 3288 // if the first visible result is partially hidden, scroll down until it's completely visible 3289 newFocused = this._elements.results.querySelector(selectors.item.focused); 3290 if (newFocused) { 3291 var topHiddenHeight = this._elements.results.scrollTop - newFocused.offsetTop; 3292 if (topHiddenHeight > 0) { 3293 this._elements.results.scrollTop -= topHiddenHeight; 3294 } 3295 } 3296 } 3297 } 3298 }; 3299 3300 Search.prototype._updateResults = function() { 3301 var self = this; 3302 if (self._hasMoreResults) { 3303 var request = new XMLHttpRequest(); 3304 var url = self._action + "?" + serialize(self._elements.form) + "&" + PARAM_RESULTS_OFFSET + "=" + self._resultsOffset; 3305 3306 request.open("GET", url, true); 3307 request.onload = function() { 3308 // when the results are loaded: hide the loading indicator and display the search icon after a minimum period 3309 setTimeout(function() { 3310 toggleShow(self._elements.loadingIndicator, false); 3311 toggleShow(self._elements.icon, true); 3312 }, LOADING_DISPLAY_DELAY); 3313 if (request.status >= 200 && request.status < 400) { 3314 // success status 3315 var data = JSON.parse(request.responseText); 3316 updateSearchResultsStatusMessageElement(self._elements.self.id, data.length); 3317 if (data.length > 0) { 3318 self._generateItems(data, self._elements.results); 3319 self._markResults(); 3320 toggleShow(self._elements.results, true); 3321 self._elements.input.setAttribute("aria-expanded", "true"); 3322 } else { 3323 self._hasMoreResults = false;
3324 } 3325 // the total number of results is not a multiple of the fetched results: 3326 // -> we reached the end of the query 3327 if (self._elements.results.querySelectorAll(selectors.item.self).length % self._properties.resultsSize > 0) { 3328 self._hasMoreResults = false; 3329 } 3330 } else { 3331 // error status 3332 } 3333 }; 3334 // when the results are loading: display the loading indicator and hide the search icon 3335 toggleShow(self._elements.loadingIndicator, true); 3336 toggleShow(self._elements.icon, false); 3337 request.send(); 3338 } 3339 }; 3340 3341 Search.prototype._cancelResults = function() { 3342 clearTimeout(this._timeout); 3343 this._elements.results.scrollTop = 0; 3344 this._resultsOffset = 0; 3345 this._hasMoreResults = true; 3346 this._elements.results.innerHTML = ""; 3347 this._elements.input.setAttribute("aria-expanded", "false"); 3348 this._hideSearchResultsStatusMessage(); 3349 }; 3350 3351 Search.prototype._hideSearchResultsStatusMessage = function() { 3352 var searchResultsStatusMessage = document.querySelector("#" + this._elements.self.id + "> .cmp_search__info"); 3353 searchResultsStatusMessage.style.visibility = "hidden"; 3354 }; 3355 3356 Search.prototype._cacheElements = function(wrapper) { 3357 this._elements = {}; 3358 this._elements.self = wrapper; 3359 var hooks = this._elements.self.querySelectorAll("[data-" + NS + "-hook-" + IS + "]"); 3360 3361 for (var i = 0; i < hooks.length; i++) { 3362 var hook = hooks[i]; 3363 var capitalized = IS; 3364 capitalized = capitalized.charAt(0).toUpperCase() + capitalized.slice(1); 3365 var key = hook.dataset[NS + "Hook" + capitalized]; 3366 this._elements[key] = hook; 3367 } 3368 }; 3369 3370 Search.prototype._setupProperties = function(options) { 3371 this._properties = {}; 3372 3373 for (var key in properties) { 3374 if (Object.prototype.hasOwnProperty.call(properties, key)) { 3375 var property = properties[key]; 3376 if (options && options[key] != null) { 3377 if (property && typeof property.transform === "function") { 3378 this._properties[key] = property.transform(options[key]); 3379 } else { 3380 this._properties[key] = options[key]; 3381 } 3382 } else { 3383 this._properties[key] = properties[key]["default"]; 3384 } 3385 } 3386 } 3387 }; 3388 3389 function onDocumentReady() { 3390 var elements = document.querySelectorAll(selectors.self); 3391 for (var i = 0; i < elements.length; i++) { 3392 new Search({ element: elements[i], options: readData(elements[i]) }); 3393 } 3394 3395 var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver; 3396 var body = document.querySelector("body"); 3397 var observer = new MutationObserver(function(mutations) { 3398 mutations.forEach(function(mutation) { 3399 // needed for IE 3400 var nodesArray = [].slice.call(mutation.addedNodes); 3401 if (nodesArray.length > 0) { 3402 nodesArray.forEach(function(addedNode) { 3403 if (addedNode.querySelectorAll) { 3404 var elementsArray = [].slice.call(addedNode.querySelectorAll(selectors.self)); 3405 elementsArray.forEach(function(element) { 3406 new Search({ element: element, options: readData(element) }); 3407 }); 3408 } 3409 }); 3410 } 3411 }); 3412 }); 3413 3414 observer.observe(body, { 3415 subtree: true, 3416 childList: true, 3417 characterData: true 3418 }); 3419 } 3420 3421 if (document.readyState !== "loading") { 3422 onDocumentReady(); 3423 } else { 3424 document.addEventListener("DOMContentLoaded", onDocumentReady); 3425 } 3426 3427})(); 3428 3429 3430/******************************************************************************* 3431 * Copyright 2016 Adobe 3432 * 3433 * Licensed under the Apache License, Version 2.0 (the "License");
3434 * you may not use this file except in compliance with the License. 3435 * You may obtain a copy of the License at 3436 * 3437 * http://www.apache.org/licenses/LICENSE-2.0 3438 * 3439 * Unless required by applicable law or agreed to in writing, software 3440 * distributed under the License is distributed on an "AS IS" BASIS, 3441 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 3442 * See the License for the specific language governing permissions and 3443 * limitations under the License. 3444 ******************************************************************************/ 3445(function() { 3446 "use strict"; 3447 3448 var NS = "cmp"; 3449 var IS = "formText"; 3450 var IS_DASH = "form-text"; 3451 var SELF_SELECTOR = "[data-" + NS + '-is="' + IS + '"]'; 3452 3453 var selectors = { 3454 self: SELF_SELECTOR, 3455 validationMessage: SELF_SELECTOR + " .cmp-form-text__validation-message" 3456 }; 3457 3458 var displayValidationMessage = false; 3459 3460 var properties = { 3461 /** 3462 * A validation message to display if there is a type mismatch between the user input and expected input. 3463 * 3464 * @type {String} 3465 */ 3466 constraintMessage: "", 3467 /** 3468 * A validation message to display if no input is supplied, but input is expected for the field. 3469 * 3470 * @type {String} 3471 */ 3472 requiredMessage: "" 3473 }; 3474 3475 function readData(element) { 3476 var data = element.dataset; 3477 var options = []; 3478 var capitalized = IS; 3479 capitalized = capitalized.charAt(0).toUpperCase() + capitalized.slice(1); 3480 var reserved = ["is", "hook" + capitalized]; 3481 3482 for (var key in data) { 3483 if (Object.prototype.hasOwnProperty.call(data, key)) { 3484 var value = data[key]; 3485 3486 if (key.indexOf(NS) === 0) { 3487 key = key.slice(NS.length); 3488 key = key.charAt(0).toLowerCase() + key.substring(1); 3489 3490 if (reserved.indexOf(key) === -1) { 3491 options[key] = value; 3492 } 3493 } 3494 } 3495 } 3496 3497 return options; 3498 } 3499 3500 function FormText(config) { 3501 if (config.element) { 3502 // prevents multiple initialization 3503 config.element.removeAttribute("data-" + NS + "-is"); 3504 } 3505 3506 this._cacheElements(config.element); 3507 this._setupProperties(config.options); 3508 3509 this._elements.input.addEventListener("invalid", this._onInvalid.bind(this)); 3510 this._elements.input.addEventListener("input", this._onInput.bind(this)); 3511 if (displayValidationMessage) { 3512 this._elements.input.checkValidity(); 3513 } 3514 } 3515 3516 FormText.prototype._onInvalid = function(event) { 3517 event.target.setCustomValidity(""); 3518 if (event.target.validity.typeMismatch) { 3519 if (this._properties.constraintMessage) { 3520 event.target.setCustomValidity(this._properties.constraintMessage); 3521 } 3522 } else if (event.target.validity.valueMissing) { 3523 if (this._properties.requiredMessage) { 3524 event.target.setCustomValidity(this._properties.requiredMessage); 3525 } 3526 } 3527 if (displayValidationMessage) { 3528 var validationMessage = event.target.parentElement.querySelector(".cmp-form-text__validation-message"); 3529 if (validationMessage) { 3530 validationMessage.innerText = event.target.validationMessage; 3531 } 3532 } 3533 }; 3534 3535 FormText.prototype._onInput = function(event) { 3536 event.target.setCustomValidity(""); 3537 if (displayValidationMessage) { 3538 event.target.checkValidity(); 3539 } 3540 }; 3541 3542 FormText.prototype._cacheElements = function(wrapper) { 3543 this._elements = {}; 3544 this._elements.self = wrapper; 3545 var hooks = this._elements.self.querySelectorAll("[data-" + NS + "-hook-" + IS_DASH + "]"); 3546 for (var i = 0; i < hooks.length; i++) { 3547 var hook = hooks[i]; 3548 var capitalized = IS; 3549 capitalized = capitalized.charAt(0).toUpperCase() + capitalized.slice(1); 3550 var key = hook.dataset[NS + "Hook" + capitalized]; 3551 this._elements[key] = hook; 3552 } 3553 }; 3554 3555 FormText.prototype._setupProperties = function(options) { 3556 this._properties = {}; 3557 3558 for (var key in properties) { 3559 if (Object.prototype.hasOwnProperty.call(properties, key)) { 3560 var property = properties[key]; 3561 if (options && options[key] != null) { 3562 if (property && typeof property.transform === "function") { 3563 this._properties[key] = property.transform(options[key]); 3564 } else { 3565 this._properties[key] = options[key]; 3566 } 3567 } else { 3568 this._properties[key] = properties[key]["default"]; 3569 } 3570 } 3571 } 3572 }; 3573 3574 function onDocumentReady() {
3575 var validationMessages = document.querySelectorAll(selectors.validationMessage); 3576 if (validationMessages && validationMessages.length > 0) { 3577 displayValidationMessage = true; 3578 } 3579 3580 var elements = document.querySelectorAll(selectors.self); 3581 for (var i = 0; i < elements.length; i++) { 3582 new FormText({ element: elements[i], options: readData(elements[i]) }); 3583 } 3584 3585 var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver; 3586 var body = document.querySelector("body"); 3587 var observer = new MutationObserver(function(mutations) { 3588 mutations.forEach(function(mutation) { 3589 // needed for IE 3590 var nodesArray = [].slice.call(mutation.addedNodes); 3591 if (nodesArray.length > 0) { 3592 nodesArray.forEach(function(addedNode) { 3593 if (addedNode.querySelectorAll) { 3594 var elementsArray = [].slice.call(addedNode.querySelectorAll(selectors.self)); 3595 elementsArray.forEach(function(element) { 3596 new FormText({ element: element, options: readData(element) }); 3597 }); 3598 } 3599 }); 3600 } 3601 }); 3602 }); 3603 3604 observer.observe(body, { 3605 subtree: true, 3606 childList: true, 3607 characterData: true 3608 }); 3609 } 3610 3611 if (document.readyState !== "loading") { 3612 onDocumentReady(); 3613 } else { 3614 document.addEventListener("DOMContentLoaded", onDocumentReady); 3615 } 3616 3617})(); 3618 3619 3620/******************************************************************************* 3621 * Copyright 2020 Adobe 3622 * 3623 * Licensed under the Apache License, Version 2.0 (the "License"); 3624 * you may not use this file except in compliance with the License. 3625 * You may obtain a copy of the License at 3626 * 3627 * http://www.apache.org/licenses/LICENSE-2.0 3628 * 3629 * Unless required by applicable law or agreed to in writing, software 3630 * distributed under the License is distributed on an "AS IS" BASIS, 3631 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 3632 * See the License for the specific language governing permissions and 3633 * limitations under the License. 3634 ******************************************************************************/ 3635(function () { 3636 "use strict"; 3637 3638 var NS = "cmp"; 3639 var IS = "pdfviewer"; 3640 var SDK_URL = "https://documentservices.adobe.com/view-sdk/viewer.js"; 3641 var SDK_READY_EVENT = "adobe_dc_view_sdk.ready"; 3642 3643 var selectors = { 3644 self: "[data-" + NS + '-is="' + IS + '"]', 3645 sdkScript: 'script[src="' + SDK_URL + '"]' 3646 }; 3647 3648 function initSDK() { 3649 var sdkIncluded = $(selectors.sdkScript).length > 0; 3650 if (!window.adobe_dc_view_sdk && !sdkIncluded) { 3651 var dcv = document.createElement("script"); 3652 dcv.type = "text/javascript"; 3653 dcv.src = SDK_URL; 3654 document.body.appendChild(dcv); 3655 } 3656 } 3657 3658 function previewPdf(component) { 3659 var $component = $(component); 3660 3661 // prevents multiple initialization 3662 $component.removeAttr("data-" + NS + "-is"); 3663 3664 // add the view sdk to the page 3665 initSDK(); 3666 3667 // manage the preview 3668 if ($component.data() && component.id) { 3669 if (window.AdobeDC && window.AdobeDC.View) { 3670 dcView(component); 3671 } else { 3672 document.addEventListener(SDK_READY_EVENT, function () { 3673 dcView(component); 3674 }); 3675 } 3676 } 3677 } 3678 3679 function dcView(component) { 3680 var adobeDCView = new window.AdobeDC.View({ 3681 clientId: component.dataset.cmpClientId, 3682 divId: component.id + "-content", 3683 locale: navigator.language, 3684 reportSuiteId: component.dataset.cmpReportSuiteId 3685 }); 3686 3687 let viewerConfig; 3688 try { 3689 viewerConfig = JSON.parse(component.dataset.cmpViewerConfigJson); 3690 } catch (e) { 3691 console.error("Errore nel parsing di cmpViewerConfigJson:", e); 3692 return; 3693 } 3694 adobeDCView.previewFile({ 3695 content: { location: { url: component.dataset.cmpDocumentPath } }, 3696 metaData: { fileName: component.dataset.cmpDocumentFileName } 3697 }, viewerConfig); 3698 } 3699 3700 function onDocumentReady() { 3701 // Inizializza i pdfviewer presenti al caricamento 3702 $(selectors.self).each(function () { 3703 previewPdf(this); 3704 }); 3705 3706 // Observer per elementi aggiunti dinamicamente 3707 var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver; 3708 var observer = new MutationObserver(function (mutations) { 3709 mutations.forEach(function (mutation) { 3710 $(mutation.addedNodes).each(function () { 3711 var $node = $(this); 3712 if ($node.find) { 3713 $node.find(selectors.self).each(function () { 3714 previewPdf(this); 3715 }); 3716 } 3717 }); 3718 }); 3719 }); 3720 3721 observer.observe(document.body, { 3722 subtree: true, 3723 childList: true, 3724 characterData: true 3725 }); 3726 } 3727 3728 if (document.readyState !== "loading") { 3729 onDocumentReady(); 3730 } else { 3731 $(document).ready(onDocumentReady); 3732 } 3733})(); 3734 3735 3736 3737/******************************************************************************* 3738 * Copyright 2022 Adobe 3739 * 3740 * Licensed under the Apache License, Version 2.0 (the "License");
3741 * you may not use this file except in compliance with the License. 3742 * You may obtain a copy of the License at 3743 * 3744 * http://www.apache.org/licenses/LICENSE-2.0 3745 * 3746 * Unless required by applicable law or agreed to in writing, software 3747 * distributed under the License is distributed on an "AS IS" BASIS, 3748 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 3749 * See the License for the specific language governing permissions and 3750 * limitations under the License. 3751 ******************************************************************************/ 3752(function() { 3753 "use strict"; 3754 3755 var dataLayerEnabled; 3756 var dataLayer; 3757 var dataLayerName; 3758 3759 /** 3760 * Adds Click Event Listener to the main <div> of the Text Components 3761 */ 3762 function addClickEventListenerToTextComponents() { 3763 var componentMainDivs = document.getElementsByClassName("cmp-text"); 3764 3765 for (var i = 0; i < componentMainDivs.length; i++) { 3766 componentMainDivs[i].addEventListener("click", addClickedLinkToDataLayer); 3767 } 3768 } 3769 3770 /** 3771 * Adds clicked link contained by the Text Component to Data Layer 3772 * 3773 * @private 3774 * @param {Object} event The Click event 3775 */ 3776 function addClickedLinkToDataLayer(event) { 3777 var element = event.currentTarget; 3778 var componentId = getDataLayerId(element); 3779 3780 if (event.target.tagName === "A") { 3781 dataLayer.push({ 3782 event: "cmp:click", 3783 eventInfo: { 3784 path: "component." + componentId, 3785 link: event.target.getAttribute("href") 3786 } 3787 }); 3788 } 3789 } 3790 3791 /** 3792 * Parses the dataLayer string and returns the ID 3793 * 3794 * @private 3795 * @param {HTMLElement} item, the Text item 3796 * @returns {String} dataLayerId or undefined 3797 */ 3798 function getDataLayerId(item) { 3799 if (item) { 3800 if (item.dataset.cmpDataLayer) { 3801 return Object.keys(JSON.parse(item.dataset.cmpDataLayer))[0]; 3802 } else { 3803 return item.id; 3804 } 3805 } 3806 return null; 3807 } 3808 3809 function onDocumentReady() { 3810 dataLayerEnabled = document.body.hasAttribute("data-cmp-data-layer-enabled"); 3811 if (dataLayerEnabled) { 3812 dataLayerName = document.body.getAttribute("data-cmp-data-layer-name") || "adobeDataLayer"; 3813 dataLayer = window[dataLayerName] = window[dataLayerName] || []; 3814 3815 addClickEventListenerToTextComponents(); 3816 } 3817 } 3818 3819 if (document.readyState !== "loading") { 3820 onDocumentReady(); 3821 } else { 3822 document.addEventListener("DOMContentLoaded", onDocumentReady); 3823 } 3824})(); 3825 3826 3827/******/ (() => { // webpackBootstrap 3828/******/ var __webpack_modules__ = ({ 3829 3830/***/ 889: 3831/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { 3832 3833 "use strict"; 3834 __webpack_require__.r(__webpack_exports__); 3835 /* harmony export */ __webpack_require__.d(__webpack_exports__, { 3836 /* harmony export */ BotInfo: () => (/* binding */ BotInfo), 3837 /* harmony export */ BrowserInfo: () => (/* binding */ BrowserInfo), 3838 /* harmony export */ NodeInfo: () => (/* binding */ NodeInfo), 3839 /* harmony export */ ReactNativeInfo: () => (/* binding */ ReactNativeInfo), 3840 /* harmony export */ SearchBotDeviceInfo: () => (/* binding */ SearchBotDeviceInfo), 3841 /* harmony export */ browserName: () => (/* binding */ browserName), 3842 /* harmony export */ detect: () => (/* binding */ detect), 3843 /* harmony export */ detectOS: () => (/* binding */ detectOS), 3844 /* harmony export */ getNodeVersion: () => (/* binding */ getNodeVersion), 3845 /* harmony export */ parseUserAgent: () => (/* binding */ parseUserAgent) 3846 /* harmony export */ }); 3847 var __spreadArray = (undefined && undefined.__spreadArray) || function (to, from, pack) { 3848 if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { 3849 if (ar || !(i in from)) { 3850 if (!ar) ar = Array.prototype.slice.call(from, 0, i); 3851 ar[i] = from[i]; 3852 } 3853 } 3854 return to.concat(ar || Array.prototype.slice.call(from)); 3855 }; 3856 var BrowserInfo = /** @class */ (function () { 3857 function BrowserInfo(name, version, os) { 3858 this.name = name; 3859 this.version = version; 3860 this.os = os; 3861 this.type = 'browser'; 3862 } 3863 return BrowserInfo; 3864 }()); 3865 3866 var NodeInfo = /** @class */ (function () { 3867 function NodeInfo(version) { 3868 this.version = version; 3869 this.type = 'node'; 3870 this.name = 'node'; 3871 this.os = process.platform; 3872 } 3873 return NodeInfo; 3874 }()); 3875 3876 var SearchBotDeviceInfo = /** @class */ (function () { 3877 function SearchBotDeviceInfo(name, version, os, bot) { 3878 this.name = name; 3879 this.version = version; 3880 this.os = os; 3881 this.bot = bot; 3882 this.type = 'bot-device'; 3883 } 3884 return SearchBotDeviceInfo; 3885 }()); 3886 3887 var BotInfo = /** @class */ (function () { 3888 function BotInfo() { 3889 this.type = 'bot'; 3890 this.bot = true; // NOTE: deprecated test name instead 3891 this.name = 'bot'; 3892 this.version = null; 3893 this.os = null; 3894 } 3895 return BotInfo; 3896 }()); 3897 3898 var ReactNativeInfo = /** @class */ (function () { 3899 function ReactNativeInfo() { 3900 this.type = 'react-native'; 3901 this.name = 'react-native'; 3902 this.version = null; 3903 this.os = null; 3904 } 3905 return ReactNativeInfo; 3906 }()); 3907 3908 // tslint:disable-next-line:max-line-length 3909 var SEARCHBOX_UA_REGEX = /alexa|bot|crawl(er|ing)|facebookexternalhit|feedburner|google web preview|nagios|postrank|pingdom|slurp|spider|yaho
vendor: 4,112 bytes, lines 3909-4021
3909o!|yandex/; 3910 var SEARCHBOT_OS_REGEX = /(nuhk|curl|Googlebot|Yammybot|Openbot|Slurp|MSNBot|Ask\ Jeeves\/Teoma|ia_archiver)/; 3911 var REQUIRED_VERSION_PARTS = 3; 3912 var userAgentRules = [ 3913 ['aol', /AOLShield\/([0-9\._]+)/], 3914 ['edge', /Edge\/([0-9\._]+)/], 3915 ['edge-ios', /EdgiOS\/([0-9\._]+)/], 3916 ['yandexbrowser', /YaBrowser\/([0-9\._]+)/], 3917 ['kakaotalk', /KAKAOTALK\s([0-9\.]+)/], 3918 ['samsung', /SamsungBrowser\/([0-9\.]+)/], 3919 ['silk', /\bSilk\/([0-9._-]+)\b/], 3920 ['miui', /MiuiBrowser\/([0-9\.]+)$/], 3921 ['beaker', /BeakerBrowser\/([0-9\.]+)/], 3922 ['edge-chromium', /EdgA?\/([0-9\.]+)/], 3923 [ 3924 'chromium-webview', 3925 /(?!Chrom.*OPR)wv\).*Chrom(?:e|ium)\/([0-9\.]+)(:?\s|$)/, 3926 ], 3927 ['chrome', /(?!Chrom.*OPR)Chrom(?:e|ium)\/([0-9\.]+)(:?\s|$)/], 3928 ['phantomjs', /PhantomJS\/([0-9\.]+)(:?\s|$)/], 3929 ['crios', /CriOS\/([0-9\.]+)(:?\s|$)/], 3930 ['firefox', /Firefox\/([0-9\.]+)(?:\s|$)/], 3931 ['fxios', /FxiOS\/([0-9\.]+)/], 3932 ['opera-mini', /Opera Mini.*Version\/([0-9\.]+)/], 3933 ['opera', /Opera\/([0-9\.]+)(?:\s|$)/], 3934 ['opera', /OPR\/([0-9\.]+)(:?\s|$)/], 3935 ['pie', /^Microsoft Pocket Internet Explorer\/(\d+\.\d+)$/], 3936 ['pie', /^Mozilla\/\d\.\d+\s\(compatible;\s(?:MSP?IE|MSInternet Explorer) (\d+\.\d+);.*Windows CE.*\)$/], 3937 ['netfront', /^Mozilla\/\d\.\d+.*NetFront\/(\d.\d)/], 3938 ['ie', /Trident\/7\.0.*rv\:([0-9\.]+).*\).*Gecko$/], 3939 ['ie', /MSIE\s([0-9\.]+);.*Trident\/[4-7].0/], 3940 ['ie', /MSIE\s(7\.0)/], 3941 ['bb10', /BB10;\sTouch.*Version\/([0-9\.]+)/], 3942 ['android', /Android\s([0-9\.]+)/], 3943 ['ios', /Version\/([0-9\._]+).*Mobile.*Safari.*/], 3944 ['safari', /Version\/([0-9\._]+).*Safari/], 3945 ['facebook', /FB[AS]V\/([0-9\.]+)/], 3946 ['instagram', /Instagram\s([0-9\.]+)/], 3947 ['ios-webview', /AppleWebKit\/([0-9\.]+).*Mobile/], 3948 ['ios-webview', /AppleWebKit\/([0-9\.]+).*Gecko\)$/], 3949 ['curl', /^curl\/([0-9\.]+)$/], 3950 ['searchbot', SEARCHBOX_UA_REGEX], 3951 ]; 3952 var operatingSystemRules = [ 3953 ['iOS', /iP(hone|od|ad)/], 3954 ['Android OS', /Android/], 3955 ['BlackBerry OS', /BlackBerry|BB10/], 3956 ['Windows Mobile', /IEMobile/], 3957 ['Amazon OS', /Kindle/], 3958 ['Windows 3.11', /Win16/], 3959 ['Windows 95', /(Windows 95)|(Win95)|(Windows_95)/], 3960 ['Windows 98', /(Windows 98)|(Win98)/], 3961 ['Windows 2000', /(Windows NT 5.0)|(Windows 2000)/], 3962 ['Windows XP', /(Windows NT 5.1)|(Windows XP)/], 3963 ['Windows Server 2003', /(Windows NT 5.2)/], 3964 ['Windows Vista', /(Windows NT 6.0)/], 3965 ['Windows 7', /(Windows NT 6.1)/], 3966 ['Windows 8', /(Windows NT 6.2)/], 3967 ['Windows 8.1', /(Windows NT 6.3)/], 3968 ['Windows 10', /(Windows NT 10.0)/], 3969 ['Windows ME', /Windows ME/], 3970 ['Windows CE', /Windows CE|WinCE|Microsoft Pocket Internet Explorer/], 3971 ['Open BSD', /OpenBSD/], 3972 ['Sun OS', /SunOS/], 3973 ['Chrome OS', /CrOS/], 3974 ['Linux', /(Linux)|(X11)/], 3975 ['Mac OS', /(Mac_PowerPC)|(Macintosh)/], 3976 ['QNX', /QNX/], 3977 ['BeOS', /BeOS/], 3978 ['OS/2', /OS\/2/], 3979 ]; 3980 function detect(userAgent) { 3981 if (!!userAgent) { 3982 return parseUserAgent(userAgent); 3983 } 3984 if (typeof document === 'undefined' && 3985 typeof navigator !== 'undefined' && 3986 navigator.product === 'ReactNative') { 3987 return new ReactNativeInfo(); 3988 } 3989 if (typeof navigator !== 'undefined') { 3990 return parseUserAgent(navigator.userAgent); 3991 } 3992 return getNodeVersion(); 3993 } 3994 function matchUserAgent(ua) { 3995 // opted for using reduce here rather than Array#first with a regex.test call 3996 // this is primarily because using the reduce we only perform the regex 3997 // execution once rather than once for the test and for the exec again below 3998 // probably something that needs to be benchmarked though 3999 return (ua !== '' && 4000 userAgentRules.reduce(function (matched, _a) { 4001 var browser = _a[0], regex = _a[1]; 4002 if (matched) { 4003 return matched; 4004 } 4005 var uaMatch = regex.exec(ua); 4006 return !!uaMatch && [browser, uaMatch]; 4007 }, false)); 4008 } 4009 function browserName(ua) { 4010 var data = matchUserAgent(ua); 4011 return data ? data[0] : null; 4012 } 4013 function parseUserAgent(ua) { 4014 var matchedRule = matchUserAgent(ua); 4015 if (!matchedRule) { 4016 return null; 4017 } 4018 var name = matchedRule[0], match = matchedRule[1]; 4019 if (name === 'searchbot') { 4020 return new BotInfo(); 4021 }
4022 // Do not use RegExp for split operation as some browser do not support it (See: http://blog.stevenlevithan.com/archives/cross-browser-split) 4023 var versionParts = match[1] && match[1].split('.').join('_').split('_').slice(0, 3); 4024 if (versionParts) { 4025 if (versionParts.length < REQUIRED_VERSION_PARTS) { 4026 versionParts = __spreadArray(__spreadArray([], versionParts, true), createVersionParts(REQUIRED_VERSION_PARTS - versionParts.length), true); 4027 } 4028 } 4029 else { 4030 versionParts = []; 4031 } 4032 var version = versionParts.join('.'); 4033 var os = detectOS(ua); 4034 var searchBotMatch = SEARCHBOT_OS_REGEX.exec(ua); 4035 if (searchBotMatch && searchBotMatch[1]) { 4036 return new SearchBotDeviceInfo(name, version, os, searchBotMatch[1]); 4037 } 4038 return new BrowserInfo(name, version, os); 4039 } 4040 function detectOS(ua) { 4041 for (var ii = 0, count = operatingSystemRules.length; ii < count; ii++) { 4042 var _a = operatingSystemRules[ii], os = _a[0], regex = _a[1]; 4043 var match = regex.exec(ua); 4044 if (match) { 4045 return os; 4046 } 4047 } 4048 return null; 4049 } 4050 function getNodeVersion() { 4051 var isNode = typeof process !== 'undefined' && process.version; 4052 return isNode ? new NodeInfo(process.version.slice(1)) : null; 4053 } 4054 function createVersionParts(count) { 4055 var output = []; 4056 for (var ii = 0; ii < count; ii++) { 4057 output.push('0'); 4058 } 4059 return output; 4060 } 4061 4062 4063 /***/ }), 4064 4065 /***/ 71: 4066 /***/ (function(module) { 4067 4068 !function(n,t){ true?module.exports=t():0}(this,(function(){"use strict";function n(){return n=Object.assign||function(n){for(var t=1;t<arguments.length;t++){var e=arguments[t];for(var i in e)Object.prototype.hasOwnProperty.call(e,i)&&(n[i]=e[i])}return n},n.apply(this,arguments)}var t="undefined"!=typeof window,e=t&&!("onscroll"in window)||"undefined"!=typeof navigator&&/(gle|ing|ro)bot|crawl|spider/i.test(navigator.userAgent),i=t&&"IntersectionObserver"in window,o=t&&"classList"in document.createElement("p"),a=t&&window.devicePixelRatio>1,r={elements_selector:".lazy",container:e||t?document:null,threshold:300,thresholds:null,data_src:"src",data_srcset:"srcset",data_sizes:"sizes",data_bg:"bg",data_bg_hidpi:"bg-hidpi",data_bg_multi:"bg-multi",data_bg_multi_hidpi:"bg-multi-hidpi",data_bg_set:"bg-set",data_poster:"poster",class_applied:"applied",class_loading:"loading",class_loaded:"loaded",class_error:"error",class_entered:"entered",class_exited:"exited",unobserve_completed:!0,unobserve_entered:!1,cancel_on_exit:!0,callback_enter:null,callback_exit:null,callback_applied:null,callback_loading:null,callback_loaded:null,callback_error:null,callback_finish:null,callback_cancel:null,use_native:!1,restore_on_error:!1},c=function(t){return n({},r,t)},l=function(n,t){var e,i="LazyLoad::Initialized",o=new n(t);try{e=new CustomEvent(i,{detail:{instance:o}})}catch(n){(e=document.createEvent("CustomEvent")).initCustomEvent(i,!1,!1,{instance:o})}window.dispatchEvent(e)},u="src",s="srcset",d="sizes",f="poster",_="llOriginalAttrs",g="data",v="loading",b="loaded",m="applied",p="error",h="native",E="data-",I="ll-status",y=function(n,t){return n.getAttribute(E+t)},k=function(n){return y(n,I)},w=function(n,t){return function(n,t,e){var i="data-ll-status";null!==e?n.setAttribute(i,e):n.removeAttribute(i)}(n,0,t)},A=function(n){return w(n,null)},L=function(n){return null===k(n)},O=function(n){return k(n)===h},x=[v,b,m,p],C=function(n,t,e,i){n&&(void 0===i?void 0===e?n(t):n(t,e):n(t,e,i))},N=function(n,t){o?n.classList.add(t):n.className+=(n.className?" ":"")+t},M=function(n,t){o?n.classList.remove(t):n.className=n.className.replace(new RegExp("(^|\\s+)"+t+"(\\s+|$)")," ").replace(/^\s+/,"").replace(/\s+$/,"")},z=function(n){return n.llTempImage},T=function(n,t){if(t){var e=t._observer;e&&e.unobserve(n)}},R=function(n,t){n&&(n.loadingCount+=t)},G=function(n,t){n&&(n.toLoadCount=t)},j=function(n){for(var t,e=[],i=0;t=n.children[i];i+=1)"SOURCE"===t.tagName&&e.push(t);return e},D=function(n,t){var e=n.parentNode;e&&"PICTURE"===e.tagName&&j(e).forEach(t)},H=function(n,t){j(n).forEach(t)},V=[u],F=[u,f],B=[u,s,d],J=[g],P=function(n){return!!n[_]},S=function(n){return n[_]},U=function(n){return delete n[_]},$=function(n,t){if(!P(n)){var e={};t.forEach((function(t){e[t]=n.getAttribute(t)})),n[_]=e}},q=function(n,t){if(P(n)){var e=S(n);t.forEach((function(t){!function(n,t,e){e?n.setAttribute(t,e):n.removeAttribute(t)}(n,t,e[t])}))}},K=function(n,t,e){N(n,t.class_applied),w(n,m),e&&(t.unobserve_completed&&T(n,t),C(t.callback_applied,n,e))},Q=function(n,t,e){N(n,t.class_loading),w(n,v),e&&(R(e,1),C(t.callback_loading,n,e))},W=function(n,t,e){e&&n.setAttribute(t,e)},X=function(n,t){W(n,d,y(n,t.data_sizes)),W(n,s,y(n,t.data_srcset)),W(n,u,y(n,t.data_src))},Y={IMG:function(n,t){D(n,(function(n){$(n,B),X(n,t)})),$(n,B),X(n,t)},IFRAME:function(n,t){$(n,V),W(n,u,y(n,t.data_src))},VIDEO:function(n,t){H(n,(function(n){$(n,V),W(n,u,y(n,t.data_src))})),$(n,F),W(n,f,y(n,t.data_poster)),W(n,u,y(n,t.data_src)),n.load()},OBJECT:function(n,t){$(n,J),W(n,g,y(n,t.data_src))}},Z=["IMG","IFRAME","VIDEO","OBJECT"],nn=function(n,t){!t||function(n){return n.loadingCount>0}(t)||function(n){return n.toLoadCount>0}(t)||C(n.callback_finish,t)},tn=function(n,t,e){n.addEventListener(t,e),n.llEvLisnrs[t]=e},en=function(n,t,e){n.removeEventListener(t,e)},on=function(n){return!!n.llEvLisnrs},an=function(n){if(on(n)){var t=n.llEvLisnrs;for(var e in t){var i=t[e];en(n,e,i)}delete n.llEvLisnrs}},rn=function(n,t,e){!function(n){delete n.llTempImage}(n),R(e,-1),function(n){n&&(n.toLoadCount-=1)}(e),M(n,t.class_loading),t.unobserve_completed&&T(n,e)},cn=function(n,t,e){var i=z(n)||n;on(i)||function(n,t,e){on(n)||(n.llEvLisnrs={});var i="VIDEO"===n.tagName?"loadeddata":"load";tn(n,i,t),tn(n,"error",e)}(i,(function(o){!function(n,t,e,i){var o=O(t);rn(t,e,i),N(t,e.class_loaded),w(t,b),C(e.callback_loaded,t,i),o||nn(e,i)}(0,n,t,e),an(i)}),(function(o){!function(n,t,e,i){var o=O(t);rn(t,e,i),N(t,e.class_error),w(t,p),C(e.callback_error,t,i),e.restore_on_error&&q(t,B),o||nn(e,i)}(0,n,t,e),an(i)}))},ln=function(n,t,e){!function(n){return Z.indexOf(n.tagName)>-1}(n)?function(n,t,e){!function(n){n.llTempImage=document.createElement("IMG")}(n),cn(n,t,e),function(n){P(n)||(n[_]={backgroundImage:n.style.backgroundImage})}(n),function(n,t,e){var i=y(n,t.data_bg),o=y(n,t.data_bg_hidpi),r=a&&o?o:i;r&&(n.style.backgroundImage='url("'.concat(r,'")'),z(n).setAttribute(u,r),Q(n,t,e))}(n,t,e),function(n,t,e){var i=y(n,t.data_bg_multi),o=y(n,t.data_bg_multi_hidpi),r=a&&o?o:i;r&&(n.style.backgroundImage=r,K(n,t,e))}(n,t,e),function(n,t,e){var i=y(n,t.data_bg_set);if(i){var o=i.split("|"),a=o.map((function(n){return"image-set(".concat(n,")")}));n.style.backgroundImage=a.join(),""===n.style.backgroundImage&&(a=o.map((function(n){return"-webkit-image-set(".concat(n,")")})),n.style.backgroundImage=a.join()),K(n,t,e)}}(n,t,e)}(n,t,e):function(n,t,e){cn(n,t,e),function(n,t,e){var i=Y[n.tagName];i&&(i(n,t),Q(n,t,e))}(n,t,e)}(n,t,e)},un=function(n){n.removeAttribute(u),n.removeAttribute(s),n.removeAttribute(d)},sn=function(n){D(n,(function(n){q(n,B)})),q(n,B)},dn={IMG:sn,IFRAME:function(n){q(n,V)},VIDEO:function(n){H(n,(function(n){q(n,V)}
4068)),q(n,F),n.load()},OBJECT:function(n){q(n,J)}},fn=function(n,t){(function(n){var t=dn[n.tagName];t?t(n):function(n){if(P(n)){var t=S(n);n.style.backgroundImage=t.backgroundImage}}(n)})(n),function(n,t){L(n)||O(n)||(M(n,t.class_entered),M(n,t.class_exited),M(n,t.class_applied),M(n,t.class_loading),M(n,t.class_loaded),M(n,t.class_error))}(n,t),A(n),U(n)},_n=["IMG","IFRAME","VIDEO"],gn=function(n){return n.use_native&&"loading"in HTMLImageElement.prototype},vn=function(n,t,e){n.forEach((function(n){return function(n){return n.isIntersecting||n.intersectionRatio>0}(n)?function(n,t,e,i){var o=function(n){return x.indexOf(k(n))>=0}(n);w(n,"entered"),N(n,e.class_entered),M(n,e.class_exited),function(n,t,e){t.unobserve_entered&&T(n,e)}(n,e,i),C(e.callback_enter,n,t,i),o||ln(n,e,i)}(n.target,n,t,e):function(n,t,e,i){L(n)||(N(n,e.class_exited),function(n,t,e,i){e.cancel_on_exit&&function(n){return k(n)===v}(n)&&"IMG"===n.tagName&&(an(n),function(n){D(n,(function(n){un(n)})),un(n)}(n),sn(n),M(n,e.class_loading),R(i,-1),A(n),C(e.callback_cancel,n,t,i))}(n,t,e,i),C(e.callback_exit,n,t,i))}(n.target,n,t,e)}))},bn=function(n){return Array.prototype.slice.call(n)},mn=function(n){return n.container.querySelectorAll(n.elements_selector)},pn=function(n){return function(n){return k(n)===p}(n)},hn=function(n,t){return function(n){return bn(n).filter(L)}(n||mn(t))},En=function(n,e){var o=c(n);this._settings=o,this.loadingCount=0,function(n,t){i&&!gn(n)&&(t._observer=new IntersectionObserver((function(e){vn(e,n,t)}),function(n){return{root:n.container===document?null:n.container,rootMargin:n.thresholds||n.threshold+"px"}}(n)))}(o,this),function(n,e){t&&(e._onlineHandler=function(){!function(n,t){var e;(e=mn(n),bn(e).filter(pn)).forEach((function(t){M(t,n.class_error),A(t)})),t.update()}(n,e)},window.addEventListener("online",e._onlineHandler))}(o,this),this.update(e)};return En.prototype={update:function(n){var t,o,a=this._settings,r=hn(n,a);G(this,r.length),!e&&i?gn(a)?function(n,t,e){n.forEach((function(n){-1!==_n.indexOf(n.tagName)&&function(n,t,e){n.setAttribute("loading","lazy"),cn(n,t,e),function(n,t){var e=Y[n.tagName];e&&e(n,t)}(n,t),w(n,h)}(n,t,e)})),G(e,0)}(r,a,this):(o=r,function(n){n.disconnect()}(t=this._observer),function(n,t){t.forEach((function(t){n.observe(t)}))}(t,o)):this.loadAll(r)},destroy:function(){this._observer&&this._observer.disconnect(),t&&window.removeEventListener("online",this._onlineHandler),mn(this._settings).forEach((function(n){U(n)})),delete this._observer,delete this._settings,delete this._onlineHandler,delete this.loadingCount,delete this.toLoadCount},loadAll:function(n){var t=this,e=this._settings;hn(n,e).forEach((function(n){T(n,t),ln(n,e,t)}))},restoreAll:function(){var n=this._settings;mn(n).forEach((function(t){fn(t,n)}))}},En.load=function(n,t){var e=c(t);ln(n,e)},En.resetStatus=function(n){A(n)},t&&function(n,t){if(t)if(t.length)for(var e,i=0;e=t[i];i+=1)l(n,e);else l(n,t)}(En,window.lazyLoadOptions),En})); 4069 4070 4071 /***/ }), 4072 4073 /***/ 877: 4074 /***/ (() => { 4075 4076 const STATUS_FAV_ADD = 'Aggiungi ai preferiti'; 4077 const STATUS_FAV_ADDED = 'Aggiunto ai preferiti'; 4078 4079 let btn=$('.favorite-button') 4080 4081 btn.on('click', function(){ 4082 $(this).toggleClass('active') 4083 4084 if (this.classList.contains('active')) { 4085 this.setAttribute('aria-label', STATUS_FAV_ADDED); 4086 } else { 4087 this.setAttribute('aria-label', STATUS_FAV_ADD); 4088 } 4089 4090 }) 4091 4092 4093 /***/ }), 4094 4095 /***/ 159: 4096 /***/ (() => { 4097 4098 const showMoreButtonsCat = document.querySelectorAll('.category-list-show'); 4099 //console.log(showMoreButtons) 4100 4101 showMoreButtonsCat.forEach(button => { 4102 //console.log(item) 4103 const categoryList = button.closest('.sup-category-list'); 4104 4105 button.addEventListener('click', event => { 4106 const catItems = categoryList.querySelectorAll('.category-list-more') 4107 4108 catItems.forEach(item => { 4109 item.classList.remove('d-none') 4110 }) 4111 4112 button.remove(); 4113 }) 4114 }) 4115 4116 4117 /***/ }), 4118 4119 /***/ 815: 4120 /***/ (() => { 4121 4122 const STATUS_CHIP_SR_SELECTED = 'Selezionato'; 4123 const STATUS_CHIP_SR_DESELECTED = 'Deselezionato'; 4124 const SELECTOR_CHIP_SR = '.sr-only'; 4125 4126 //MODIFICA SVILUPPO 4127 let chip = document.querySelectorAll('button.btn-chip') 4128
4129 chip.forEach(function (el) { 4130 if(!el.classList.contains("filtri-chip")){ 4131 el.addEventListener('click', function () { 4132 el.classList.toggle('active') 4133 const srElement = el.querySelector(SELECTOR_CHIP_SR); 4134 if (srElement) { 4135 srElement.textContent = el.classList.contains('active') ? STATUS_CHIP_SR_SELECTED : STATUS_CHIP_SR_DESELECTED; 4136 } 4137 }); 4138 } 4139 }) 4140 4141 }), 4142 4143 /***/ 751: 4144 /***/ (() => { 4145 4146 //MODIFICA SVILUPPO 4147 // Seleziona gli elementi .banner-header e header 4148 const bannerHeader = document.querySelector(".banner-header"); 4149 const header = document.querySelector("header"); 4150 // Ottieni l'altezza in pixel di ciascun elemento 4151 let bannerHeight; 4152 if(bannerHeader) bannerHeight = bannerHeader.getBoundingClientRect().height; 4153 let headerHeight; 4154 if(header) headerHeight = header.getBoundingClientRect().height; 4155 4156 function updateCssVariableWithHeightSum() { 4157 4158 4159 // Controlla se gli elementi esistono nella pagina 4160 if (bannerHeader && header) { 4161 4162 bannerHeight = bannerHeader.getBoundingClientRect().height; 4163 headerHeight = header.getBoundingClientRect().height; 4164 // Calcola la somma delle altezze 4165 const totalHeight = bannerHeight + headerHeight; 4166 4167 // Imposta le variabili CSS con i valori calcolati 4168 document.documentElement.style.setProperty("--total-header-height", `${totalHeight}px`); 4169 document.documentElement.style.setProperty("--banner-height", `${bannerHeight}px`); 4170 4171 //console.log(`Variabile CSS --total-header-height aggiornata a: ${totalHeight}px`); 4172 } else { 4173 //console.warn("Elemento .banner-header o header non trovato nella pagina."); 4174 } 4175 } 4176 4177 // Esegui la funzione al caricamento della pagina 4178 4179 if(document.readyState !== 'loading'){ 4180 updateCssVariableWithHeightSum(); 4181 }else{ 4182 document.addEventListener("DOMContentLoaded", updateCssVariableWithHeightSum); 4183 } 4184 // Esegui la funzione anche al ridimensionamento della finestra per aggiornare la variabile 4185 window.addEventListener("resize", updateCssVariableWithHeightSum); 4186 4187 //scroll 4188 4189 // Funzione che gestisce l'aggiunta/rimozione della classe 4190 function toggleStickyClass() { 4191 if(header){ 4192 if (window.scrollY > bannerHeight) { 4193 header.classList.add('sticky-element'); 4194 } else { 4195 header.classList.remove('sticky-element'); 4196 } 4197 }else{ 4198 console.error("Header non trovato toggleStickyClass()"); 4199 } 4200 } 4201 4202 // Aggiungi un evento di ascolto per lo scroll 4203 window.addEventListener('scroll', toggleStickyClass); 4204 4205 4206 /***/ }), 4207 4208 /***/ 825: 4209 /***/ (() => { 4210 //### MODIFICA SVILUPPO (fix per safari perché non gestisce l'evento "DOMContentLoaded") 4211 if(document.readyState !== 'loading'){ 4212 gestioneVideoHomepage(); 4213 }else{ 4214 document.addEventListener("DOMContentLoaded", function () { 4215 gestioneVideoHomepage(); 4216 }); 4217 } 4218 4219 function gestioneVideoHomepage(){ 4220 // Seleziona tutte le sezioni .hero-home 4221 const heroSections = document.querySelectorAll(".hero-home"); 4222 4223 // Itera su ciascuna sezione .hero-home 4224 heroSections.forEach(function (section, index) { 4225 const video = section.querySelector("video"); // Seleziona il video nella sezione 4226 4227 // Seleziona tutti i pulsanti .hero-video-toggle nella sezione 4228 const toggleButtons = section.querySelectorAll(".hero-video-toggle"); 4229 4230 // Itera su ciascun pulsante e aggiungi un event listener 4231 toggleButtons.forEach(function (toggleButton) { 4232 toggleButton.addEventListener("click", function () { 4233 if (video.paused) { 4234 video.play(); 4235 //console.log("Video avviato nella sezione", index + 1); 4236 //MODIFICA SVILUPPO 4237 toggleButton.querySelector("use").setAttribute("href", "/etc.clientlibs/superabile/clientlibs/clientlib-base/resources/svg/wd-sprite.svg#pause"); 4238 toggleButton.setAttribute("aria-label", "Metti in pausa il video di sfondo"); 4239 } else { 4240 video.pause(); 4241 //console.log("Video in pausa nella sezione", index + 1); 4242 toggleButton.querySelector("use").setAttribute("href", "/etc.clientlibs/superabile/clientlibs/clientlib-base/resources/svg/wd-sprite.svg#play"); 4243 toggleButton.setAttribute("aria-label", "Avvia il video di sfondo"); 4244 4245 } 4246 }); 4247 }); 4248 }); 4249 } 4250 4251 /***/ }), 4252 4253 /***/ 447: 4254 /***/ (() => { 4255 4256 /** 4257 * Evita la chiusura della modale quando si preme il tasto ESC per chiudere il date pocker 4258 */ 4259 4260 const SELECTOR_MODAL_SIDEBAR_FILTERS = '.modal-content' 4261 const CLASS_DATEPICKER_OPENED = 'datepicker-opened' 4262 const CLASS_DATEPICKER_ACTIVE = 'active' 4263 4264 const modalContent = document.querySelector(SELECTOR_MODAL_SIDEBAR_FILTERS) 4265 //MODIFICA SVILUPPO 4266 if(modalContent){ 4267 modalContent.addEventListener('keydown', (e) => { 4268 if (e.code === 'Escape' && e.currentTarget.classList.contains(CLASS_DATEPICKER_OPENED)) { 4269 e.stopPropagation() 4270 e.preventDefault() 4271 } 4272 }) 4273 } 4274 4275 4276 const observer = new MutationObserver((mutations) => { 4277 const modal = mutations[0].target.closest(SELECTOR_MODAL_SIDEBAR_FILTERS) 4278 const found = mutations.find((mutation) => mutation.type === 'attributes' && mutation.attributeName === 'class' && mutation.target.classList.contains(CLASS_DATEPICKER_ACTIVE)) 4279 4280 //il timeout serve affinché la classe persista per qualche istante nel momento in cui si preme il tasto (esc fa chiudere il date picker e quindi il suo stato non è più attivo) 4281 if (found) { 4282 setTimeout( 4283 () => { modal.classList.add(CLASS_DATEPICKER_OPENED)}, 4284 100 4285 ) 4286 } else { 4287 setTimeout( 4288 () => { modal.classList.remove(CLASS_DATEPICKER_OPENED)}, 4289 100 4290 ) 4291 } 4292 }) 4293 4294 const datePickers = document.querySelectorAll('#sidebar-filters .datepicker-dropdown')
4295 datePickers.forEach((dp) => { 4296 observer.observe(dp, { 4297 attributes: true, 4298 attributeFilter: ['class'], 4299 childList: false, 4300 characterData: false 4301 }) 4302 }) 4303 4304 4305 /***/ }), 4306 4307 /***/ 185: 4308 /***/ (() => { 4309 4310 const sidebarAnchors = document.querySelectorAll('.sup-sidebar-menu .navbar-nav a'); 4311 4312 function handleAnchors(evt) { 4313 sidebarAnchors.forEach(anchors => {( 4314 anchors.classList.remove('active') 4315 )}) 4316 evt.target.classList.add('active'); 4317 4318 $('#sidebar-menu-trigger').click() 4319 } 4320 4321 const handleKeyDown = (evt) => { 4322 switch (evt.code) { 4323 case 'Space': 4324 case 'Enter': 4325 evt.preventDefault(); 4326 evt.target.click(); 4327 break; 4328 } 4329 } 4330 4331 if (sidebarAnchors) { 4332 sidebarAnchors.forEach(item => { 4333 item.addEventListener('click', handleAnchors); 4334 item.addEventListener('keydown', handleKeyDown); 4335 }) 4336 } 4337 4338 const collapseBtn = document.querySelector('#sidebar-menu-trigger'); 4339 if (collapseBtn) { 4340 collapseBtn.addEventListener('click', () => { 4341 $(collapseBtn.dataset.target).collapse('toggle'); 4342 }); 4343 } 4344 4345 document.addEventListener('focus', (evt) => { 4346 let found = false; 4347 sidebarAnchors.forEach(anchor => { 4348 if (anchor.isEqualNode(evt.target)) { 4349 found = true; 4350 return; 4351 } 4352 }); 4353 if (collapseBtn) { 4354 if (collapseBtn.isEqualNode(evt.target)) { 4355 found = true; 4356 } 4357 if (!found) { 4358 const collapse = document.querySelector(collapseBtn.getAttribute('data-target')); 4359 if (collapse && collapse.classList.contains('show')) { 4360 $(collapseBtn.dataset.target).collapse('hide'); 4361 } 4362 } 4363 } 4364 }, true); 4365 4366 4367 /***/ }), 4368 4369 /***/ 540:
4370 /***/ (() => { 4371 4372 const showMoreButtons = document.querySelectorAll('.team-show'); 4373 //console.log(showMoreButtons) 4374 4375 showMoreButtons.forEach(item => { 4376 //console.log(item) 4377 const team = item.closest('.sup-team'); 4378 4379 item.addEventListener('click', event => { 4380 team.querySelector('.team-more').classList.remove('d-none') 4381 item.remove(); 4382 }) 4383 }) 4384 4385 4386 /***/ }), 4387 4388 /***/ 719: 4389 /***/ (() => { 4390 4391 const toastClose = document.querySelectorAll( '.sup-toast button' ); 4392 4393 toastClose.forEach(item => { 4394 item.addEventListener('click', event => { 4395 item.closest('.sup-toast').remove() 4396 }) 4397 }) 4398 4399 4400 /***/ }), 4401 4402 /***/ 643: 4403 /***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { 4404 4405 //browser detect 4406 const { detect } = __webpack_require__(889); 4407 const browser = detect(); 4408 // handle the case where we don't detect the browser 4409 if (browser) { 4410 let browserOs = browser.os; 4411 let browserName = browser.name; 4412 let browserVersion = browser.version; 4413 4414 browserOs = browserOs.replace(/\s/g, '').toLowerCase(); 4415 browserName = browserName.replace(/\s/g, '').toLowerCase(); 4416 browserVersion = browserVersion.split('.'); // only major version 4417 4418 document.body.classList.add(browserOs); 4419 document.body.classList.add(browserName); 4420 document.body.classList.add('v' + browserVersion[0]); 4421 } 4422 4423 4424 /***/ }) 4425 4426 /******/ }); 4427 /************************************************************************/ 4428 /******/ // The module cache 4429 /******/ var __webpack_module_cache__ = {}; 4430 /******/ 4431 /******/ // The require function 4432 /******/ function __webpack_require__(moduleId) { 4433 /******/ // Check if module is in cache 4434 /******/ var cachedModule = __webpack_module_cache__[moduleId]; 4435 /******/ if (cachedModule !== undefined) { 4436 /******/ return cachedModule.exports; 4437 /******/ } 4438 /******/ // Create a new module (and put it into the cache) 4439 /******/ var module = __webpack_module_cache__[moduleId] = { 4440 /******/ // no module.id needed 4441 /******/ // no module.loaded needed 4442 /******/ exports: {} 4443 /******/ }; 4444 /******/ 4445 /******/ // Execute the module function 4446 /******/ __webpack_modules__[moduleId].call(module.exports, module, module.exports, __webpack_require__); 4447 /******/ 4448 /******/ // Return the exports of the module 4449 /******/ return module.exports; 4450 /******/ } 4451 /******/ 4452 /************************************************************************/ 4453 /******/ /* webpack/runtime/compat get default export */ 4454 /******/ (() => { 4455 /******/ // getDefaultExport function for compatibility with non-harmony modules 4456 /******/ __webpack_require__.n = (module) => { 4457 /******/ var getter = module && module.__esModule ? 4458 /******/ () => (module['default']) : 4459 /******/ () => (module); 4460 /******/ __webpack_require__.d(getter, { a: getter }); 4461 /******/ return getter; 4462 /******/ }; 4463 /******/ })(); 4464 /******/ 4465 /******/ /* webpack/runtime/define property getters */ 4466 /******/ (() => { 4467 /******/ // define getter functions for harmony exports 4468 /******/ __webpack_require__.d = (exports, definition) => { 4469 /******/ for(var key in definition) { 4470 /******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { 4471 /******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); 4472 /******/ } 4473 /******/ } 4474 /******/ }; 4475 /******/ })(); 4476 /******/ 4477 /******/ /* webpack/runtime/hasOwnProperty shorthand */ 4478 /******/ (() => { 4479 /******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) 4480 /******/ })(); 4481 /******/ 4482 /******/ /* webpack/runtime/make namespace object */ 4483 /******/ (() => { 4484 /******/ // define __esModule on exports 4485 /******/ __webpack_require__.r = (exports) => { 4486 /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { 4487 /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); 4488 /******/ } 4489 /******/ Object.defineProperty(exports, '__esModule', { value: true }); 4490 /******/ }; 4491 /******/ })(); 4492 /******/ 4493 /************************************************************************/ 4494 var __webpack_exports__ = {}; 4495 // This entry need to be wrapped in an IIFE because it need to be in strict mode. 4496 (() => { 4497 "use strict"; 4498 4499 // EXTERNAL MODULE: ./src/components/button/button.js 4500 var button_button = __webpack_require__(877); 4501 // EXTERNAL MODULE: ./src/components/category-list/category-list.js 4502 var category_list = __webpack_require__(159); 4503 // EXTERNAL MODULE: ./src/components/chips/chips.js 4504 var chips = __webpack_require__(815); 4505 // EXTERNAL MODULE: ./src/components/header/header.js 4506 var header = __webpack_require__(751); 4507 // EXTERNAL MODULE: ./src/components/heros/hero-home/hero-home.js 4508 var hero_home = __webpack_require__(825); 4509 // EXTERNAL MODULE: ./src/components/sidebar-filters/sidebar-filters.js 4510 var sidebar_filters = __webpack_require__(447); 4511 // EXTERNAL MODULE: ./src/components/sidebar-menu/sidebar-menu.js 4512 var sidebar_menu = __webpack_require__(185); 4513 ;// ./src/utils/index.js 4514 const isElement = obj => { 4515 if (!obj || typeof obj !== 'object') { 4516 return false 4517 } 4518 4519 if (typeof obj.jquery !== 'undefined') { 4520 obj = obj[0] 4521 } 4522 4523 return typeof obj.nodeType !== 'undefined' 4524 } 4525 4526 const getElement = obj => { 4527 if (isElement(obj)) { // it's a jQuery object or a node element 4528 return obj.jquery ? obj[0] : obj 4529 } 4530 4531 if (typeof obj === 'string' && obj.length > 0) { 4532 return document.querySelector(obj) 4533 } 4534 4535 return null 4536 } 4537 4538 const isFocusable = (element) => { 4539 if (!(element instanceof HTMLElement)) { 4540 return false;
4541 } 4542 // https://stackoverflow.com/a/30753870/76472 4543 const knownFocusableElements = 4544 'a[href],area[href],button:not([disabled]),details,iframe,object,input:not([disabled]),select:not([disabled]),textarea:not([disabled]),[contentEditable="true"],[tabindex]:not([tabindex^="-"])'; 4545 if (element.matches(knownFocusableElements)) { 4546 return true; 4547 } 4548 4549 const isDisabledCustomElement = 4550 element.localName.includes('-') && element.matches('[disabled], [aria-disabled="true"]'); 4551 if (isDisabledCustomElement) { 4552 return false; 4553 } 4554 4555 return element.shadowRoot?.delegatesFocus ?? false; 4556 } 4557 4558 const findSiblingGlobal = (currentElement, direction) => { 4559 const iterator = document.createNodeIterator( 4560 document.body, // Radice del DOM in cui cercare 4561 NodeFilter.SHOW_ELEMENT // Considera solo nodi di tipo elemento 4562 ); 4563 4564 let node; 4565 let foundCurrent = false; 4566 4567 while ((node = iterator.nextNode())) { 4568 if (foundCurrent) { 4569 if (direction === 'prev') { 4570 iterator.previousNode(); 4571 iterator.previousNode(); 4572 return iterator.previousNode(); 4573 } 4574 return node; // Restituisce il prossimo elemento dopo quello corrente 4575 } 4576 if (node === currentElement) { 4577 foundCurrent = true; 4578 } 4579 } 4580 4581 return null; // Nessun elemento successivo trovato 4582 } 4583 4584 4585 4586 ;// ./src/components/tab/tab.js 4587 4588 4589 const STATUS_TAB_LINK_SR_SELECTED = 'Selezionato'; 4590 const STATUS_TAB_LINK_SR_DESELECTED = 'Deselezionato'; 4591 const SELECTOR_TAB_LINK_SR = '.sr-only'; 4592 4593 const CLASS_TAB_LINK = 'nav-link'; 4594 const CLASS_TAB_LINK_ACTIVE = 'active'; 4595 const SELECTOR_TAB = '.nav-tabs'; 4596 const SELECTOR_TAB_LINK = '.' + CLASS_TAB_LINK; 4597 const SELECTOR_TAB_LINK_NO_DOT = CLASS_TAB_LINK; 4598 4599 let currentFocused = null; 4600 4601 /** 4602 * Sposta il focus su un altro tab link del gruppo al quale appartiene target 4603 * @param {HTMLElement} target 4604 * @param {string|number} step 'home' sposta il focus all'inizio della lista, 'end' sposta il focus alla fine della lista, un valore numerico indica di quanto spostarsi (avanti o indietro) all'interno della lista 4605 */ 4606 const moveFocus = (target, step) => { 4607 const navTab = target.closest(SELECTOR_TAB); 4608 const allNavLinks = navTab.getElementsByClassName(SELECTOR_TAB_LINK_NO_DOT); 4609 let targetPos = 0; 4610 let toFocusPos = 0; 4611 4612 Array.from(allNavLinks).find((link, idx) => { 4613 if (link.isEqualNode(target)) { 4614 targetPos = idx; 4615 return true; 4616 } 4617 return false; 4618 }) 4619 4620 if (step === 'home') { 4621 toFocusPos = 0; 4622 } else if (step === 'end') { 4623 toFocusPos = allNavLinks.length - 1; 4624 } else { 4625 toFocusPos = targetPos + step; 4626 if (toFocusPos < 0) { 4627 toFocusPos = allNavLinks.length - 1; 4628 } else if (toFocusPos >= allNavLinks.length) { 4629 toFocusPos = 0; 4630 } 4631 } 4632 4633 allNavLinks[toFocusPos].focus(); 4634 } 4635 4636 /** 4637 * sposta il focus sull'elemento precedente o successivo al contenitore della lista di tab link 4638 * @param {HTMLElement} target il tab link 4639 * @param {string} 'prev', 'next' o undefined. Se undefined si considera di valore 'next' 4640 */ 4641 const contentFocus = (target, direction) => { 4642 const navTab = target.closest(SELECTOR_TAB); 4643 const allNavLinks = navTab.getElementsByClassName(SELECTOR_TAB_LINK_NO_DOT); 4644 4645 let sibling = direction === 'prev' ? findSiblingGlobal(navTab, direction) : findSiblingGlobal(allNavLinks[allNavLinks.length - 1]); 4646 let focusableElement = undefined; 4647 while (sibling && !focusableElement) { 4648 if (sibling.checkVisibility()) { 4649 if (isFocusable(sibling)) { 4650 focusableElement = sibling; 4651 } 4652 } 4653 sibling = findSiblingGlobal(sibling, direction); 4654 } 4655 4656 if (focusableElement) { 4657 focusableElement.focus(); 4658 } 4659 } 4660 4661 const wcagTabAction = (evt) => { 4662 const target = evt.currentTarget; 4663 4664 if (target.isEqualNode(document.activeElement)) { 4665 if (['Tab', 'Space', 'Home', 'End', 'ArrowLeft'].includes(evt.code)) { 4666 evt.preventDefault(); 4667 evt.stopPropagation(); 4668 } 4669 4670 switch (evt.code) { 4671 case 'Tab': 4672 contentFocus(target, evt.shiftKey ? 'prev' : ''); 4673 break; 4674 case 'ArrowRight': 4675 moveFocus(target, 1); 4676 break; 4677 case 'ArrowLeft': 4678 moveFocus(target, -1); 4679 break; 4680 case 'Space': 4681 target.click(); 4682 break; 4683 case 'Home': 4684 moveFocus(target, 'home'); 4685 break; 4686 case 'End': 4687 moveFocus(target, 'end'); 4688 break; 4689 default: 4690 break; 4691 } 4692 } 4693 } 4694 4695 /** 4696 * assegna il focus al tab link che risulta attivo quando il precedente elemento che aveva il focus è esterno alla lista dei tab link. 4697 * @param {*} evt 4698 */ 4699 const setFocus = (evt) => { 4700 let linkActive = null; 4701 if (!currentFocused 4702 || !currentFocused.classList.contains(CLASS_TAB_LINK) 4703 || (currentFocused.classList.contains(CLASS_TAB_LINK) && currentFocused.closest(SELECTOR_TAB) && !Array.from(currentFocused.closest(SELECTOR_TAB).getElementsByClassName(SELECTOR_TAB_LINK_NO_DOT)).find((el) => el.isEqualNode(evt.target))) //se è un tab link non deve appartenere alla stessa lista del target 4704 ) { 4705 linkActive = evt.target.closest(SELECTOR_TAB).querySelector(SELECTOR_TAB_LINK + '.' + CLASS_TAB_LINK_ACTIVE); 4706 } 4707 4708 if (linkActive) { 4709 linkActive.focus(); 4710 } else {
4711 evt.target.focus(); 4712 } 4713 } 4714 4715 const wcagClick = (evt) => { 4716 if (!evt.target.classList.contains(CLASS_TAB_LINK_ACTIVE)) { 4717 const currentActive = evt.target.closest(SELECTOR_TAB).querySelector(SELECTOR_TAB_LINK + '.' + CLASS_TAB_LINK_ACTIVE); 4718 if (currentActive) { 4719 currentActive.setAttribute('aria-expanded', false); 4720 /*const srElement = currentActive.querySelector(SELECTOR_TAB_LINK_SR); 4721 if (srElement) { 4722 srElement.textContent = STATUS_TAB_LINK_SR_DESELECTED; 4723 }*/ 4724 } 4725 4726 evt.target.setAttribute('aria-expanded', true); 4727 /*const srElement = evt.target.querySelector(SELECTOR_TAB_LINK_SR); 4728 if (srElement) { 4729 srElement.textContent = STATUS_TAB_LINK_SR_SELECTED; 4730 }*/ 4731 } 4732 } 4733 4734 let tab_button = $('.mob-version .nav-link'); 4735 let tab_text; 4736 4737 tab_button.on("click", function () { 4738 tab_text = $(this).text(); 4739 $(this).closest(".sup-collapse").find("span").text(tab_text); 4740 }); 4741 4742 const navLinks = document.querySelectorAll(SELECTOR_TAB + ' ' + SELECTOR_TAB_LINK); 4743 navLinks.forEach(link => { 4744 link.addEventListener('keydown', wcagTabAction); 4745 link.addEventListener('focus', setFocus); 4746 link.addEventListener('click', wcagClick); 4747 }); 4748 4749 //MODIFICA SVILUPPO (esporre listener nav) 4750 window.NavWcagTabAction = wcagTabAction; 4751 window.NavSetFocus = setFocus; 4752 window.NavWcagClick = wcagClick; 4753 4754 document.addEventListener('focus', (evt) => { 4755 setTimeout( //serve per fare in modo che l'azione avvenga dopo il focus sul tab link 4756 () => currentFocused = evt.target, 4757 10 4758 ) 4759 }, true); 4760 4761 // EXTERNAL MODULE: ./src/components/team/team.js 4762 var team = __webpack_require__(540); 4763 // EXTERNAL MODULE: ./src/components/toast/toast.js 4764 var toast = __webpack_require__(719); 4765 // EXTERNAL MODULE: ./src/js/browser-detect.js 4766 var browser_detect = __webpack_require__(643); 4767 // EXTERNAL MODULE: ./node_modules/vanilla-lazyload/dist/lazyload.min.js 4768 var lazyload_min = __webpack_require__(71); 4769 var lazyload_min_default = /*#__PURE__*/__webpack_require__.n(lazyload_min); 4770 ;// ./src/js/lazyload.js 4771 //lazy load 4772 4773 var lazyLoadInstance = new (lazyload_min_default())({ 4774 // Your custom settings go here 4775 threshold:200, //pixel offset for loading images 4776 }); 4777 4778 ;// ./src/app.js 4779 //import css 4780 4781 4782 //import components js 4783 4784 })(); 4785 4786 /******/ })() 4787 ; 4788 //# sourceMappingURL=bundle.js.map 4789var SELECTOR_UIKIT_SCRIPT_FUCUSABLE = 'span, h2, p, a[href]:not([disabled]), button:not([disabled]), textarea:not([disabled]), input[type="text"]:not([disabled]), input[type="radio"]:not([disabled]), input[type="checkbox"]:not([disabled]), select:not([disabled])'; 4790var SELECTOR_UIKIT_SCRIPT_FOCUSABLE_ARRAY = [ 4791 'span', 4792 'h2', 4793 'p', 4794 'a[href]:not([disabled])', 4795 'button:not([disabled])', 4796 'textarea:not([disabled])', 4797 'input[type="text"]:not([disabled])', 4798 'input[type="radio"]:not([disabled])', 4799 'input[type="checkbox"]:not([disabled])', 4800 'select:not([disabled])' 4801]; 4802// ScrollTop 4803$(window).on("scroll", function () { 4804 if ($(this).scrollTop() >= 350) { 4805 $("#scroll-top-btn").fadeIn(200); 4806 } else { 4807 $("#scroll-top-btn").fadeOut(200); 4808 } 4809}); 4810$("#scroll-top-btn").on("click", function (e) { 4811 $("body,html").animate({ 4812 scrollTop: 0 4813 }, 500); 4814 e.preventDefault(); 4815}); 4816 4817//MODIFICA SVILUPPO 4818$(function () { 4819 if($('[data-toggle="tooltip"]').length > 0) $('[data-toggle="tooltip"]').tooltip() 4820}) 4821 4822// IE11 Object-fit image 4823var isIE11 = !!window.MSInputMethodContext && !!document.documentMode; 4824if (isIE11) { 4825 $('.img-wrapper, .card-image-left').each(function () { 4826 var $container = $(this), 4827 imgUrl = $container.find('img').prop('src') 4828 if (imgUrl) { 4829 $container 4830 .css('backgroundImage', 'url(' + imgUrl + ')') 4831 .addClass('custom-object-fit') 4832 } 4833 }) 4834} 4835 4836// GESTIONE MENU PRINCIPALE 4837$('.nav-open').click(function (e) { 4838 $(".nav").addClass("show"); 4839 $("body").addClass("overflow-hidden"); 4840 $(".nav").on('click', function (e) { 4841 if ($(e.target).closest("#nav").length === 0) { 4842 closeMenu(); 4843 } 4844 }); 4845}); 4846function closeMenu() { 4847 $(".nav").removeClass("show").off(); 4848 $("body").removeClass("overflow-hidden"); 4849} 4850$('.nav-close').click(function (e) { 4851 closeMenu(); 4852}); 4853 4854// Click esterno al menu per la chiusura 4855$(document).on('click', function (e) { 4856 if ($(".navbar-collapse.show").length > 0 || $("#cerca-top.show").length > 0) { 4857 if ($(e.target).closest(".divMenu").length === 0) { 4858 $("#menu-top").collapse('hide'); 4859 $("body").removeClass("overflow-hidden"); 4860 } 4861 if ($(e.target).closest(".divCerca").length === 0) { 4862 $("#cerca-top").collapse('hide'); 4863 $("body").removeClass("overflow-hidden"); 4864 } 4865 } 4866}); 4867$(function () { 4868 var navMain = $(".navbar-collapse"); // avoid dependency on #id 4869 // "a:not([data-toggle])" - to avoid issues caused 4870 // when you have dropdown inside navbar 4871 navMain.on("click", "a:not([data-toggle])", null, function () { 4872 navMain.collapse('hide'); 4873 }); 4874}); 4875$(document).on('click', 'a[href="#menu-top"]', function (e) { 4876 $("#menu-top a").first().focus(); 4877 $("body").addClass("overflow-hidden"); 4878}); 4879$(document).on('click', 'a[href="#cerca-top"]', function (e) { 4880 $("#cerca-top a").first().focus(); 4881 $("body").addClass("overflow-hidden"); 4882}); 4883$(document).on('click', 'a[href="#sidebar-menu-mobile"]', function (e) { 4884 $("#sidebar-menu-mobile a").first().focus(); 4885 $("body").addClass("overflow-hidden"); 4886}); 4887$(document).on('click', 'a[href="#menu-top"][aria-expanded="true"], a[href="#cerca-top"][aria-expanded="true"], a[href="#sidebar-menu-mobile"][aria-expanded="true"]', function (e) { 4888 $("body").removeClass("overflow-hidden"); 4889}); 4890$(document).on('keydown', function (e) { 4891 if (e.key === "Escape") { 4892 if ($("#menu-top.show").length > 0) { 4893 $("#menu-top").collapse('hide'); 4894 $("body").removeClass("overflow-hidden"); 4895 $("a[href='#menu-top']").first().focus(); 4896 } 4897 if ($("#cerca-top.show").length > 0) { 4898 $("#cerca-top").collapse('hide'); 4899 $("body").removeClass("overflow-hidden"); 4900 $("a[href='#cerca-top']").first().focus(); 4901 } 4902 if ($("#sidebar-menu-mobile.show").length > 0) { 4903 $("#sidebar-menu-mobile").collapse('hide'); 4904 $("body").removeClass("overflow-hidden"); 4905 $("a[href='#sidebar-menu-mobile']").first().focus(); 4906 } 4907 } 4908 if (e.key === "Tab") { 4909 // if ($("#menu-top.show").length > 0) { 4910 // if ($(e.target).closest("#menu-top").length === 0) { 4911 // $("#menu-top a").first().focus(); 4912 // } 4913 // } 4914 if ($("#cerca-top.show").length > 0) { 4915 if ($(e.target).closest("#cerca-top").length === 0) { 4916 $("#cerca-top a").first().focus(); 4917 } 4918 } 4919 if ($("#sidebar-menu-mobile.show").length > 0) { 4920 if ($(e.target).closest("#sidebar-menu-mobile").length === 0) { 4921 $("#sidebar-menu-mobile button").first().focus(); 4922 } 4923 } 4924 } 4925}); 4926 4927$(document).on('keyup', function (e) { 4928 if (e.key === "Tab") { 4929 //chiusura automatica del menu quando il focus non è più su uno dei suoi elementi 4930 if ($("#menu-top.show").length > 0) { 4931 if ($(e.target).closest("#menu-top").length === 0) { 4932 $("#menu-top").collapse('hide'); 4933 } 4934 } 4935 } 4936}); 4937 4938// Accesso rapido tabs 4939$(document).on('click', '.accesso-rapido .nav-link', function (e) { 4940 id = $(this).attr("href"); 4941 $(".accesso-rapido .tab-pane").removeClass("active").removeClass("show"); 4942 $(id).addClass("active show"); 4943}); 4944 4945// Input text, textarea, select filled 4946$("textarea.form-control, input.form-control, select.form-control").on('keyup change', '', function (e) { 4947 if ($(this).hasClass("thin-ui-multiselect")) { 4948 if (!$(this).val().length) { 4949 $(this).next().find("button.form-control").removeClass("filled"); 4950 } else { 4951 $(this).next().find("button.form-control").addClass("filled"); 4952 } 4953 } else { 4954 if (!$(this).val()) { 4955 $(this).removeClass("filled"); 4956 } else { 4957 $(this).addClass("filled"); 4958 } 4959 } 4960}); 4961$("textarea.form-control, input.form-control").keyup(); 4962$("select.form-control").change(); 4963 4964 4965// Inizializzazione Calendario VanillaJs Datepicker Sirio Version 4966// Lingua italiana modifica per ottenere la grafica del design 4967(function () { 4968 Datepicker.locales.it = { 4969 // Termini di base 4970 days: ["Domenica", "Lunedì", "Martedì", "Mercoledì", "Giovedì", "Venerdì", "Sabato"], 4971 daysShort: ["Dom", "Lun", "Mar", "Mer", "Gio", "Ven", "Sab"], 4972 daysMin: ["Dom", "Lun", "Mar", "Mer", "Gio", "Ven", "Sab"], 4973 months: ["Gennaio", "Febbraio", "Marzo", "Aprile", "Maggio", "Giugno", "Luglio", "Agosto", "Settembre", "Ottobre", "Novembre", "Dicembre"], 4974 monthsShort: ["Gennaio", "Febbraio", "Marzo", "Aprile", "Maggio", "Giugno", "Luglio", "Agosto", "Settembre", "Ottobre", "Novembre", "Dicembre"], 4975 today: "Oggi", 4976 monthsTitle: "Mesi", 4977 clear: "Cancella", 4978 format: "dd/mm/yyyy", 4979 4980 // Aggiunte per l'aria-label dei bottoni in testata 4981 btnMonth: "Cambia il mese", 4982 btnPrevMonth: "Mese precedente", 4983 btnNextMonth: "Mese successivo", 4984 // Utilizzati dopo aver cliccato sul bottone centrale prima volta 4985 btnYear: "Cambia l\'anno", 4986 btnPrevYear: "Anno precedente", 4987 btnNextYear: "Anno successivo", 4988 // Utilizzati dopo aver cliccato sul bottone centrale seconda volta 4989 btnDecade: "Cambia il decennio", 4990 btnPrevDecade: "Decennio precedente", 4991 btnNextDecade: "Decennio successivo", 4992 // Utilizzati dopo aver cliccato sul bottone centrale terza volta 4993 btnPrevCentury: "Secolo precedente", 4994 btnNextCentury: "Secolo successivo" 4995 }; 4996}()); 4997 4998var elems = document.querySelectorAll(".form-datepicker"); 4999for (var elem of elems) { 5000 if (!elem.parentNode.classList.contains("form-datepicker-range")) { 5001 var datepicker = new Datepicker(elem, { 5002 format: "dd/mm/yyyy", 5003 language: "it", 5004 weekStart: 1, 5005 prevArrow: '<span class="icon-xs icon-chevron-small-left" aria-hidden="true"></span>', 5006 nextArrow: '<span class="icon-xs icon-chevron-small-right" aria-hidden="true"></span>', 5007 autohide: true 5008 }); 5009 } 5010} 5011 5012var elemsRange = document.querySelectorAll(".form-datepicker-range"); 5013for (var elemRange of elemsRange) { 5014 var datepickerRange = new DateRangePicker(elemRange, { 5015 format: "dd/mm/yyyy", 5016 language: "it", 5017 weekStart: 1, 5018 prevArrow: '<span class="icon-xs icon-chevron-small-left" aria-hidden="true"></span>', 5019 nextArrow: '<span class="icon-xs icon-chevron-small-right" aria-hidden="true"></span>' 5020 }); 5021} 5022 5023// Splide carousel
5024const splideDataMap = new Map(); 5025window.SplideData = class { 5026 static set(element, instance) { 5027 if (!splideDataMap.has(element)) { 5028 splideDataMap.set(element, instance); 5029 } 5030 } 5031 static get(element) { 5032 if (splideDataMap.has(element)) { 5033 return splideDataMap.get(element); 5034 } 5035 5036 return null; 5037 } 5038 static remove(element) { 5039 if (!elementMap.has(element)) { 5040 return 5041 } 5042 5043 splideDataMap.delete(element) 5044 } 5045} 5046 5047var splide1 = { 5048 0: { 5049 perPage: 1 5050 } 5051} 5052var splide2 = { 5053 0: { 5054 gap: 12, 5055 perPage: 1 5056 }, 5057 768: { 5058 gap: 24, 5059 perPage: 2 5060 } 5061} 5062var splide3 = { 5063 0: { 5064 gap: 12, 5065 perPage: 1 5066 }, 5067 768: { 5068 gap: 24, 5069 perPage: 2 5070 }, 5071 992: { 5072 perPage: 3 5073 } 5074} 5075var splide4 = { 5076 0: { 5077 gap: 12, 5078 perPage: 1 5079 }, 5080 768: { 5081 gap: 24, 5082 perPage: 2 5083 }, 5084 992: { 5085 perPage: 3 5086 }, 5087 1280: { 5088 perPage: 4 5089 } 5090} 5091var splideSubsite = { 5092 0: { 5093 gap: 12, 5094 perPage: 1 5095 }, 5096 768: { 5097 destroy: true 5098 } 5099} 5100var splideAccessoRapido = { 5101 0: { 5102 gap: 12, 5103 perPage: 1 5104 }, 5105 768: { 5106 destroy: true 5107 } 5108} 5109var fotogallery = { 5110 0: { 5111 perPage: 3 5112 }, 5113 768: { 5114 perPage: 4, 5115 pagination: true 5116 }, 5117 992: { 5118 perPage: 5 5119 }, 5120 1280: { 5121 perPage: 6 5122 } 5123} 5124var gallery = { 5125 0: { 5126 fixedWidth: 100, 5127 fixedHeight: 60 5128 }, 5129 768: { 5130 fixedWidth: 150, 5131 fixedHeight: 90, 5132 } 5133} 5134var infografica = { 5135 0: { 5136 perPage: 3 5137 }, 5138 768: { 5139 perPage: 4, 5140 arrows: true 5141 }, 5142 992: { 5143 destroy: true 5144 } 5145} 5146if ($(".splide").length) { 5147 var splideElem = document.getElementsByClassName("splide"); 5148 for (var i = 0; i < splideElem.length; i++) { 5149 var bp = splide3 5150 if ($(splideElem[i]).hasClass("splide-1")) { 5151 bp = splide1; 5152 } 5153 if ($(splideElem[i]).hasClass("splide-2")) { 5154 bp = splide2; 5155 } 5156 if ($(splideElem[i]).hasClass("splide-4") || $(splideElem[i]).hasClass("videogallery-slider")) { 5157 bp = splide4; 5158 } 5159 if ($(splideElem[i]).hasClass("splide-subsite")) { 5160 bp = splideSubsite; 5161 } 5162 if ($(splideElem[i]).hasClass("splide-accesso-rapido")) { 5163 bp = splideAccessoRapido; 5164 } 5165 if ($(splideElem[i]).hasClass("fotogallery-slider")) { 5166 bp = fotogallery; 5167 } 5168 if ($(splideElem[i]).hasClass("infografica-slider")) { 5169 bp = infografica; 5170 } 5171 if ($(splideElem[i]).hasClass("splide-slider")) { 5172 bp = {}; 5173 arrOptions = { 5174 type: 'fade', 5175 rewind: true, 5176 pagination: false, 5177 arrows: false, 5178 padding: { 5179 left: 3, 5180 right: 3, 5181 }, 5182 perPage: 1 5183 } 5184 } else if ($(splideElem[i]).hasClass("splide-thumb")) { 5185 bp = gallery; 5186 arrOptions = { 5187 fixedWidth: 150, 5188 fixedHeight: 90, 5189 gap: 10, 5190 padding: { 5191 left: 3, 5192 right: 3, 5193 }, 5194 rewind: true, 5195 pagination: false, 5196 cover: true, 5197 isNavigation: true, 5198 classes: { 5199 prev: 'splide__arrow--prev text-white icon-xs icon-chevron-small-left', 5200 next: 'splide__arrow--next text-white icon-xs icon-chevron-small-right', 5201 }, 5202 i18n: { 5203 prev: 'Slide precedente', 5204 next: 'Slide successiva', 5205 pageX: 'Vai alla pagina %s', 5206 slideX: 'Vai alla slide %s', 5207 first: 'Vai alla prima slide', 5208 last: 'Vai all\'ultima slide', 5209 play: 'Avvia riproduzione automatica', 5210 pause: 'Ferma riproduzione automatica', 5211 select: 'Seleziona la slide da visualizzare', 5212 slideLabel: '%s di %s' 5213 } 5214 } 5215 } else if ($(splideElem[i]).hasClass("splide-autoplay")) { 5216 arrOptions = { 5217 type: 'loop', 5218 perPage: 3, 5219 perMove: 1, 5220 autoplay: true, 5221 /* 5222 rewind: true, 5223 pauseOnHover: false, 5224 pauseOnFocus: false, 5225 focus: false, 5226 trimSpace: false, 5227 arrows: true, 5228 pagination: true, 5229 */ 5230 gap: 24, 5231 padding: { 5232 left: 0, 5233 right: 0, 5234 }, 5235 mediaQuery: 'min', 5236 breakpoints: bp, 5237 classes: { 5238 prev: 'splide__arrow--prev text-white icon-xs icon-chevron-small-left', 5239 next: 'splide__arrow--next text-white icon-xs icon-chevron-small-right', 5240 }, 5241 i18n: { 5242 prev: 'Slide precedente', 5243 next: 'Slide successiva', 5244 pageX: 'Vai alla pagina %s', 5245 slideX: 'Vai alla slide %s', 5246 first: 'Vai alla prima slide', 5247 last: 'Vai all\'ultima slide', 5248 play: 'Avvia riproduzione automatica', 5249 pause: 'Ferma riproduzione automatica', 5250 select: 'Seleziona la slide da visualizzare', 5251 slideLabel: '%s di %s' 5252 } 5253 } 5254 } else { 5255 arrOptions = { 5256 perPage: 3, 5257 perMove: 1, 5258 /* 5259 focus: false,
5260 trimSpace: false, 5261 arrows: true, 5262 pagination: true,*/ 5263 gap: 24, 5264 padding: { 5265 left: 0, 5266 right: 0, 5267 }, 5268 mediaQuery: 'min', 5269 breakpoints: bp, 5270 classes: { 5271 prev: 'splide__arrow--prev text-white icon-xs icon-chevron-small-left', 5272 next: 'splide__arrow--next text-white icon-xs icon-chevron-small-right', 5273 }, 5274 i18n: { 5275 prev: 'Slide precedente', 5276 next: 'Slide successiva', 5277 pageX: 'Vai alla pagina %s', 5278 slideX: 'Vai alla slide %s', 5279 first: 'Vai alla prima slide', 5280 last: 'Vai all\'ultima slide', 5281 select: 'Seleziona la slide da visualizzare', 5282 slideLabel: '%s di %s' 5283 } 5284 } 5285 } 5286 5287 if ($(splideElem[i]).hasClass("splide-subsite")) { 5288 id = $(splideElem[i]).closest(".section-subsite").attr("id"); 5289 if (id.includes('section-subsite')) { 5290 $('[id*="section-subsite"]').find(".img-wrapper").each(function () { 5291 $(this).find("img").not(":eq(0)").addClass("d-none"); 5292 }); 5293 new Splide(splideElem[i], arrOptions).mount().on('move', function (i) { 5294 $('[id*="section-subsite"]').find(".img-wrapper img").addClass("d-none"); 5295 $('[id*="section-subsite"]').find(".img-wrapper img:eq(" + (i + 1) + ")").removeClass("d-none") 5296 }); 5297 } 5298 } else { 5299 //MODIFICA SVILUPPO 5300 if(!splideElem[i].classList.contains('vue-splide')){ 5301 var splideInstance = new Splide(splideElem[i], arrOptions); 5302 splideInstance.mount(); 5303 SplideData.set(splideElem[i], splideInstance); 5304 } 5305 } 5306 } 5307 for (var i = 0; i < splideElem.length; i++) { 5308 if ($(splideElem[i]).hasClass("splide-thumb")) { 5309 SplideData.get(splideElem[i - 1]).sync(SplideData.get(splideElem[i])); 5310 } 5311 5312 if ($(splideElem[i]).hasClass("splide-thumb-video")) { 5313 var istanzaSplider = $(splideElem[i - 1]); 5314 SplideData.get(splideElem[i - 1]).on("active", function (e) { 5315 istanzaSplider.attr("tabindex", "0").focus(); 5316 $('html, body').animate({ 5317 scrollTop: $("#" + istanzaSplider.attr("id")).offset().top - 100 5318 }, 500); 5319 }); 5320 $(splideElem[i]).find("li").keydown(function (event) { 5321 if (event.which === 13) { 5322 indice = $(this).index() 5323 contentVideo = istanzaSplider.find("li:eq(" + $(this).index() + ")"); 5324 contentVideo.attr('tabindex', '0').focus(); 5325 5326 id = "#" + contentVideo.parent().attr("id"); 5327 $('html, body').animate({ 5328 scrollTop: $(id).offset().top - 100 5329 }, 500); 5330 } 5331 }); 5332 } 5333 } 5334} 5335/* 5336$(".splide-thumb li").keydown(function (event) { 5337 if (event.which === 13) { 5338 console.log('hai premuto enter sulla miniatura ') 5339 console.log($(this).parent().parent().parent().siblings().children()) 5340 5341 $(this).parent().parent().parent().siblings().children().attr('tabindex', '0').focus() 5342 } 5343}) */ 5344 5345// Carousel Subsite change images 5346$(document).on('mouseenter', '.splide-subsite .splide__slide .card', function () { 5347 eq = $(this).closest(".splide__slide").index(); 5348 $(this).closest(".section-subsite").find(".img-wrapper img").addClass("d-none"); 5349 $(this).closest(".section-subsite").find(".img-wrapper img:eq(" + (eq + 1) + ")").removeClass("d-none") 5350}); 5351$(document).on('mouseleave', '.splide-subsite', function () { 5352 $(this).closest(".section-subsite").find(".img-wrapper img").addClass("d-none"); 5353 $(this).closest(".section-subsite").find(".img-wrapper img:first").removeClass("d-none") 5354}); 5355 5356 5357// Modals autofocus 5358$('.modal').on('shown.bs.modal', function () { 5359 //$(this).trigger('focus'); 5360 //FIX: set focus on the first interactive element of the modal 5361 var focusableEls = []; 5362 SELECTOR_UIKIT_SCRIPT_FOCUSABLE_ARRAY.forEach(function(selector) { 5363 var tagName = selector.split('[')[0].split(':')[0]; 5364 var elements = Array.from(this.getElementsByTagName(tagName)); 5365 elements.forEach(function(el) { 5366 if (el.matches(selector)) { 5367 focusableEls.push(el); 5368 } 5369 }); 5370 }, this); 5371 if (focusableEls) { 5372 console.log({first: focusableEls[0]}); 5373 focusableEls[0].focus(); 5374 } 5375}) 5376$('.modal').on('hidden.bs.modal', function () { 5377 var caller = document.querySelector('[data-target="#' + $(this).attr('id') + '"]') 5378 if (caller) { 5379 caller.focus(); 5380 } 5381}) 5382 5383// Fotogallery 5384$(document).on('click', '[data-src-hq]', function (e) { 5385 if ($(this).closest(".fotogallery-slider").length <= 0 && $(this).closest(".infografica-slider").length <= 0) {
5386 if ($("#modal-zoom").length == 0) { 5387 modal = '<div class="modal modal-zoom" id="modal-zoom" tabindex="-1" role="dialog"><div class="modal-dialog" role="document"><div class="modal-content"><div class="modal-header"><h2 class="h3">Zoom immagine</h2><button type="button" class="close" data-dismiss="modal" aria-label="Chiudi"><span class="icon icon-close" aria-hidden="true"></span></button></div><div class="modal-body p-0"><figure><img src="" alt="" class="w-100 img-fluid"><figcaption><p></p></figcaption></figure></div></div></div></div>'; 5388 $("body").append(modal); 5389 } 5390 figcaption = $(this).parent().find("figcaption").text(); 5391 figure = $(this).attr("data-src-hq"); 5392 if (figcaption == "undefined") { 5393 figcaption = ""; 5394 } 5395 $("#modal-zoom figcaption p").html(figcaption); 5396 $("#modal-zoom img").attr("src", figure); 5397 $("#modal-zoom").modal("show"); 5398 } 5399 5400}); 5401 5402$(document).on('click', '.fotogallery-slider a', function (e) { 5403 $(".fotogallery-slider a").removeClass("active"); 5404 $(this).addClass("active"); 5405 id = $(this).closest(".fotogallery-slider").attr("data-slider-img"); 5406 figcaption = $(this).parent().find("figcaption").text(); 5407 figure = $(this).find("img").attr("data-src-hq"); 5408 if (figcaption == "undefined") { 5409 figcaption = ""; 5410 } 5411 $("#" + id + " figcaption p").html(figcaption); 5412 $("#" + id + " img").attr("src", figure); 5413 $("#" + id + " img").attr("data-src-hq", figure); 5414 e.preventDefault(); 5415}); 5416 5417 5418$(document).on('click', '.videogallery-slider a', function (e) { 5419 $(".videogallery-slider a").removeClass("active"); 5420 $(this).addClass("active"); 5421 id = "#" + $(this).attr("data-slider-video"); 5422 $(".videogallery > div").addClass("d-none"); 5423 $(id).removeClass("d-none"); 5424 $('html, body').animate({ 5425 scrollTop: $(id).offset().top - 200 5426 }, 500); 5427 // Servirebbe portare il focus sul video per accessibilità5428 e.preventDefault(); 5429}); 5430 5431 5432// Stycky top 5433$(document).ready(function () { 5434 // Custom 5435 var stickyToggle = function (sticky, stickyWrapper, scrollElement) { 5436 var stickyHeight = sticky.outerHeight(); 5437 var lastScrollTop = sticky.attr('data-scroll'); 5438 5439 if (scrollElement.scrollTop() == 0) { 5440 sticky.removeClass("is-sticky"); 5441 stickyWrapper.height('auto'); 5442 sticky.removeClass("is-sticky-onscroll"); 5443 } else if (scrollElement.scrollTop() < lastScrollTop) { 5444 sticky.addClass("is-sticky-onscroll"); 5445 } else if (scrollElement.scrollTop() >= lastScrollTop) { 5446 stickyWrapper.height(stickyHeight); 5447 sticky.addClass("is-sticky"); 5448 sticky.removeClass("is-sticky-onscroll"); 5449 } 5450 lastScrollTop = scrollElement.scrollTop(); 5451 sticky.attr('data-scroll', lastScrollTop); 5452 }; 5453 5454 // Find all data-toggle="sticky-onscroll" elements 5455 $('[data-toggle="sticky-onscroll"]').each(function () { 5456 var sticky = $(this); 5457 var stickyWrapper = $('<div>').addClass('sticky-wrapper'); // insert hidden element to maintain actual top offset on page 5458 sticky.before(stickyWrapper); 5459 sticky.addClass('sticky'); 5460 sticky.attr('data-scroll', '0'); 5461 5462 // Scroll & resize events 5463 // $(window).on('scroll.sticky-onscroll resize.sticky-onscroll', function() { 5464 $(window).on('scroll.is-sticky resize.is-sticky', function () { 5465 stickyToggle(sticky, stickyWrapper, $(this)); 5466 }); 5467 5468 // On page load 5469 stickyToggle(sticky, stickyWrapper, $(window)); 5470 }); 5471}); 5472 5473// Gestione focus 5474$(document).on("keydown mousedown", function (t) { 5475 e = "keydown" === t.type; 5476 k = $("[data-keyboard='true']").length; 5477 if (k == 0 && e) { 5478 $("html").attr("data-keyboard", e); 5479 } else if (k > 0 && e == false) { 5480 $("html").removeAttr("data-keyboard"); 5481 } 5482}) 5483 5484// Organigramma 5485if ($("img[usemap]").length) { 5486 $("img[usemap]").each(function () { 5487 $(this).rwdImageMaps(); 5488 id = "#" + $(this).closest("div").attr("id"); 5489 lc_mouseDrag(id, 0.3, false, false); 5490 }) 5491} 5492 5493// Dropdown search 5494$(".dropdown-menu-search .dropdown-item:not(.dropdown-item-link)").on('click', function (e) { 5495 $(".dropdown-menu-search .dropdown-item").removeClass("active"); 5496 $(this).addClass("active"); 5497 $(".btn-dropdown-search span").text($(this).text()); 5498 $(".dropdown-menu-search input[type=hidden]").val($(this).text()); 5499 e.preventDefault(); 5500}); 5501 5502$('#dropdown-menu-search').on('show.bs.dropdown', function () { 5503 $(".search-bar").addClass("active"); 5504}) 5505$('#dropdown-menu-search').on('hide.bs.dropdown', function () { 5506 $(".search-bar").removeClass("active"); 5507}) 5508$('#dropdown-header-search').on('show.bs.dropdown', function () { 5509 $(".divCerca").addClass("active"); 5510}) 5511$('#dropdown-header-search').on('hide.bs.dropdown', function () { 5512 $(".divCerca").removeClass("active"); 5513}) 5514 5515//custom splide per frecce quando sono meno di 4 card 5516if ($(".splide").length) { 5517 if ($(".splide.splide")) { 5518 $("[data-attr='cardGallery'] .splide__arrows").attr("data-attr", "card-gallery-arrows") 5519 const numeroCard = $("[data-attr='cardGallery'] ul.splide__list li").length 5520 let pagination = $("[data-attr='cardGallery'] .splide__pagination") 5521 if (numeroCard <= 3) { 5522 $("[data-attr='card-gallery-arrows']").toggle() 5523 arrOptions = {
5524 arrows: false 5525 } 5526 $(pagination).hide() 5527 } 5528 } 5529} 5530 5531//custom splide autoplay per frecce quando sono meno di 4 card 5532if ($(".splide").length) { 5533 if ($(".splide.splide-autoplay")) { 5534 $("[id*='carouselCard'].splide.splide-autoplay").each(function () { 5535 let carouselArrows = $(this).find(".splide__arrows") 5536 let pagination = $(this).find(".splide__pagination") 5537 carouselArrows.attr("data-attr", "carousel-card-arrows") 5538 const numeroCardTotale = $(this).find("ul.splide__list li") 5539 const numCardReali = $(numeroCardTotale).not(".splide__slide--clone").length 5540 if ($(this).hasClass("splide-4")) { 5541 if (numCardReali <= 4) { 5542 $(carouselArrows).hide() 5543 $(pagination).hide() 5544 } else { 5545 $(carouselArrows).show() 5546 $(pagination).show() 5547 } 5548 } else { 5549 if (numCardReali <= 3) { 5550 $(carouselArrows).hide() 5551 $(pagination).hide() 5552 } else { 5553 $(carouselArrows).show() 5554 $(pagination).show() 5555 } 5556 } 5557 }) 5558 } 5559} 5560 5561$(document).on('keypress', '.splide__slide', function (e) { 5562 if (e.keyCode == 13 || e.keyCode == 32) { 5563 $(".w-100 img-fluid").removeClass("active"); 5564 $(this).children().children().addClass("active"); 5565 id = $(this).children().children().closest(".fotogallery-slider").attr("data-slider-img"); 5566 figcaption = $(this).children().children().parent().find("figcaption").text(); 5567 figure = $(this).children().children().attr("data-src-hq"); 5568 if (figcaption == "undefined") { 5569 figcaption = ""; 5570 } 5571 $("#" + id + " figcaption p").html(figcaption); 5572 $("#" + id + " img").attr("src", figure); 5573 $("#" + id + " img").attr("data-src-hq", figure); 5574 } 5575}); 5576 5577 5578// Script per creazione dinamica aria-label degli accordion 5579$('button[id*=accordion]').each(function () { 5580 let accordion = $(this) 5581 let buttonText = $(accordion).children().eq(0).text() 5582 5583 if ($(accordion).attr('aria-expanded') == "true") { 5584 $(accordion).attr('aria-label', buttonText + ' Aperto') 5585 } else { 5586 $(accordion).attr('aria-label', buttonText + ' Chiuso') 5587 } 5588 5589 $(accordion).on('click', function () { 5590 let value = $(accordion).attr('aria-expanded') 5591 if (value == 'false') { 5592 $(accordion).attr('aria-label', buttonText + ' Aperto') 5593 } else { 5594 $(accordion).attr('aria-label', buttonText + ' Chiuso') 5595 } 5596 }) 5597 5598 5599 $(accordion).on('keydown', function (e) { 5600 if (e.key === 'Enter' || e.key === ' ') { 5601 e.preventDefault() 5602 let value = $(accordion).attr('aria-expanded') 5603 if (value == 'false') { 5604 $(accordion).attr('aria-label', buttonText + ' Aperto') 5605 } else { 5606 $(accordion).attr('aria-label', buttonText + ' Chiuso') 5607 } 5608 } 5609 }) 5610}) 5611 5612 5613 5614function trapFocus(element) { 5615 var focusableEls = getFocusableElements(element); 5616 var firstFocusableEl = focusableEls[0]; 5617 var lastFocusableEl = focusableEls[focusableEls.length - 1]; 5618 var KEYCODE_TAB = 9; 5619 5620 element.addEventListener('keydown', function (e) { 5621 var isTabPressed = (e.key === 'Tab' || e.keyCode === KEYCODE_TAB); 5622 5623 if (!isTabPressed) { 5624 return; 5625 } 5626 5627 if (e.shiftKey) /* shift + tab */ { 5628 if (document.activeElement === firstFocusableEl) {
5629 lastFocusableEl.focus(); 5630 e.preventDefault(); 5631 } 5632 } else /* tab */ { 5633 if (document.activeElement === lastFocusableEl) { 5634 firstFocusableEl.focus(); 5635 e.preventDefault(); 5636 } 5637 } 5638 }); 5639} 5640 5641function getFocusableElements(element) { 5642 var allElements, focusableEls, i; 5643 5644 allElements = element.getElementsByTagName("*"); 5645 focusableEls = []; 5646 5647 for (i = 0; i < allElements.length; i++) { 5648 if (isFocusableElement(allElements[i])) { 5649 focusableEls.push(allElements[i]); 5650 } 5651 } 5652 return focusableEls; 5653} 5654 5655function isFocusableElement(element) { 5656 var tagName, inputType; 5657 5658 tagName = element.tagName.toLowerCase(); 5659 5660 if (tagName === 'span' || tagName === 'h2' || tagName === 'p') { 5661 return true; 5662 } 5663 5664 if (tagName === 'a') { 5665 return element.getAttribute('href') && !element.disabled; 5666 } 5667 5668 if (tagName === 'button' || tagName === 'textarea' || tagName === 'select') { 5669 return !element.disabled; 5670 } 5671 5672 if (tagName === 'input') { 5673 inputType = element.getAttribute('type'); 5674 5675 return !element.disabled && (inputType === 'text' || inputType === 'radio' || inputType === 'checkbox'); 5676 } 5677 5678 return false; 5679} 5680 5681// if ($("#menu-top").length) { 5682// var trapMenuTop = document.getElementById('menu-top') 5683// trapFocus(trapMenuTop) 5684// } 5685 5686if ($("#cerca-top").length && window.innerWidth < 992) { 5687 var trapCercaTop = document.getElementById('cerca-top') 5688 trapFocus(trapCercaTop) 5689} 5690 5691if ($("#sidebar-menu-mobile.show").length) { 5692 var trapMenuMobile = document.getElementById('sidebar-menu-mobile.show') 5693 trapFocus(trapMenuMobile) 5694} 5695 5696//FIX: modal focus trap 5697const modals = document.querySelectorAll('.modal'); 5698modals.forEach(modal => { 5699 trapFocus(modal); 5700}); 5701 5702function moveButton() { 5703 $('#scroll-top-btn').attr('class', (i, prevClass) => { 5704 return prevClass + ' captcha' 5705 }) 5706} 5707 5708$(function () { 5709 var isEditor = window.Granite && window.Granite.author ? true : false; 5710 if (isEditor) { 5711 $(document).on("foundation-contentloaded", function () { 5712 if ($('[data-toggle="popover"]') != null && $('[data-toggle="popover"]').length > 0) $('[data-toggle="popover"]').popover(); 5713 }) 5714 } else { 5715 if ($('[data-toggle="popover"]') != null && $('[data-toggle="popover"]').length > 0) $('[data-toggle="popover"]').popover(); 5716 } 5717 if(self !== top){ 5718 $('.container-main').removeClass("h-100vh"); 5719 } 5720})
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.