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 * Copyright 2018 Adobe 674 * 675 * Licensed under the Apache License, Version 2.0 (the "License");
676 * you may not use this file except in compliance with the License. 677 * You may obtain a copy of the License at 678 * 679 * http://www.apache.org/licenses/LICENSE2.0 680 * 681 * Unless required by applicable law or agreed to in writing, software 682 * distributed under the License is distributed on an "AS IS" BASIS, 683 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 684 * See the License for the specific language governing permissions and 685 * limitations under the License. 686 ******************************************************************************/ 687 688/** 689 * Element.matches() 690 * https://developer.mozilla.org/enUS/docs/Web/API/Element/matches#Polyfill 691 */ 692if (!Element.prototype.matches) { 693 Element.prototype.matches = Element.prototype.msMatchesSelector || Element.prototype.webkitMatchesSelector; 694} 695 696// eslint-disable-next-line valid-jsdoc 697/** 698 * Element.closest() 699 * https://developer.mozilla.org/enUS/docs/Web/API/Element/closest#Polyfill 700 */ 701if (!Element.prototype.closest) { 702 Element.prototype.closest = function(s) { 703 "use strict"; 704 var el = this; 705 if (!document.documentElement.contains(el)) { 706 return null; 707 } 708 do { 709 if (el.matches(s)) { 710 return el; 711 } 712 el = el.parentElement || el.parentNode; 713 } while (el !== null && el.nodeType === 1); 714 return null; 715 }; 716} 717 718/******************************************************************************* 719 * Copyright 2018 Adobe 720 * 721 * Licensed under the Apache License, Version 2.0 (the "License"); 722 * you may not use this file except in compliance with the License. 723 * You may obtain a copy of the License at 724 * 725 * http://www.apache.org/licenses/LICENSE-2.0 726 * 727 * Unless required by applicable law or agreed to in writing, software 728 * distributed under the License is distributed on an "AS IS" BASIS, 729 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 730 * See the License for the specific language governing permissions and 731 * limitations under the License. 732 ******************************************************************************/ 733/* global 734 CQ 735 */ 736(function() { 737 "use strict"; 738 739 var containerUtils = window.CQ && window.CQ.CoreComponents && window.CQ.CoreComponents.container && window.CQ.CoreComponents.container.utils ? window.CQ.CoreComponents.container.utils : undefined; 740 if (!containerUtils) { 741 // eslint-disable-next-line no-console 742 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."); 743 } 744 var dataLayerEnabled; 745 var dataLayer; 746 var dataLayerName; 747 748 var NS = "cmp"; 749 var IS = "tabs"; 750 751 var keyCodes = { 752 END: 35, 753 HOME: 36, 754 ARROW_LEFT: 37, 755 ARROW_UP: 38, 756 ARROW_RIGHT: 39, 757 ARROW_DOWN: 40 758 }; 759 760 var selectors = { 761 self: "[data-" + NS + '-is="' + IS + '"]', 762 active: { 763 tab: "cmp-tabs__tab--active", 764 tabpanel: "cmp-tabs__tabpanel--active" 765 } 766 }; 767 768 /** 769 * Tabs Configuration 770 * 771 * @typedef {Object} TabsConfig Represents a Tabs configuration 772 * @property {HTMLElement} element The HTMLElement representing the Tabs 773 * @property {Object} options The Tabs options 774 */ 775 776 /** 777 * Tabs 778 * 779 * @class Tabs 780 * @classdesc An interactive Tabs component for navigating a list of tabs 781 * @param {TabsConfig} config The Tabs configuration 782 */ 783 function Tabs(config) { 784 var that = this; 785 786 if (config && config.element) { 787 init(config); 788 } 789 790 /** 791 * Initializes the Tabs 792 * 793 * @private 794 * @param {TabsConfig} config The Tabs configuration 795 */ 796 function init(config) { 797 that._config = config; 798 799 // prevents multiple initialization 800 config.element.removeAttribute("data-" + NS + "-is"); 801 802 cacheElements(config.element); 803 that._active = getActiveIndex(that._elements["tab"]); 804 805 if (that._elements.tabpanel) { 806 refreshActive(); 807 bindEvents(); 808 scrollToDeepLinkIdInTabs(); 809 } 810 811 if (window.Granite && window.Granite.author && window.Granite.author.MessageChannel) { 812 /* 813 * Editor message handling: 814 * - subscribe to "cmp.panelcontainer" message requests sent by the editor frame
815 * - check that the message data panel container type is correct and that the id (path) matches this specific Tabs component 816 * - if so, route the "navigate" operation to enact a navigation of the Tabs based on index data 817 */ 818 CQ.CoreComponents.MESSAGE_CHANNEL = CQ.CoreComponents.MESSAGE_CHANNEL || new window.Granite.author.MessageChannel("cqauthor", window); 819 CQ.CoreComponents.MESSAGE_CHANNEL.subscribeRequestMessage("cmp.panelcontainer", function(message) { 820 if (message.data && message.data.type === "cmp-tabs" && message.data.id === that._elements.self.dataset["cmpPanelcontainerId"]) { 821 if (message.data.operation === "navigate") { 822 navigate(message.data.index); 823 } 824 } 825 }); 826 } 827 } 828 829 /** 830 * Displays the panel containing the element that corresponds to the deep link in the URI fragment 831 * and scrolls the browser to this element. 832 */ 833 function scrollToDeepLinkIdInTabs() { 834 if (containerUtils) { 835 var deepLinkItemIdx = containerUtils.getDeepLinkItemIdx(that, "tab", "tabpanel"); 836 if (deepLinkItemIdx > -1) { 837 var deepLinkItem = that._elements["tab"][deepLinkItemIdx]; 838 if (deepLinkItem && that._elements["tab"][that._active].id !== deepLinkItem.id) { 839 navigateAndFocusTab(deepLinkItemIdx, true); 840 } 841 var hashId = window.location.hash.substring(1); 842 if (hashId) { 843 var hashItem = document.querySelector("[id='" + hashId + "']"); 844 if (hashItem) { 845 hashItem.scrollIntoView(); 846 } 847 } 848 } 849 } 850 } 851 852 /** 853 * Returns the index of the active tab, if no tab is active returns 0 854 * 855 * @param {Array} tabs Tab elements 856 * @returns {Number} Index of the active tab, 0 if none is active 857 */ 858 function getActiveIndex(tabs) { 859 if (tabs) { 860 for (var i = 0; i < tabs.length; i++) { 861 if (tabs[i].classList.contains(selectors.active.tab)) { 862 return i; 863 } 864 } 865 } 866 return 0; 867 } 868 869 /** 870 * Caches the Tabs elements as defined via the {@code data-tabs-hook="ELEMENT_NAME"} markup API 871 * 872 * @private 873 * @param {HTMLElement} wrapper The Tabs wrapper element 874 */ 875 function cacheElements(wrapper) { 876 that._elements = {}; 877 that._elements.self = wrapper; 878 var hooks = that._elements.self.querySelectorAll("[data-" + NS + "-hook-" + IS + "]"); 879 880 for (var i = 0; i < hooks.length; i++) { 881 var hook = hooks[i]; 882 if (hook.closest("." + NS + "-" + IS) === that._elements.self) { // only process own tab elements 883 var capitalized = IS; 884 capitalized = capitalized.charAt(0).toUpperCase() + capitalized.slice(1); 885 var key = hook.dataset[NS + "Hook" + capitalized]; 886 if (that._elements[key]) { 887 if (!Array.isArray(that._elements[key])) { 888 var tmp = that._elements[key]; 889 that._elements[key] = [tmp]; 890 } 891 that._elements[key].push(hook); 892 } else { 893 that._elements[key] = hook; 894 } 895 } 896 } 897 } 898 899 /** 900 * Binds Tabs event handling 901 * 902 * @private 903 */ 904 function bindEvents() { 905 window.addEventListener("hashchange", scrollToDeepLinkIdInTabs, false); 906 var tabs = that._elements["tab"]; 907 if (tabs) { 908 for (var i = 0; i < tabs.length; i++) { 909 (function(index) { 910 tabs[i].addEventListener("click", function(event) { 911 navigateAndFocusTab(index); 912 }); 913 tabs[i].addEventListener("keydown", function(event) { 914 onKeyDown(event); 915 }); 916 })(i); 917 } 918 } 919 } 920 921 /** 922 * Handles tab keydown events 923 * 924 * @private 925 * @param {Object} event The keydown event 926 */ 927 function onKeyDown(event) { 928 var index = that._active; 929 var lastIndex = that._elements["tab"].length - 1; 930 931 switch (event.keyCode) { 932 case keyCodes.ARROW_LEFT: 933 case keyCodes.ARROW_UP: 934 event.preventDefault(); 935 if (index > 0) { 936 navigateAndFocusTab(index - 1); 937 } 938 break; 939 case keyCodes.ARROW_RIGHT: 940 case keyCodes.ARROW_DOWN: 941 event.preventDefault(); 942 if (index < lastIndex) { 943 navigateAndFocusTab(index + 1); 944 } 945 break; 946 case keyCodes.HOME: 947 event.preventDefault(); 948 navigateAndFocusTab(0); 949 break; 950 case keyCodes.END: 951 event.preventDefault(); 952 navigateAndFocusTab(lastIndex); 953 break; 954 default: 955 return; 956 } 957 } 958 959 /** 960 * Refreshes the tab markup based on the current {@code Tabs#_active} index 961 * 962 * @private 963 */ 964 function refreshActive() { 965 var tabpanels = that._elements["tabpanel"]; 966 var tabs = that._elements["tab"]; 967 968 if (tabpanels) { 969 if (Array.isArray(tabpanels)) { 970 for (var i = 0; i < tabpanels.length; i++) { 971 if (i === parseInt(that._active)) { 972 tabpanels[i].classList.add(selectors.active.tabpanel); 973 tabpanels[i].removeAttribute("aria-hidden"); 974 tabs[i].classList.add(selectors.active.tab); 975 tabs[i].setAttribute("aria-selected", true); 976 tabs[i].setAttribute("tabindex", "0"); 977 } else { 978 tabpanels[i].classList.remove(selectors.active.tabpanel); 979 tabpanels[i].setAttribute("aria-hidden", true); 980 tabs[i].classList.remove(selectors.active.tab); 981 tabs[i].setAttribute("aria-selected", false); 982 tabs[i].setAttribute("tabindex", "-1"); 983 } 984 } 985 } else { 986 // only one tab 987 tabpanels.classList.add(selectors.active.tabpanel); 988 tabs.classList.add(selectors.active.tab); 989 } 990 } 991 } 992 993 /** 994 * Focuses the element and prevents scrolling the element into view 995 * 996 * @param {HTMLElement} element Element to focus 997 */ 998 function focusWithoutScroll(element) { 999 var x = window.scrollX || window.pageXOffset; 1000 var y = window.scrollY || window.pageYOffset; 1001 element.focus(); 1002 window.scrollTo(x, y); 1003 } 1004 1005 /** 1006 * Navigates to the tab at the provided index 1007 * 1008 * @private 1009 * @param {Number} index The index of the tab to navigate to 1010 */ 1011 function navigate(index) { 1012 that._active = index; 1013 refreshActive(); 1014 } 1015 1016 /** 1017 * Navigates to the item at the provided index and ensures the active tab gains focus 1018 * 1019 * @private 1020 * @param {Number} index The index of the item to navigate to 1021 * @param {Boolean} keepHash true to keep the hash in the URL, false to update it 1022 */ 1023 function navigateAndFocusTab(index, keepHash) { 1024 var exActive = that._active; 1025 if (!keepHash && containerUtils) { 1026 containerUtils.updateUrlHash(that, "tab", index); 1027 } 1028 navigate(index); 1029 focusWithoutScroll(that._elements["tab"][index]); 1030 1031 if (dataLayerEnabled) { 1032 1033 var activeItem = getDataLayerId(that._elements.tabpanel[index]); 1034 var exActiveItem = getDataLayerId(that._elements.tabpanel[exActive]); 1035 1036 dataLayer.push({ 1037 event: "cmp:show", 1038 eventInfo: { 1039 path: "component." + activeItem 1040 } 1041 }); 1042 1043 dataLayer.push({ 1044 event: "cmp:hide", 1045 eventInfo: { 1046 path: "component." + exActiveItem 1047 } 1048 }); 1049 1050 var tabsId = that._elements.self.id; 1051 var uploadPayload = { component: {} }; 1052 uploadPayload.component[tabsId] = { shownItems: [activeItem] }; 1053 1054 var removePayload = { component: {} }; 1055 removePayload.component[tabsId] = { shownItems: undefined }; 1056 1057 dataLayer.push(removePayload); 1058 dataLayer.push(uploadPayload); 1059 } 1060 } 1061 } 1062 1063 /**
1064 * Reads options data from the Tabs wrapper element, defined via {@code data-cmp-*} data attributes 1065 * 1066 * @private 1067 * @param {HTMLElement} element The Tabs element to read options data from 1068 * @returns {Object} The options read from the component data attributes 1069 */ 1070 function readData(element) { 1071 var data = element.dataset; 1072 var options = []; 1073 var capitalized = IS; 1074 capitalized = capitalized.charAt(0).toUpperCase() + capitalized.slice(1); 1075 var reserved = ["is", "hook" + capitalized]; 1076 1077 for (var key in data) { 1078 if (Object.prototype.hasOwnProperty.call(data, key)) { 1079 var value = data[key]; 1080 1081 if (key.indexOf(NS) === 0) { 1082 key = key.slice(NS.length); 1083 key = key.charAt(0).toLowerCase() + key.substring(1); 1084 1085 if (reserved.indexOf(key) === -1) { 1086 options[key] = value; 1087 } 1088 } 1089 } 1090 } 1091 1092 return options; 1093 } 1094 1095 /** 1096 * Parses the dataLayer string and returns the ID 1097 * 1098 * @private 1099 * @param {HTMLElement} item the accordion item 1100 * @returns {String} dataLayerId or undefined 1101 */ 1102 function getDataLayerId(item) { 1103 if (item) { 1104 if (item.dataset.cmpDataLayer) { 1105 return Object.keys(JSON.parse(item.dataset.cmpDataLayer))[0]; 1106 } else { 1107 return item.id; 1108 } 1109 } 1110 return null; 1111 } 1112 1113 /** 1114 * Document ready handler and DOM mutation observers. Initializes Tabs components as necessary. 1115 * 1116 * @private 1117 */ 1118 function onDocumentReady() { 1119 dataLayerEnabled = document.body.hasAttribute("data-cmp-data-layer-enabled"); 1120 if (dataLayerEnabled) { 1121 dataLayerName = document.body.getAttribute("data-cmp-data-layer-name") || "adobeDataLayer"; 1122 dataLayer = window[dataLayerName] = window[dataLayerName] || []; 1123 } 1124 1125 var elements = document.querySelectorAll(selectors.self); 1126 for (var i = 0; i < elements.length; i++) { 1127 new Tabs({ element: elements[i], options: readData(elements[i]) }); 1128 } 1129 1130 var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver; 1131 var body = document.querySelector("body"); 1132 var observer = new MutationObserver(function(mutations) { 1133 mutations.forEach(function(mutation) { 1134 // needed for IE 1135 var nodesArray = [].slice.call(mutation.addedNodes); 1136 if (nodesArray.length > 0) { 1137 nodesArray.forEach(function(addedNode) { 1138 if (addedNode.querySelectorAll) { 1139 var elementsArray = [].slice.call(addedNode.querySelectorAll(selectors.self)); 1140 elementsArray.forEach(function(element) { 1141 new Tabs({ element: element, options: readData(element) }); 1142 }); 1143 } 1144 }); 1145 } 1146 }); 1147 }); 1148 1149 observer.observe(body, { 1150 subtree: true, 1151 childList: true, 1152 characterData: true 1153 }); 1154 } 1155 1156 if (document.readyState !== "loading") { 1157 onDocumentReady(); 1158 } else { 1159 document.addEventListener("DOMContentLoaded", onDocumentReady); 1160 } 1161 1162 if (containerUtils) { 1163 window.addEventListener("load", containerUtils.scrollToAnchor, false); 1164 } 1165 1166}()); 1167 1168/******************************************************************************* 1169 * Copyright 2022 Adobe 1170 * 1171 * Licensed under the Apache License, Version 2.0 (the "License"); 1172 * you may not use this file except in compliance with the License. 1173 * You may obtain a copy of the License at 1174 * 1175 * http://www.apache.org/licenses/LICENSE-2.0 1176 * 1177 * Unless required by applicable law or agreed to in writing, software 1178 * distributed under the License is distributed on an "AS IS" BASIS, 1179 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1180 * See the License for the specific language governing permissions and 1181 * limitations under the License. 1182 ******************************************************************************/ 1183(function(document) { 1184 "use strict"; 1185 1186 window.CMP = window.CMP || {}; 1187 window.CMP.utils = (function() { 1188 var NS = "cmp"; 1189 1190 /**
1191 * Reads options data from the Component wrapper element, defined via {@code data-cmp-*} data attributes 1192 * 1193 * @param {HTMLElement} element The component element to read options data from 1194 * @param {String} is The component identifier 1195 * @returns {String[]} The options read from the component data attributes 1196 */ 1197 var readData = function(element, is) { 1198 var data = element.dataset; 1199 var options = []; 1200 var capitalized = is; 1201 capitalized = capitalized.charAt(0).toUpperCase() + capitalized.slice(1); 1202 var reserved = ["is", "hook" + capitalized]; 1203 1204 for (var key in data) { 1205 if (Object.prototype.hasOwnProperty.call(data, key)) { 1206 var value = data[key]; 1207 1208 if (key.indexOf(NS) === 0) { 1209 key = key.slice(NS.length); 1210 key = key.charAt(0).toLowerCase() + key.substring(1); 1211 1212 if (reserved.indexOf(key) === -1) { 1213 options[key] = value; 1214 } 1215 } 1216 } 1217 } 1218 return options; 1219 }; 1220 1221 /** 1222 * Set up the final properties of a component by evaluating the transform function or fall back to the default value on demand 1223 * @param {String[]} options the options to transform 1224 * @param {Object} properties object of properties of property functions 1225 * @returns {Object} transformed properties 1226 */ 1227 var setupProperties = function(options, properties) { 1228 var transformedProperties = {}; 1229 1230 for (var key in properties) { 1231 if (Object.prototype.hasOwnProperty.call(properties, key)) { 1232 var property = properties[key]; 1233 if (options && options[key] != null) { 1234 if (property && typeof property.transform === "function") { 1235 transformedProperties[key] = property.transform(options[key]); 1236 } else { 1237 transformedProperties[key] = options[key]; 1238 } 1239 } else { 1240 transformedProperties[key] = properties[key]["default"]; 1241 } 1242 } 1243 } 1244 return transformedProperties; 1245 }; 1246 1247 1248 return { 1249 readData: readData, 1250 setupProperties: setupProperties 1251 }; 1252 }()); 1253}(window.document)); 1254 1255/******************************************************************************* 1256 * Copyright 2018 Adobe 1257 * 1258 * Licensed under the Apache License, Version 2.0 (the "License"); 1259 * you may not use this file except in compliance with the License. 1260 * You may obtain a copy of the License at 1261 * 1262 * http://www.apache.org/licenses/LICENSE-2.0 1263 * 1264 * Unless required by applicable law or agreed to in writing, software 1265 * distributed under the License is distributed on an "AS IS" BASIS, 1266 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1267 * See the License for the specific language governing permissions and 1268 * limitations under the License. 1269 ******************************************************************************/ 1270(function() { 1271 "use strict"; 1272 1273 var containerUtils = window.CQ && window.CQ.CoreComponents && window.CQ.CoreComponents.container && window.CQ.CoreComponents.container.utils ? window.CQ.CoreComponents.container.utils : undefined; 1274 if (!containerUtils) { 1275 // eslint-disable-next-line no-console 1276 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."); 1277 } 1278 var dataLayerEnabled; 1279 var dataLayer; 1280 var dataLayerName; 1281 1282 var NS = "cmp"; 1283 var IS = "carousel"; 1284 1285 var keyCodes = { 1286 SPACE: 32, 1287 END: 35, 1288 HOME: 36, 1289 ARROW_LEFT: 37, 1290 ARROW_UP: 38, 1291 ARROW_RIGHT: 39, 1292 ARROW_DOWN: 40 1293 }; 1294 1295 var selectors = { 1296 self: "[data-" + NS + '-is="' + IS + '"]' 1297 }; 1298 1299 var properties = { 1300 /** 1301 * Determines whether the Carousel will automatically transition between slides 1302 * 1303 * @memberof Carousel
1304 * @type {Boolean} 1305 * @default false 1306 */ 1307 "autoplay": { 1308 "default": false, 1309 "transform": function(value) { 1310 return !(value === null || typeof value === "undefined"); 1311 } 1312 }, 1313 /** 1314 * Duration (in milliseconds) before automatically transitioning to the next slide 1315 * 1316 * @memberof Carousel 1317 * @type {Number} 1318 * @default 5000 1319 */ 1320 "delay": { 1321 "default": 5000, 1322 "transform": function(value) { 1323 value = parseFloat(value); 1324 return !isNaN(value) ? value : null; 1325 } 1326 }, 1327 /** 1328 * Determines whether automatic pause on hovering the carousel is disabled 1329 * 1330 * @memberof Carousel 1331 * @type {Boolean} 1332 * @default false 1333 */ 1334 "autopauseDisabled": { 1335 "default": false, 1336 "transform": function(value) { 1337 return !(value === null || typeof value === "undefined"); 1338 } 1339 } 1340 }; 1341 1342 /** 1343 * Carousel Configuration 1344 * 1345 * @typedef {Object} CarouselConfig Represents a Carousel configuration 1346 * @property {HTMLElement} element The HTMLElement representing the Carousel 1347 * @property {*[]} options The Carousel options 1348 */ 1349 1350 /** 1351 * Carousel 1352 * 1353 * @class Carousel 1354 * @classdesc An interactive Carousel component for navigating a list of generic items 1355 * @param {CarouselConfig} config The Carousel configuration 1356 */ 1357 function Carousel(config) { 1358 var that = this; 1359 1360 if (config && config.element) { 1361 init(config); 1362 } 1363 1364 /** 1365 * Initializes the Carousel 1366 * 1367 * @private 1368 * @param {CarouselConfig} config The Carousel configuration 1369 */ 1370 function init(config) { 1371 that._config = config; 1372 1373 // prevents multiple initialization 1374 config.element.removeAttribute("data-" + NS + "-is"); 1375 1376 setupProperties(config.options); 1377 cacheElements(config.element); 1378 1379 that._active = 0; 1380 that._paused = false; 1381 1382 if (that._elements.item) { 1383 initializeActive(); 1384 bindEvents(); 1385 resetAutoplayInterval(); 1386 refreshPlayPauseActions(); 1387 scrollToDeepLinkIdInCarousel(); 1388 } 1389 1390 // TODO: This section is only relevant in edit mode and should move to the editor clientLib 1391 if (window.Granite && window.Granite.author && window.Granite.author.MessageChannel) { 1392 /* 1393 * Editor message handling: 1394 * - subscribe to "cmp.panelcontainer" message requests sent by the editor frame 1395 * - check that the message data panel container type is correct and that the id (path) matches this specific Carousel component 1396 * - if so, route the "navigate" operation to enact a navigation of the Carousel based on index data 1397 */ 1398 window.CQ = window.CQ || {}; 1399 window.CQ.CoreComponents = window.CQ.CoreComponents || {}; 1400 window.CQ.CoreComponents.MESSAGE_CHANNEL = window.CQ.CoreComponents.MESSAGE_CHANNEL || new window.Granite.author.MessageChannel("cqauthor", window); 1401 window.CQ.CoreComponents.MESSAGE_CHANNEL.subscribeRequestMessage("cmp.panelcontainer", function(message) { 1402 if (message.data && message.data.type === "cmp-carousel" && message.data.id === that._elements.self.dataset["cmpPanelcontainerId"]) { 1403 if (message.data.operation === "navigate") { 1404 navigate(message.data.index); 1405 } 1406 } 1407 }); 1408 } 1409 } 1410 1411 /** 1412 * Displays the slide containing the element that corresponds to the deep link in the URI fragment 1413 * and scrolls the browser to this element. 1414 */ 1415 function scrollToDeepLinkIdInCarousel() { 1416 if (containerUtils) { 1417 var deepLinkItemIdx = containerUtils.getDeepLinkItemIdx(that, "item", "item"); 1418 if (deepLinkItemIdx > -1) { 1419 var deepLinkItem = that._elements["item"][deepLinkItemIdx]; 1420 if (deepLinkItem && that._elements["item"][that._active].id !== deepLinkItem.id) { 1421 navigateAndFocusIndicator(deepLinkItemIdx, true); 1422 // pause the carousel auto-rotation 1423 pause(); 1424 } 1425 var hashId = window.location.hash.substring(1); 1426 if (hashId) { 1427 var hashItem = document.querySelector("[id='" + hashId + "']"); 1428 if (hashItem) { 1429 hashItem.scrollIntoView(); 1430 } 1431 } 1432 } 1433 } 1434 } 1435 1436 /** 1437 * Caches the Carousel elements as defined via the {@code data-carousel-hook="ELEMENT_NAME"} markup API 1438 * 1439 * @private 1440 * @param {HTMLElement} wrapper The Carousel wrapper element 1441 */ 1442 function cacheElements(wrapper) { 1443 that._elements = {}; 1444 that._elements.self = wrapper; 1445 var hooks = that._elements.self.querySelectorAll("[data-" + NS + "-hook-" + IS + "]"); 1446 1447 for (var i = 0; i < hooks.length; i++) { 1448 var hook = hooks[i]; 1449 var capitalized = IS; 1450 capitalized = capitalized.charAt(0).toUpperCase() + capitalized.slice(1); 1451 var key = hook.dataset[NS + "Hook" + capitalized]; 1452 if (that._elements[key]) { 1453 if (!Array.isArray(that._elements[key])) { 1454 var tmp = that._elements[key]; 1455 that._elements[key] = [tmp]; 1456 } 1457 that._elements[key].push(hook); 1458 } else { 1459 that._elements[key] = hook; 1460 } 1461 } 1462 } 1463 1464 /** 1465 * Sets up properties for the Carousel based on the passed options. 1466 * 1467 * @private 1468 * @param {Object} options The Carousel options 1469 */ 1470 function setupProperties(options) { 1471 that._properties = {}; 1472 1473 for (var key in properties) { 1474 if (Object.prototype.hasOwnProperty.call(properties, key)) { 1475 var property = properties[key]; 1476 var value = null; 1477 1478 if (options && options[key] != null) { 1479 value = options[key]; 1480 1481 // transform the provided option 1482 if (property && typeof property.transform === "function") { 1483 value = property.transform(value); 1484 } 1485 } 1486 1487 if (value === null) { 1488 // value still null, take the property default 1489 value = properties[key]["default"]; 1490 } 1491 1492 that._properties[key] = value; 1493 } 1494 } 1495 } 1496 1497 /** 1498 * Binds Carousel event handling 1499 * 1500 * @private 1501 */ 1502 function bindEvents() { 1503 window.addEventListener("hashchange", scrollToDeepLinkIdInCarousel, false); 1504 if (that._elements["previous"]) { 1505 that._elements["previous"].addEventListener("click", function() { 1506 var index = getPreviousIndex(); 1507 navigate(index); 1508 if (dataLayerEnabled) { 1509 dataLayer.push({ 1510 event: "cmp:show", 1511 eventInfo: { 1512 path: "component." + getDataLayerId(that._elements.item[index]) 1513 } 1514 }); 1515 } 1516 }); 1517 } 1518 1519 if (that._elements["next"]) { 1520 that._elements["next"].addEventListener("click", function() { 1521 var index = getNextIndex(); 1522 navigate(index); 1523 if (dataLayerEnabled) { 1524 dataLayer.push({ 1525 event: "cmp:show", 1526 eventInfo: { 1527 path: "component." + getDataLayerId(that._elements.item[index]) 1528 } 1529 }); 1530 } 1531 }); 1532 } 1533 1534 var indicators = that._elements["indicator"]; 1535 if (indicators) { 1536 for (var i = 0; i < indicators.length; i++) { 1537 (function(index) { 1538 indicators[i].addEventListener("click", function(event) { 1539 navigateAndFocusIndicator(index); 1540 // pause the carousel auto-rotation 1541 pause(); 1542 }); 1543 })(i); 1544 } 1545 } 1546 1547 if (that._elements["pause"]) { 1548 if (that._properties.autoplay) { 1549 that._elements["pause"].addEventListener("click", onPauseClick); 1550 } 1551 } 1552 1553 if (that._elements["play"]) { 1554 if (that._properties.autoplay) { 1555 that._elements["play"].addEventListener("click", onPlayClick); 1556 } 1557 } 1558 1559 that._elements.self.addEventListener("keydown", onKeyDown); 1560 1561 if (!that._properties.autopauseDisabled) { 1562 that._elements.self.addEventListener("mouseenter", onMouseEnter); 1563 that._elements.self.addEventListener("mouseleave", onMouseLeave); 1564 } 1565 1566 // for accessibility we pause animation when a element get focused 1567 var items = that._elements["item"]; 1568 if (items) { 1569 for (var j = 0; j < items.length; j++) { 1570 items[j].addEventListener("focusin", onMouseEnter); 1571 items[j].addEventListener("focusout", onMouseLeave); 1572 } 1573 } 1574 } 1575 1576 /**
1577 * Handles carousel keydown events 1578 * 1579 * @private 1580 * @param {Object} event The keydown event 1581 */ 1582 function onKeyDown(event) { 1583 var index = that._active; 1584 var lastIndex = that._elements["indicator"].length - 1; 1585 1586 switch (event.keyCode) { 1587 case keyCodes.ARROW_LEFT: 1588 case keyCodes.ARROW_UP: 1589 event.preventDefault(); 1590 if (index > 0) { 1591 navigateAndFocusIndicator(index - 1); 1592 } 1593 break; 1594 case keyCodes.ARROW_RIGHT: 1595 case keyCodes.ARROW_DOWN: 1596 event.preventDefault(); 1597 if (index < lastIndex) { 1598 navigateAndFocusIndicator(index + 1); 1599 } 1600 break; 1601 case keyCodes.HOME: 1602 event.preventDefault(); 1603 navigateAndFocusIndicator(0); 1604 break; 1605 case keyCodes.END: 1606 event.preventDefault(); 1607 navigateAndFocusIndicator(lastIndex); 1608 break; 1609 case keyCodes.SPACE: 1610 if (that._properties.autoplay && (event.target !== that._elements["previous"] && event.target !== that._elements["next"])) { 1611 event.preventDefault(); 1612 if (!that._paused) { 1613 pause(); 1614 } else { 1615 play(); 1616 } 1617 } 1618 if (event.target === that._elements["pause"]) { 1619 that._elements["play"].focus(); 1620 } 1621 if (event.target === that._elements["play"]) { 1622 that._elements["pause"].focus(); 1623 } 1624 break; 1625 default: 1626 return; 1627 } 1628 } 1629 1630 /** 1631 * Handles carousel mouseenter events 1632 * 1633 * @private 1634 * @param {Object} event The mouseenter event 1635 */ 1636 function onMouseEnter(event) { 1637 clearAutoplayInterval(); 1638 } 1639 1640 /** 1641 * Handles carousel mouseleave events 1642 * 1643 * @private 1644 * @param {Object} event The mouseleave event 1645 */ 1646 function onMouseLeave(event) { 1647 resetAutoplayInterval(); 1648 } 1649 1650 /** 1651 * Handles pause element click events 1652 * 1653 * @private 1654 * @param {Object} event The click event 1655 */ 1656 function onPauseClick(event) { 1657 pause(); 1658 that._elements["play"].focus(); 1659 } 1660 1661 /** 1662 * Handles play element click events 1663 * 1664 * @private 1665 * @param {Object} event The click event 1666 */ 1667 function onPlayClick() { 1668 play(); 1669 that._elements["pause"].focus(); 1670 } 1671 1672 /** 1673 * Pauses the playing of the Carousel. Sets {@code Carousel#_paused} marker. 1674 * Only relevant when autoplay is enabled 1675 * 1676 * @private 1677 */ 1678 function pause() { 1679 that._paused = true; 1680 clearAutoplayInterval(); 1681 refreshPlayPauseActions(); 1682 } 1683 1684 /** 1685 * Enables the playing of the Carousel. Sets {@code Carousel#_paused} marker. 1686 * Only relevant when autoplay is enabled 1687 * 1688 * @private 1689 */ 1690 function play() { 1691 that._paused = false; 1692 1693 // If the Carousel is hovered, don't begin auto transitioning until the next mouse leave event 1694 var hovered = false; 1695 if (that._elements.self.parentElement) { 1696 hovered = that._elements.self.parentElement.querySelector(":hover") === that._elements.self; 1697 } 1698 if (that._properties.autopauseDisabled || !hovered) { 1699 resetAutoplayInterval(); 1700 } 1701 1702 refreshPlayPauseActions(); 1703 } 1704 1705 /** 1706 * Refreshes the play/pause action markup based on the {@code Carousel#_paused} state 1707 * 1708 * @private 1709 */ 1710 function refreshPlayPauseActions() {
1711 setActionDisabled(that._elements["pause"], that._paused); 1712 setActionDisabled(that._elements["play"], !that._paused); 1713 } 1714 1715 /** 1716 * Initialize {@code Carousel#_active} based on the active item of the carousel. 1717 */ 1718 function initializeActive() { 1719 var items = that._elements["item"]; 1720 if (items && Array.isArray(items)) { 1721 for (var i = 0; i < items.length; i++) { 1722 if (items[i].classList.contains("cmp-carousel__item--active")) { 1723 that._active = i; 1724 break; 1725 } 1726 } 1727 } 1728 } 1729 1730 /** 1731 * Refreshes the item markup based on the current {@code Carousel#_active} index 1732 * 1733 * @private 1734 */ 1735 function refreshActive() { 1736 var items = that._elements["item"]; 1737 var indicators = that._elements["indicator"]; 1738 1739 if (items) { 1740 if (Array.isArray(items)) { 1741 for (var i = 0; i < items.length; i++) { 1742 if (i === parseInt(that._active)) { 1743 items[i].classList.add("cmp-carousel__item--active"); 1744 items[i].removeAttribute("aria-hidden"); 1745 indicators[i].classList.add("cmp-carousel__indicator--active"); 1746 indicators[i].setAttribute("aria-selected", true); 1747 indicators[i].setAttribute("tabindex", "0"); 1748 } else { 1749 items[i].classList.remove("cmp-carousel__item--active"); 1750 items[i].setAttribute("aria-hidden", true); 1751 indicators[i].classList.remove("cmp-carousel__indicator--active"); 1752 indicators[i].setAttribute("aria-selected", false); 1753 indicators[i].setAttribute("tabindex", "-1"); 1754 } 1755 } 1756 } else { 1757 // only one item 1758 items.classList.add("cmp-carousel__item--active"); 1759 indicators.classList.add("cmp-carousel__indicator--active"); 1760 } 1761 } 1762 } 1763 1764 /** 1765 * Focuses the element and prevents scrolling the element into view 1766 * 1767 * @param {HTMLElement} element Element to focus 1768 */ 1769 function focusWithoutScroll(element) { 1770 var x = window.scrollX || window.pageXOffset; 1771 var y = window.scrollY || window.pageYOffset; 1772 element.focus(); 1773 window.scrollTo(x, y); 1774 } 1775 1776 /** 1777 * Retrieves the next active index, with looping 1778 * 1779 * @private 1780 * @returns {Number} Index of the next carousel item 1781 */ 1782 function getNextIndex() { 1783 return that._active === (that._elements["item"].length - 1) ? 0 : that._active + 1; 1784 } 1785 1786 /** 1787 * Retrieves the previous active index, with looping 1788 * 1789 * @private 1790 * @returns {Number} Index of the previous carousel item 1791 */ 1792 function getPreviousIndex() { 1793 return that._active === 0 ? (that._elements["item"].length - 1) : that._active - 1; 1794 } 1795 1796 /** 1797 * Navigates to the item at the provided index 1798 * 1799 * @private 1800 * @param {Number} index The index of the item to navigate to 1801 * @param {Boolean} keepHash true to keep the hash in the URL, false to update it 1802 */ 1803 function navigate(index, keepHash) { 1804 if (index < 0 || index > (that._elements["item"].length - 1)) { 1805 return; 1806 } 1807 1808 that._active = index; 1809 refreshActive(); 1810 1811 if (!keepHash && containerUtils) { 1812 containerUtils.updateUrlHash(that, "item", index); 1813 } 1814 1815 if (dataLayerEnabled) { 1816 var carouselId = that._elements.self.id; 1817 var activeItem = getDataLayerId(that._elements.item[index]); 1818 var updatePayload = { component: {} }; 1819 updatePayload.component[carouselId] = { shownItems: [activeItem] }; 1820 1821 var removePayload = { component: {} }; 1822 removePayload.component[carouselId] = { shownItems: undefined }; 1823 1824 dataLayer.push(removePayload); 1825 dataLayer.push(updatePayload); 1826 } 1827 1828 // reset the autoplay transition interval following navigation, if not already hovering the carousel
1829 if (that._elements.self.parentElement) { 1830 if (that._elements.self.parentElement.querySelector(":hover") !== that._elements.self) { 1831 resetAutoplayInterval(); 1832 } 1833 } 1834 } 1835 1836 /** 1837 * Navigates to the item at the provided index and ensures the active indicator gains focus 1838 * 1839 * @private 1840 * @param {Number} index The index of the item to navigate to 1841 * @param {Boolean} keepHash true to keep the hash in the URL, false to update it 1842 */ 1843 function navigateAndFocusIndicator(index, keepHash) { 1844 navigate(index, keepHash); 1845 focusWithoutScroll(that._elements["indicator"][index]); 1846 1847 if (dataLayerEnabled) { 1848 dataLayer.push({ 1849 event: "cmp:show", 1850 eventInfo: { 1851 path: "component." + getDataLayerId(that._elements.item[index]) 1852 } 1853 }); 1854 } 1855 } 1856 1857 /** 1858 * Starts/resets automatic slide transition interval 1859 * 1860 * @private 1861 */ 1862 function resetAutoplayInterval() { 1863 if (that._paused || !that._properties.autoplay) { 1864 return; 1865 } 1866 clearAutoplayInterval(); 1867 that._autoplayIntervalId = window.setInterval(function() { 1868 if (document.visibilityState && document.hidden) { 1869 return; 1870 } 1871 var indicators = that._elements["indicators"]; 1872 if (indicators !== document.activeElement && indicators.contains(document.activeElement)) { 1873 // if an indicator has focus, ensure we switch focus following navigation 1874 navigateAndFocusIndicator(getNextIndex(), true); 1875 } else { 1876 navigate(getNextIndex(), true); 1877 } 1878 }, that._properties.delay); 1879 } 1880 1881 /** 1882 * Clears/pauses automatic slide transition interval 1883 * 1884 * @private 1885 */ 1886 function clearAutoplayInterval() { 1887 window.clearInterval(that._autoplayIntervalId); 1888 that._autoplayIntervalId = null; 1889 } 1890 1891 /** 1892 * Sets the disabled state for an action and toggles the appropriate CSS classes 1893 * 1894 * @private 1895 * @param {HTMLElement} action Action to disable 1896 * @param {Boolean} [disable] {@code true} to disable, {@code false} to enable 1897 */ 1898 function setActionDisabled(action, disable) { 1899 if (!action) { 1900 return; 1901 } 1902 if (disable !== false) { 1903 action.disabled = true; 1904 action.classList.add("cmp-carousel__action--disabled"); 1905 } else { 1906 action.disabled = false; 1907 action.classList.remove("cmp-carousel__action--disabled"); 1908 } 1909 } 1910 } 1911 1912 /** 1913 * Parses the dataLayer string and returns the ID 1914 * 1915 * @private 1916 * @param {HTMLElement} item the accordion item 1917 * @returns {String} dataLayerId or undefined 1918 */ 1919 function getDataLayerId(item) { 1920 if (item) { 1921 if (item.dataset.cmpDataLayer) { 1922 return Object.keys(JSON.parse(item.dataset.cmpDataLayer))[0]; 1923 } else { 1924 return item.id; 1925 } 1926 } 1927 return null; 1928 } 1929 1930 /** 1931 * Document ready handler and DOM mutation observers. Initializes Carousel components as necessary. 1932 * 1933 * @private 1934 */ 1935 function onDocumentReady() { 1936 dataLayerEnabled = document.body.hasAttribute("data-cmp-data-layer-enabled"); 1937 if (dataLayerEnabled) { 1938 dataLayerName = document.body.getAttribute("data-cmp-data-layer-name") || "adobeDataLayer"; 1939 dataLayer = window[dataLayerName] = window[dataLayerName] || []; 1940 } 1941 1942 var elements = document.querySelectorAll(selectors.self); 1943 for (var i = 0; i < elements.length; i++) { 1944 new Carousel({ element: elements[i], options: CMP.utils.readData(elements[i], IS) }); 1945 } 1946 1947 var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver; 1948 var body = document.querySelector("body"); 1949 var observer = new MutationObserver(function(mutations) { 1950 mutations.forEach(function(mutation) { 1951 // needed for IE 1952 var nodesArray = [].slice.call(mutation.addedNodes); 1953 if (nodesArray.length > 0) { 1954 nodesArray.forEach(function(addedNode) { 1955 if (addedNode.querySelectorAll) { 1956 var elementsArray = [].slice.call(addedNode.querySelectorAll(selectors.self)); 1957 elementsArray.forEach(function(element) { 1958 new Carousel({ element: element, options: CMP.utils.readData(element, IS) }); 1959 }); 1960 } 1961 }); 1962 } 1963 }); 1964 }); 1965 1966 observer.observe(body, { 1967 subtree: true, 1968 childList: true, 1969 characterData: true 1970 }); 1971 } 1972 1973 var documentReady = document.readyState !== "loading" ? Promise.resolve() : new Promise(function(resolve) { 1974 document.addEventListener("DOMContentLoaded", resolve); 1975 }); 1976 Promise.all([documentReady]).then(onDocumentReady); 1977 1978 if (containerUtils) { 1979 window.addEventListener("load", containerUtils.scrollToAnchor, false); 1980 } 1981 1982}()); 1983 1984/******************************************************************************* 1985 * Copyright 2017 Adobe 1986 * 1987 * Licensed under the Apache License, Version 2.0 (the "License");
1988 * you may not use this file except in compliance with the License. 1989 * You may obtain a copy of the License at 1990 * 1991 * http://www.apache.org/licenses/LICENSE-2.0 1992 * 1993 * Unless required by applicable law or agreed to in writing, software 1994 * distributed under the License is distributed on an "AS IS" BASIS, 1995 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1996 * See the License for the specific language governing permissions and 1997 * limitations under the License. 1998 ******************************************************************************/ 1999if (window.Element && !Element.prototype.closest) { 2000 // eslint valid-jsdoc: "off" 2001 Element.prototype.closest = 2002 function(s) { 2003 "use strict"; 2004 var matches = (this.document || this.ownerDocument).querySelectorAll(s); 2005 var el = this; 2006 var i; 2007 do { 2008 i = matches.length; 2009 while (--i >= 0 && matches.item(i) !== el) { 2010 // continue 2011 } 2012 } while ((i < 0) && (el = el.parentElement)); 2013 return el; 2014 }; 2015} 2016 2017if (window.Element && !Element.prototype.matches) { 2018 Element.prototype.matches = 2019 Element.prototype.matchesSelector || 2020 Element.prototype.mozMatchesSelector || 2021 Element.prototype.msMatchesSelector || 2022 Element.prototype.oMatchesSelector || 2023 Element.prototype.webkitMatchesSelector || 2024 function(s) { 2025 "use strict"; 2026 var matches = (this.document || this.ownerDocument).querySelectorAll(s); 2027 var i = matches.length; 2028 while (--i >= 0 && matches.item(i) !== this) { 2029 // continue 2030 } 2031 return i > -1; 2032 }; 2033} 2034 2035if (!Object.assign) { 2036 Object.assign = function(target, varArgs) { // .length of function is 2 2037 "use strict"; 2038 if (target === null) { 2039 throw new TypeError("Cannot convert undefined or null to object"); 2040 } 2041 2042 var to = Object(target); 2043 2044 for (var index = 1; index < arguments.length; index++) { 2045 var nextSource = arguments[index]; 2046 2047 if (nextSource !== null) { 2048 for (var nextKey in nextSource) { 2049 if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) { 2050 to[nextKey] = nextSource[nextKey]; 2051 } 2052 } 2053 } 2054 } 2055 return to; 2056 }; 2057} 2058 2059(function(arr) { 2060 "use strict"; 2061 arr.forEach(function(item) { 2062 if (Object.prototype.hasOwnProperty.call(item, "remove")) { 2063 return; 2064 } 2065 Object.defineProperty(item, "remove", { 2066 configurable: true, 2067 enumerable: true, 2068 writable: true, 2069 value: function remove() { 2070 this.parentNode.removeChild(this); 2071 } 2072 }); 2073 }); 2074})([Element.prototype, CharacterData.prototype, DocumentType.prototype]); 2075 2076/******************************************************************************* 2077 * Copyright 2022 Adobe 2078 * 2079 * Licensed under the Apache License, Version 2.0 (the "License"); 2080 * you may not use this file except in compliance with the License. 2081 * You may obtain a copy of the License at 2082 * 2083 * http://www.apache.org/licenses/LICENSE-2.0 2084 * 2085 * Unless required by applicable law or agreed to in writing, software 2086 * distributed under the License is distributed on an "AS IS" BASIS, 2087 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 2088 * See the License for the specific language governing permissions and 2089 * limitations under the License. 2090 ******************************************************************************/ 2091(function(document) { 2092 "use strict"; 2093 2094 window.CMP = window.CMP || {}; 2095 window.CMP.utils = (function() { 2096 var NS = "cmp"; 2097 2098 /** 2099 * Reads options data from the Component wrapper element, defined via {@code data-cmp-*} data attributes 2100 * 2101 * @param {HTMLElement} element The component element to read options data from 2102 * @param {String} is The component identifier 2103 * @returns {String[]} The options read from the component data attributes 2104 */ 2105 var readData = function(element, is) { 2106 var data = element.dataset; 2107 var options = []; 2108 var capitalized = is; 2109 capitalized = capitalized.charAt(0).toUpperCase() + capitalized.slice(1); 2110 var reserved = ["is", "hook" + capitalized]; 2111 2112 for (var key in data) { 2113 if (Object.prototype.hasOwnProperty.call(data, key)) { 2114 var value = data[key]; 2115 2116 if (key.indexOf(NS) === 0) { 2117 key = key.slice(NS.length); 2118 key = key.charAt(0).toLowerCase() + key.substring(1); 2119 2120 if (reserved.indexOf(key) === -1) { 2121 options[key] = value; 2122 } 2123 } 2124 } 2125 } 2126 return options; 2127 }; 2128 2129 /** 2130 * Set up the final properties of a component by evaluating the transform function or fall back to the default value on demand 2131 * @param {String[]} options the options to transform 2132 * @param {Object} properties object of properties of property functions 2133 * @returns {Object} transformed properties 2134 */ 2135 var setupProperties = function(options, properties) { 2136 var transformedProperties = {}; 2137 2138 for (var key in properties) { 2139 if (Object.prototype.hasOwnProperty.call(properties, key)) { 2140 var property = properties[key]; 2141 if (options && options[key] != null) { 2142 if (property && typeof property.transform === "function") { 2143 transformedProperties[key] = property.transform(options[key]); 2144 } else { 2145 transformedProperties[key] = options[key]; 2146 } 2147 } else { 2148 transformedProperties[key] = properties[key]["default"]; 2149 } 2150 } 2151 } 2152 return transformedProperties; 2153 }; 2154 2155 2156 return { 2157 readData: readData, 2158 setupProperties: setupProperties 2159 }; 2160 }()); 2161}(window.document)); 2162 2163/******************************************************************************* 2164 * Copyright 2022 Adobe 2165 * 2166 * Licensed under the Apache License, Version 2.0 (the "License");
2167 * you may not use this file except in compliance with the License. 2168 * You may obtain a copy of the License at 2169 * 2170 * http://www.apache.org/licenses/LICENSE-2.0 2171 * 2172 * Unless required by applicable law or agreed to in writing, software 2173 * distributed under the License is distributed on an "AS IS" BASIS, 2174 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 2175 * See the License for the specific language governing permissions and 2176 * limitations under the License. 2177 ******************************************************************************/ 2178(function(document) { 2179 "use strict"; 2180 2181 window.CMP = window.CMP || {}; 2182 window.CMP.image = window.CMP.image || {}; 2183 window.CMP.image.dynamicMedia = (function() { 2184 var autoSmartCrops = {}; 2185 var SRC_URI_TEMPLATE_WIDTH_VAR = "{.width}"; 2186 var SRC_URI_TEMPLATE_DPR_VAR = "{dpr}"; 2187 var SRC_URI_DPR_OFF = "dpr=off"; 2188 var SRC_URI_DPR_ON = "dpr=on,{dpr}"; 2189 var dpr = window.devicePixelRatio || 1; 2190 var config = { 2191 minWidth: 20 2192 }; 2193 2194 /** 2195 * get auto smart crops from dm 2196 * @param {String} src the src uri 2197 * @returns {{}} the smart crop json object 2198 */ 2199 var getAutoSmartCrops = function(src) { 2200 var request = new XMLHttpRequest(); 2201 var url = src.split(SRC_URI_TEMPLATE_WIDTH_VAR)[0] + "?req=set,json"; 2202 request.open("GET", url, false); 2203 request.onload = function() { 2204 if (request.status >= 200 && request.status < 400) { 2205 // success status 2206 var responseText = request.responseText; 2207 var rePayload = new RegExp(/^(?:\/\*jsonp\*\/)?\s*([^()]+)\(([\s\S]+),\s*"[0-9]*"\);?$/gmi); 2208 var rePayloadJSON = new RegExp(/^{[\s\S]*}$/gmi); 2209 var resPayload = rePayload.exec(responseText); 2210 var payload; 2211 if (resPayload) { 2212 var payloadStr = resPayload[2]; 2213 if (rePayloadJSON.test(payloadStr)) { 2214 payload = JSON.parse(payloadStr); 2215 } 2216 2217 } 2218 // check "relation" - only in case of smartcrop preset 2219 if (payload && payload.set.relation && payload.set.relation.length > 0) { 2220 for (var i = 0; i < payload.set.relation.length; i++) { 2221 autoSmartCrops[parseInt(payload.set.relation[i].userdata.SmartCropWidth)] = 2222 ":" + payload.set.relation[i].userdata.SmartCropDef; 2223 } 2224 } 2225 } else { 2226 // error status 2227 } 2228 }; 2229 request.send(); 2230 return autoSmartCrops; 2231 }; 2232 2233 /** 2234 * Build and return the srcset value based on the available auto smart crops 2235 * @param {String} src the src uri 2236 * @param {Object} smartCrops the smart crops object 2237 * @returns {String} the srcset 2238 */ 2239 var getSrcSet = function(src, smartCrops) { 2240 var srcset; 2241 var keys = Object.keys(smartCrops); 2242 if (keys.length > 0) { 2243 srcset = []; 2244 for (var key in autoSmartCrops) { 2245 srcset.push(src.replace(SRC_URI_TEMPLATE_WIDTH_VAR, smartCrops[key]) + " " + key + "w"); 2246 } 2247 } 2248 return srcset.join(","); 2249 }; 2250 2251 /** 2252 * Get the optimal width based on the available sizes 2253 * @param {[Number]} sizes the available sizes 2254 * @param {Number} width the element width 2255 * @returns {String} the optimal width 2256 */ 2257 function getOptimalWidth(sizes, width) { 2258 var len = sizes.length; 2259 var key = 0; 2260 2261 while ((key < len - 1) && (sizes[key] < width)) { 2262 key++; 2263 } 2264 2265 return sizes[key] !== undefined ? sizes[key].toString() : width; 2266 } 2267 2268 /** 2269 * Get the width of an element or parent element if the width is smaller than the minimum width 2270 * @param {HTMLElement} component the image component 2271 * @param {HTMLElement | Node} parent the parent element 2272 * @returns {Number} the width of the element 2273 */ 2274 var getWidth = function(component, parent) { 2275 var width = component.offsetWidth; 2276 while (width < config.minWidth && parent && !component._autoWidth) { 2277 width = parent.offsetWidth; 2278 parent = parent.parentNode; 2279 } 2280 return width; 2281 }; 2282 2283 /** 2284 * Set the src and srcset attribute for a Dynamic Media Image which auto smart crops enabled. 2285 * @param {HTMLElement} component the image component 2286 * @param {{}} properties the component properties 2287 */ 2288 var setDMAttributes = function(component, properties) { 2289 // for v3 we first have to turn the dpr on
2290 var src = properties.src.replace(SRC_URI_DPR_OFF, SRC_URI_DPR_ON); 2291 src = src.replace(SRC_URI_TEMPLATE_DPR_VAR, dpr); 2292 var smartCrops = {}; 2293 var width; 2294 if (properties["smartcroprendition"] === "SmartCrop:Auto") { 2295 smartCrops = getAutoSmartCrops(src); 2296 } 2297 var hasWidths = (properties.widths && properties.widths.length > 0) || Object.keys(smartCrops).length > 0; 2298 if (hasWidths) { 2299 var image = component.querySelector("img"); 2300 var elemWidth = getWidth(component, component.parentNode); 2301 if (properties["smartcroprendition"] === "SmartCrop:Auto") { 2302 image.setAttribute("srcset", CMP.image.dynamicMedia.getSrcSet(src, smartCrops)); 2303 width = getOptimalWidth(Object.keys(smartCrops, elemWidth)); 2304 image.setAttribute("src", CMP.image.dynamicMedia.getSrc(src, smartCrops[width])); 2305 } else { 2306 width = getOptimalWidth(properties.widths, elemWidth); 2307 image.setAttribute("src", CMP.image.dynamicMedia.getSrc(src, width)); 2308 } 2309 } 2310 }; 2311 2312 /** 2313 * Get the src attribute based on the optimal width 2314 * @param {String} src the src uri 2315 * @param {String} width the element width 2316 * @returns {String} the final src attribute 2317 */ 2318 var getSrc = function(src, width) { 2319 if (src.indexOf(SRC_URI_TEMPLATE_WIDTH_VAR) > -1) { 2320 src = src.replace(SRC_URI_TEMPLATE_WIDTH_VAR, width); 2321 } 2322 return src; 2323 }; 2324 2325 2326 return { 2327 getAutoSmartCrops: getAutoSmartCrops, 2328 getSrcSet: getSrcSet, 2329 getSrc: getSrc, 2330 setDMAttributes: setDMAttributes, 2331 getWidth: getWidth 2332 }; 2333 }()); 2334 document.dispatchEvent(new CustomEvent("core.wcm.components.commons.site.image.dynamic-media.loaded")); 2335}(window.document)); 2336 2337/******************************************************************************* 2338 * Copyright 2016 Adobe 2339 * 2340 * Licensed under the Apache License, Version 2.0 (the "License"); 2341 * you may not use this file except in compliance with the License. 2342 * You may obtain a copy of the License at 2343 * 2344 * http://www.apache.org/licenses/LICENSE-2.0 2345 * 2346 * Unless required by applicable law or agreed to in writing, software 2347 * distributed under the License is distributed on an "AS IS" BASIS, 2348 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 2349 * See the License for the specific language governing permissions and 2350 * limitations under the License. 2351 ******************************************************************************/ 2352(function() { 2353 "use strict"; 2354 2355 var NS = "cmp"; 2356 var IS = "image"; 2357 2358 var EMPTY_PIXEL = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"; 2359 var LAZY_THRESHOLD_DEFAULT = 0; 2360 var SRC_URI_TEMPLATE_WIDTH_VAR = "{.width}"; 2361 var SRC_URI_TEMPLATE_WIDTH_VAR_ASSET_DELIVERY = "width={width}"; 2362 var SRC_URI_TEMPLATE_DPR_VAR = "{dpr}"; 2363 2364 var selectors = { 2365 self: "[data-" + NS + '-is="' + IS + '"]', 2366 image: '[data-cmp-hook-image="image"]', 2367 map: '[data-cmp-hook-image="map"]', 2368 area: '[data-cmp-hook-image="area"]' 2369 }; 2370 2371 var lazyLoader = { 2372 "cssClass": "cmp-image__image--is-loading", 2373 "style": { 2374 "height": 0, 2375 "padding-bottom": "" // will be replaced with % ratio 2376 } 2377 }; 2378 2379 var properties = { 2380 /** 2381 * An array of alternative image widths (in pixels). 2382 * Used to replace a {.width} variable in the src property with an optimal width if a URI template is provided. 2383 * 2384 * @memberof Image 2385 * @type {Number[]} 2386 * @default [] 2387 */ 2388 "widths": { 2389 "default": [], 2390 "transform": function(value) { 2391 var widths = []; 2392 value.split(",").forEach(function(item) { 2393 item = parseFloat(item); 2394 if (!isNaN(item)) { 2395 widths.push(item); 2396 } 2397 }); 2398 return widths; 2399 } 2400 }, 2401 /** 2402 * Indicates whether the image should be rendered lazily. 2403 * 2404 * @memberof Image 2405 * @type {Boolean} 2406 * @default false 2407 */ 2408 "lazy": { 2409 "default": false, 2410 "transform": function(value) { 2411 return !(value === null || typeof value === "undefined"); 2412 } 2413 }, 2414 /** 2415 * Indicates image is DynamicMedia image. 2416 * 2417 * @memberof Image 2418 * @type {Boolean} 2419 * @default false 2420 */ 2421 "dmimage": { 2422 "default": false, 2423 "transform": function(value) { 2424 return !(value === null || typeof value === "undefined"); 2425 } 2426 }, 2427 /** 2428 * The lazy threshold. 2429 * This is the number of pixels, in advance of becoming visible, when an lazy-loading image should begin 2430 * to load. 2431 * 2432 * @memberof Image 2433 * @type {Number} 2434 * @default 0 2435 */ 2436 "lazythreshold": { 2437 "default": 0, 2438 "transform": function(value) { 2439 var val = parseInt(value); 2440 if (isNaN(val)) { 2441 return LAZY_THRESHOLD_DEFAULT; 2442 } 2443 return val; 2444 } 2445 }, 2446 /** 2447 * The image source. 2448 * 2449 * Can be a simple image source, or a URI template representation that 2450 * can be variable expanded - useful for building an image configuration with an alternative width. 2451 * e.g. '/path/image.coreimg{.width}.jpeg/1506620954214.jpeg' 2452 * 2453 * @memberof Image 2454 * @type {String} 2455 */ 2456 "src": { 2457 "transform": function(value) { 2458 return decodeURIComponent(value); 2459 } 2460 } 2461 }; 2462 2463 var devicePixelRatio = window.devicePixelRatio || 1; 2464 2465 function Image(config) { 2466 var that = this; 2467 2468 var smartCrops = {}; 2469 2470 var useAssetDelivery = false;
2471 var srcUriTemplateWidthVar = SRC_URI_TEMPLATE_WIDTH_VAR; 2472 2473 function init(config) { 2474 // prevents multiple initialization 2475 config.element.removeAttribute("data-" + NS + "-is"); 2476 2477 // check if asset delivery is used 2478 if (config.options.src && config.options.src.indexOf(SRC_URI_TEMPLATE_WIDTH_VAR_ASSET_DELIVERY) >= 0) { 2479 useAssetDelivery = true; 2480 srcUriTemplateWidthVar = SRC_URI_TEMPLATE_WIDTH_VAR_ASSET_DELIVERY; 2481 } 2482 2483 that._properties = CMP.utils.setupProperties(config.options, properties); 2484 cacheElements(config.element); 2485 // check image is DM asset; if true try to make req=set 2486 if (config.options.src && Object.prototype.hasOwnProperty.call(config.options, "dmimage") && (config.options["smartcroprendition"] === "SmartCrop:Auto")) { 2487 smartCrops = CMP.image.dynamicMedia.getAutoSmartCrops(config.options.src); 2488 } 2489 2490 if (!that._elements.noscript) { 2491 return; 2492 } 2493 2494 that._elements.container = that._elements.link ? that._elements.link : that._elements.self; 2495 2496 unwrapNoScript(); 2497 2498 if (that._properties.lazy) { 2499 addLazyLoader(); 2500 } 2501 2502 if (that._elements.map) { 2503 that._elements.image.addEventListener("load", onLoad); 2504 } 2505 2506 window.addEventListener("resize", onWindowResize); 2507 ["focus", "click", "load", "transitionend", "animationend", "scroll"].forEach(function(name) { 2508 document.addEventListener(name, that.update); 2509 }); 2510 2511 that._elements.image.addEventListener("cmp-image-redraw", that.update); 2512 2513 that._interSectionObserver = new IntersectionObserver(function(entries, interSectionObserver) { 2514 entries.forEach(function(entry) { 2515 if (entry.intersectionRatio > 0) { 2516 that.update(); 2517 } 2518 }); 2519 }); 2520 that._interSectionObserver.observe(that._elements.self); 2521 2522 that.update(); 2523 } 2524 2525 function loadImage() { 2526 var hasWidths = (that._properties.widths && that._properties.widths.length > 0) || Object.keys(smartCrops).length > 0; 2527 var replacement; 2528 if (Object.keys(smartCrops).length > 0) { 2529 var optimalWidth = getOptimalWidth(Object.keys(smartCrops), false); 2530 replacement = smartCrops[optimalWidth]; 2531 } else { 2532 replacement = hasWidths ? (that._properties.dmimage ? "" : ".") + getOptimalWidth(that._properties.widths, true) : ""; 2533 } 2534 if (useAssetDelivery) { 2535 replacement = replacement !== "" ? ("width=" + replacement.substring(1)) : ""; 2536 } 2537 var url = that._properties.src.replace(srcUriTemplateWidthVar, replacement); 2538 url = url.replace(SRC_URI_TEMPLATE_DPR_VAR, devicePixelRatio); 2539 2540 var imgSrcAttribute = that._elements.image.getAttribute("src"); 2541 2542 if (url !== imgSrcAttribute) { 2543 if (imgSrcAttribute === null || imgSrcAttribute === EMPTY_PIXEL) { 2544 that._elements.image.setAttribute("src", url); 2545 } else { 2546 var urlTemplateParts = that._properties.src.split(srcUriTemplateWidthVar); 2547 // check if image src was dynamically swapped meanwhile (e.g. by Target) 2548 var isImageRefSame = imgSrcAttribute.startsWith(urlTemplateParts[0]); 2549 if (isImageRefSame && urlTemplateParts.length > 1) { 2550 isImageRefSame = imgSrcAttribute.endsWith(urlTemplateParts[urlTemplateParts.length - 1]); 2551 } 2552 if (isImageRefSame) { 2553 that._elements.image.setAttribute("src", url); 2554 if (!hasWidths) { 2555 window.removeEventListener("scroll", that.update); 2556 } 2557 } 2558 } 2559 } 2560 if (that._lazyLoaderShowing) { 2561 that._elements.image.addEventListener("load", removeLazyLoader); 2562 } 2563 that._interSectionObserver.unobserve(that._elements.self); 2564 } 2565 2566 function getOptimalWidth(widths, useDevicePixelRatio) { 2567 var container = that._elements.self; 2568 var containerWidth = container.clientWidth; 2569 while (containerWidth === 0 && container.parentNode) { 2570 container = container.parentNode; 2571 containerWidth = container.clientWidth; 2572 } 2573 2574 var dpr = useDevicePixelRatio ? devicePixelRatio : 1; 2575 var optimalWidth = containerWidth * dpr; 2576 var len = widths.length; 2577 var key = 0; 2578 2579 while ((key < len - 1) && (widths[key] < optimalWidth)) { 2580 key++; 2581 } 2582 2583 return widths[key].toString(); 2584 } 2585 2586 function addLazyLoader() { 2587 var width = that._elements.image.getAttribute("width"); 2588 var height = that._elements.image.getAttribute("height"); 2589 2590 if (width && height) { 2591 var ratio = (height / width) * 100; 2592 var styles = lazyLoader.style; 2593 2594 styles["padding-bottom"] = ratio + "%"; 2595 2596 for (var s in styles) { 2597 if (Object.prototype.hasOwnProperty.call(styles, s)) { 2598 that._elements.image.style[s] = styles[s]; 2599 } 2600 } 2601 } 2602 that._elements.image.setAttribute("src", EMPTY_PIXEL); 2603 that._elements.image.classList.add(lazyLoader.cssClass); 2604 that._lazyLoaderShowing = true; 2605 } 2606 2607 function unwrapNoScript() { 2608 var markup = decodeNoscript(that._elements.noscript.textContent.trim()); 2609 var parser = new DOMParser(); 2610 2611 // temporary document avoids requesting the image before removing its src 2612 var temporaryDocument = parser.parseFromString(markup, "text/html"); 2613 var imageElement = temporaryDocument.querySelector(selectors.image); 2614 imageElement.removeAttribute("src"); 2615 that._elements.container.insertBefore(imageElement, that._elements.noscript); 2616 2617 var mapElement = temporaryDocument.querySelector(selectors.map); 2618 if (mapElement) { 2619 that._elements.container.insertBefore(mapElement, that._elements.noscript); 2620 } 2621 2622 that._elements.noscript.parentNode.removeChild(that._elements.noscript); 2623 if (that._elements.container.matches(selectors.image)) { 2624 that._elements.image = that._elements.container; 2625 } else { 2626 that._elements.image = that._elements.container.querySelector(selectors.image); 2627 } 2628 2629 that._elements.map = that._elements.container.querySelector(selectors.map); 2630 that._elements.areas = that._elements.container.querySelectorAll(selectors.area); 2631 } 2632 2633 function removeLazyLoader() { 2634 that._elements.image.classList.remove(lazyLoader.cssClass); 2635 for (var property in lazyLoader.style) { 2636 if (Object.prototype.hasOwnProperty.call(lazyLoader.style, property)) { 2637 that._elements.image.style[property] = ""; 2638 } 2639 } 2640 that._elements.image.removeEventListener("load", removeLazyLoader); 2641 that._lazyLoaderShowing = false;
2642 } 2643 2644 function isLazyVisible() { 2645 if (that._elements.container.offsetParent === null) { 2646 return false; 2647 } 2648 2649 var wt = window.pageYOffset; 2650 var wb = wt + document.documentElement.clientHeight; 2651 var et = that._elements.container.getBoundingClientRect().top + wt; 2652 var eb = et + that._elements.container.clientHeight; 2653 2654 return eb >= wt - that._properties.lazythreshold && et <= wb + that._properties.lazythreshold; 2655 } 2656 2657 function resizeAreas() { 2658 if (that._elements.areas && that._elements.areas.length > 0) { 2659 for (var i = 0; i < that._elements.areas.length; i++) { 2660 var width = that._elements.image.width; 2661 var height = that._elements.image.height; 2662 2663 if (width && height) { 2664 var relcoords = that._elements.areas[i].dataset.cmpRelcoords; 2665 if (relcoords) { 2666 var relativeCoordinates = relcoords.split(","); 2667 var coordinates = new Array(relativeCoordinates.length); 2668 2669 for (var j = 0; j < coordinates.length; j++) { 2670 if (j % 2 === 0) { 2671 coordinates[j] = parseInt(relativeCoordinates[j] * width); 2672 } else { 2673 coordinates[j] = parseInt(relativeCoordinates[j] * height); 2674 } 2675 } 2676 2677 that._elements.areas[i].coords = coordinates; 2678 } 2679 } 2680 } 2681 } 2682 } 2683 2684 function cacheElements(wrapper) { 2685 that._elements = {}; 2686 that._elements.self = wrapper; 2687 var hooks = that._elements.self.querySelectorAll("[data-" + NS + "-hook-" + IS + "]"); 2688 2689 for (var i = 0; i < hooks.length; i++) { 2690 var hook = hooks[i]; 2691 var capitalized = IS; 2692 capitalized = capitalized.charAt(0).toUpperCase() + capitalized.slice(1); 2693 var key = hook.dataset[NS + "Hook" + capitalized]; 2694 that._elements[key] = hook; 2695 } 2696 } 2697 2698 function onWindowResize() { 2699 that.update(); 2700 resizeAreas(); 2701 } 2702 2703 function onLoad() { 2704 resizeAreas(); 2705 } 2706 2707 that.update = function() { 2708 if (that._properties.lazy) { 2709 if (isLazyVisible()) { 2710 loadImage(); 2711 } 2712 } else { 2713 loadImage(); 2714 } 2715 }; 2716 2717 if (config && config.element) { 2718 init(config); 2719 } 2720 } 2721 2722 function onDocumentReady() { 2723 var elements = document.querySelectorAll(selectors.self); 2724 for (var i = 0; i < elements.length; i++) { 2725 new Image({ element: elements[i], options: CMP.utils.readData(elements[i], IS) }); 2726 } 2727 2728 var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver; 2729 var body = document.querySelector("body"); 2730 var observer = new MutationObserver(function(mutations) { 2731 mutations.forEach(function(mutation) { 2732 // needed for IE 2733 var nodesArray = [].slice.call(mutation.addedNodes); 2734 if (nodesArray.length > 0) { 2735 nodesArray.forEach(function(addedNode) { 2736 if (addedNode.querySelectorAll) { 2737 var elementsArray = [].slice.call(addedNode.querySelectorAll(selectors.self)); 2738 elementsArray.forEach(function(element) { 2739 new Image({ element: element, options: CMP.utils.readData(element, IS) }); 2740 }); 2741 } 2742 }); 2743 } 2744 }); 2745 }); 2746 2747 observer.observe(body, { 2748 subtree: true, 2749 childList: true, 2750 characterData: true 2751 }); 2752 } 2753 2754 var documentReady = document.readyState !== "loading" ? Promise.resolve() : new Promise(function(resolve) { 2755 document.addEventListener("DOMContentLoaded", resolve); 2756 }); 2757 2758 Promise.all([documentReady]).then(onDocumentReady); 2759 /* 2760 on drag & drop of the component into a parsys, noscript's content will be escaped multiple times by the editor which creates 2761 the DOM for editing; the HTML parser cannot be used here due to the multiple escaping 2762 */ 2763 function decodeNoscript(text) { 2764 text = text.replace(/&(amp;)*lt;/g, "<"); 2765 text = text.replace(/&(amp;)*gt;/g, ">"); 2766 return text; 2767 } 2768 2769})(); 2770 2771/******************************************************************************* 2772 * Copyright 2017 Adobe 2773 * 2774 * Licensed under the Apache License, Version 2.0 (the "License");
2775 * you may not use this file except in compliance with the License. 2776 * You may obtain a copy of the License at 2777 * 2778 * http://www.apache.org/licenses/LICENSE-2.0 2779 * 2780 * Unless required by applicable law or agreed to in writing, software 2781 * distributed under the License is distributed on an "AS IS" BASIS, 2782 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 2783 * See the License for the specific language governing permissions and 2784 * limitations under the License. 2785 ******************************************************************************/ 2786if (window.Element && !Element.prototype.closest) { 2787 // eslint valid-jsdoc: "off" 2788 Element.prototype.closest = 2789 function(s) { 2790 "use strict"; 2791 var matches = (this.document || this.ownerDocument).querySelectorAll(s); 2792 var el = this; 2793 var i; 2794 do { 2795 i = matches.length; 2796 while (--i >= 0 && matches.item(i) !== el) { 2797 // continue 2798 } 2799 } while ((i < 0) && (el = el.parentElement)); 2800 return el; 2801 }; 2802} 2803 2804if (window.Element && !Element.prototype.matches) { 2805 Element.prototype.matches = 2806 Element.prototype.matchesSelector || 2807 Element.prototype.mozMatchesSelector || 2808 Element.prototype.msMatchesSelector || 2809 Element.prototype.oMatchesSelector || 2810 Element.prototype.webkitMatchesSelector || 2811 function(s) { 2812 "use strict"; 2813 var matches = (this.document || this.ownerDocument).querySelectorAll(s); 2814 var i = matches.length; 2815 while (--i >= 0 && matches.item(i) !== this) { 2816 // continue 2817 } 2818 return i > -1; 2819 }; 2820} 2821 2822if (!Object.assign) { 2823 Object.assign = function(target, varArgs) { // .length of function is 2 2824 "use strict"; 2825 if (target === null) { 2826 throw new TypeError("Cannot convert undefined or null to object"); 2827 } 2828 2829 var to = Object(target); 2830 2831 for (var index = 1; index < arguments.length; index++) { 2832 var nextSource = arguments[index]; 2833 2834 if (nextSource !== null) { 2835 for (var nextKey in nextSource) { 2836 if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) { 2837 to[nextKey] = nextSource[nextKey]; 2838 } 2839 } 2840 } 2841 } 2842 return to; 2843 }; 2844} 2845 2846(function(arr) { 2847 "use strict"; 2848 arr.forEach(function(item) { 2849 if (Object.prototype.hasOwnProperty.call(item, "remove")) { 2850 return; 2851 } 2852 Object.defineProperty(item, "remove", { 2853 configurable: true, 2854 enumerable: true, 2855 writable: true, 2856 value: function remove() { 2857 this.parentNode.removeChild(this); 2858 } 2859 }); 2860 }); 2861})([Element.prototype, CharacterData.prototype, DocumentType.prototype]); 2862 2863/******************************************************************************* 2864 * Copyright 2016 Adobe 2865 * 2866 * Licensed under the Apache License, Version 2.0 (the "License"); 2867 * you may not use this file except in compliance with the License. 2868 * You may obtain a copy of the License at 2869 * 2870 * http://www.apache.org/licenses/LICENSE-2.0 2871 * 2872 * Unless required by applicable law or agreed to in writing, software 2873 * distributed under the License is distributed on an "AS IS" BASIS, 2874 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 2875 * See the License for the specific language governing permissions and 2876 * limitations under the License. 2877 ******************************************************************************/ 2878(function() { 2879 "use strict"; 2880 2881 var NS = "cmp"; 2882 var IS = "image"; 2883 2884 var EMPTY_PIXEL = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"; 2885 var LAZY_THRESHOLD_DEFAULT = 0; 2886 var SRC_URI_TEMPLATE_WIDTH_VAR = "{.width}"; 2887 var SRC_URI_TEMPLATE_WIDTH_VAR_ASSET_DELIVERY = "width={width}"; 2888 var SRC_URI_TEMPLATE_DPR_VAR = "{dpr}"; 2889 2890 var selectors = { 2891 self: "[data-" + NS + '-is="' + IS + '"]', 2892 image: '[data-cmp-hook-image="image"]', 2893 map: '[data-cmp-hook-image="map"]', 2894 area: '[data-cmp-hook-image="area"]' 2895 }; 2896 2897 var lazyLoader = { 2898 "cssClass": "cmp-image__image--is-loading", 2899 "style": { 2900 "height": 0, 2901 "padding-bottom": "" // will be replaced with % ratio 2902 } 2903 }; 2904 2905 var properties = { 2906 /** 2907 * An array of alternative image widths (in pixels). 2908 * Used to replace a {.width} variable in the src property with an optimal width if a URI template is provided. 2909 * 2910 * @memberof Image 2911 * @type {Number[]} 2912 * @default [] 2913 */ 2914 "widths": { 2915 "default": [], 2916 "transform": function(value) { 2917 var widths = []; 2918 value.split(",").forEach(function(item) { 2919 item = parseFloat(item); 2920 if (!isNaN(item)) { 2921 widths.push(item); 2922 } 2923 }); 2924 return widths; 2925 } 2926 }, 2927 /** 2928 * Indicates whether the image should be rendered lazily. 2929 * 2930 * @memberof Image 2931 * @type {Boolean} 2932 * @default false 2933 */ 2934 "lazy": { 2935 "default": false, 2936 "transform": function(value) { 2937 return !(value === null || typeof value === "undefined"); 2938 } 2939 }, 2940 /** 2941 * Indicates image is DynamicMedia image. 2942 * 2943 * @memberof Image 2944 * @type {Boolean} 2945 * @default false 2946 */ 2947 "dmimage": { 2948 "default": false, 2949 "transform": function(value) { 2950 return !(value === null || typeof value === "undefined"); 2951 } 2952 }, 2953 /** 2954 * The lazy threshold. 2955 * This is the number of pixels, in advance of becoming visible, when an lazy-loading image should begin 2956 * to load. 2957 * 2958 * @memberof Image 2959 * @type {Number} 2960 * @default 0 2961 */ 2962 "lazythreshold": { 2963 "default": 0, 2964 "transform": function(value) { 2965 var val = parseInt(value); 2966 if (isNaN(val)) { 2967 return LAZY_THRESHOLD_DEFAULT; 2968 } 2969 return val; 2970 } 2971 }, 2972 /** 2973 * The image source. 2974 * 2975 * Can be a simple image source, or a URI template representation that 2976 * can be variable expanded - useful for building an image configuration with an alternative width. 2977 * e.g. '/path/image.coreimg{.width}.jpeg/1506620954214.jpeg' 2978 * 2979 * @memberof Image 2980 * @type {String} 2981 */ 2982 "src": { 2983 "transform": function(value) { 2984 return decodeURIComponent(value); 2985 } 2986 } 2987 }; 2988 2989 var devicePixelRatio = window.devicePixelRatio || 1; 2990 2991 function readData(element) { 2992 var data = element.dataset; 2993 var options = []; 2994 var capitalized = IS; 2995 capitalized = capitalized.charAt(0).toUpperCase() + capitalized.slice(1); 2996 var reserved = ["is", "hook" + capitalized]; 2997 2998 for (var key in data) { 2999 if (Object.prototype.hasOwnProperty.call(data, key)) { 3000 var value = data[key]; 3001 3002 if (key.indexOf(NS) === 0) { 3003 key = key.slice(NS.length); 3004 key = key.charAt(0).toLowerCase() + key.substring(1); 3005 3006 if (reserved.indexOf(key) === -1) { 3007 options[key] = value; 3008 } 3009 } 3010 } 3011 } 3012 return options; 3013 } 3014 3015 function Image(config) { 3016 var that = this; 3017 3018 var smartCrops = {}; 3019 3020 var useAssetDelivery = false;
3021 var srcUriTemplateWidthVar = SRC_URI_TEMPLATE_WIDTH_VAR; 3022 3023 function init(config) { 3024 // prevents multiple initialization 3025 config.element.removeAttribute("data-" + NS + "-is"); 3026 3027 // check if asset delivery is used 3028 if (config.options.src && config.options.src.indexOf(SRC_URI_TEMPLATE_WIDTH_VAR_ASSET_DELIVERY) >= 0) { 3029 useAssetDelivery = true; 3030 srcUriTemplateWidthVar = SRC_URI_TEMPLATE_WIDTH_VAR_ASSET_DELIVERY; 3031 } 3032 3033 setupProperties(config.options); 3034 cacheElements(config.element); 3035 // check image is DM asset; if true try to make req=set 3036 if (config.options.src && Object.prototype.hasOwnProperty.call(config.options, "dmimage") && (config.options["smartcroprendition"] === "SmartCrop:Auto")) { 3037 var request = new XMLHttpRequest(); 3038 var urlTemplatePart = decodeURIComponent(config.options.src).split(srcUriTemplateWidthVar)[0]; 3039 var url = urlTemplatePart + (urlTemplatePart.indexOf("?") < 0 ? "?" : "") + "req=set,json"; 3040 3041 request.open("GET", url, false); 3042 request.onload = function() { 3043 if (request.status >= 200 && request.status < 400) { 3044 // success status 3045 var responseText = request.responseText; 3046 var rePayload = new RegExp(/^(?:\/\*jsonp\*\/)?\s*([^()]+)\(([\s\S]+),\s*"[0-9]*"\);?$/gmi); 3047 var rePayloadJSON = new RegExp(/^{[\s\S]*}$/gmi); 3048 var resPayload = rePayload.exec(responseText); 3049 var payload; 3050 if (resPayload) { 3051 var payloadStr = resPayload[2]; 3052 if (rePayloadJSON.test(payloadStr)) { 3053 payload = JSON.parse(payloadStr); 3054 } 3055 3056 } 3057 // check "relation" - only in case of smartcrop preset 3058 if (payload && payload.set.relation && payload.set.relation.length > 0) { 3059 for (var i = 0; i < payload.set.relation.length; i++) { 3060 smartCrops[parseInt(payload.set.relation[i].userdata.SmartCropWidth)] = 3061 ":" + payload.set.relation[i].userdata.SmartCropDef; 3062 } 3063 } 3064 } else { 3065 // error status 3066 } 3067 }; 3068 request.send(); 3069 } 3070 3071 if (!that._elements.noscript) { 3072 return; 3073 } 3074 3075 that._elements.container = that._elements.link ? that._elements.link : that._elements.self; 3076 3077 unwrapNoScript(); 3078 3079 if (that._properties.lazy) { 3080 addLazyLoader(); 3081 } 3082 3083 if (that._elements.map) { 3084 that._elements.image.addEventListener("load", onLoad); 3085 } 3086 3087 window.addEventListener("resize", onWindowResize); 3088 ["focus", "click", "load", "transitionend", "animationend", "scroll"].forEach(function(name) { 3089 document.addEventListener(name, that.update); 3090 }); 3091 3092 that._elements.image.addEventListener("cmp-image-redraw", that.update); 3093 that.update(); 3094 } 3095 3096 function loadImage() { 3097 var hasWidths = (that._properties.widths && that._properties.widths.length > 0) || Object.keys(smartCrops).length > 0; 3098 var replacement; 3099 if (Object.keys(smartCrops).length > 0) { 3100 var optimalWidth = getOptimalWidth(Object.keys(smartCrops), false); 3101 replacement = smartCrops[optimalWidth]; 3102 } else { 3103 replacement = hasWidths ? (that._properties.dmimage ? "" : ".") + getOptimalWidth(that._properties.widths, true) : ""; 3104 } 3105 if (useAssetDelivery) {
3106 replacement = replacement !== "" ? ("width=" + replacement.substring(1)) : ""; 3107 } 3108 var url = that._properties.src.replace(srcUriTemplateWidthVar, replacement); 3109 url = url.replace(SRC_URI_TEMPLATE_DPR_VAR, devicePixelRatio); 3110 3111 var imgSrcAttribute = that._elements.image.getAttribute("src"); 3112 3113 if (url !== imgSrcAttribute) { 3114 if (imgSrcAttribute === null || imgSrcAttribute === EMPTY_PIXEL) { 3115 that._elements.image.setAttribute("src", url); 3116 } else { 3117 var urlTemplateParts = that._properties.src.split(srcUriTemplateWidthVar); 3118 // check if image src was dynamically swapped meanwhile (e.g. by Target) 3119 var isImageRefSame = imgSrcAttribute.startsWith(urlTemplateParts[0]); 3120 if (isImageRefSame && urlTemplateParts.length > 1) { 3121 isImageRefSame = imgSrcAttribute.endsWith(urlTemplateParts[urlTemplateParts.length - 1]); 3122 } 3123 if (isImageRefSame) { 3124 that._elements.image.setAttribute("src", url); 3125 if (!hasWidths) { 3126 window.removeEventListener("scroll", that.update); 3127 } 3128 } 3129 } 3130 } 3131 if (that._lazyLoaderShowing) { 3132 that._elements.image.addEventListener("load", removeLazyLoader); 3133 } 3134 } 3135 3136 function getOptimalWidth(widths, useDevicePixelRatio) { 3137 var container = that._elements.self; 3138 var containerWidth = container.clientWidth; 3139 while (containerWidth === 0 && container.parentNode) { 3140 container = container.parentNode; 3141 containerWidth = container.clientWidth; 3142 } 3143 3144 var dpr = useDevicePixelRatio ? devicePixelRatio : 1; 3145 var optimalWidth = containerWidth * dpr; 3146 var len = widths.length; 3147 var key = 0; 3148 3149 while ((key < len - 1) && (widths[key] < optimalWidth)) { 3150 key++; 3151 } 3152 3153 return widths[key].toString(); 3154 } 3155 3156 function addLazyLoader() { 3157 var width = that._elements.image.getAttribute("width"); 3158 var height = that._elements.image.getAttribute("height"); 3159 3160 if (width && height) { 3161 var ratio = (height / width) * 100; 3162 var styles = lazyLoader.style; 3163 3164 styles["padding-bottom"] = ratio + "%"; 3165 3166 for (var s in styles) { 3167 if (Object.prototype.hasOwnProperty.call(styles, s)) { 3168 that._elements.image.style[s] = styles[s]; 3169 } 3170 } 3171 } 3172 that._elements.image.setAttribute("src", EMPTY_PIXEL); 3173 that._elements.image.classList.add(lazyLoader.cssClass); 3174 that._lazyLoaderShowing = true; 3175 } 3176 3177 function unwrapNoScript() { 3178 var markup = decodeNoscript(that._elements.noscript.textContent.trim()); 3179 var parser = new DOMParser(); 3180 3181 // temporary document avoids requesting the image before removing its src 3182 var temporaryDocument = parser.parseFromString(markup, "text/html"); 3183 var imageElement = temporaryDocument.querySelector(selectors.image); 3184 imageElement.removeAttribute("src"); 3185 that._elements.container.insertBefore(imageElement, that._elements.noscript); 3186 3187 var mapElement = temporaryDocument.querySelector(selectors.map); 3188 if (mapElement) { 3189 that._elements.container.insertBefore(mapElement, that._elements.noscript); 3190 } 3191 3192 that._elements.noscript.parentNode.removeChild(that._elements.noscript); 3193 if (that._elements.container.matches(selectors.image)) { 3194 that._elements.image = that._elements.container; 3195 } else { 3196 that._elements.image = that._elements.container.querySelector(selectors.image); 3197 } 3198 3199 that._elements.map = that._elements.container.querySelector(selectors.map); 3200 that._elements.areas = that._elements.container.querySelectorAll(selectors.area); 3201 } 3202 3203 function removeLazyLoader() { 3204 that._elements.image.classList.remove(lazyLoader.cssClass); 3205 for (var property in lazyLoader.style) { 3206 if (Object.prototype.hasOwnProperty.call(lazyLoader.style, property)) { 3207 that._elements.image.style[property] = ""; 3208 } 3209 } 3210 that._elements.image.removeEventListener("load", removeLazyLoader); 3211 that._lazyLoaderShowing = false;
3212 } 3213 3214 function isLazyVisible() { 3215 if (that._elements.container.offsetParent === null) { 3216 return false; 3217 } 3218 3219 var wt = window.pageYOffset; 3220 var wb = wt + document.documentElement.clientHeight; 3221 var et = that._elements.container.getBoundingClientRect().top + wt; 3222 var eb = et + that._elements.container.clientHeight; 3223 3224 return eb >= wt - that._properties.lazythreshold && et <= wb + that._properties.lazythreshold; 3225 } 3226 3227 function resizeAreas() { 3228 if (that._elements.areas && that._elements.areas.length > 0) { 3229 for (var i = 0; i < that._elements.areas.length; i++) { 3230 var width = that._elements.image.width; 3231 var height = that._elements.image.height; 3232 3233 if (width && height) { 3234 var relcoords = that._elements.areas[i].dataset.cmpRelcoords; 3235 if (relcoords) { 3236 var relativeCoordinates = relcoords.split(","); 3237 var coordinates = new Array(relativeCoordinates.length); 3238 3239 for (var j = 0; j < coordinates.length; j++) { 3240 if (j % 2 === 0) { 3241 coordinates[j] = parseInt(relativeCoordinates[j] * width); 3242 } else { 3243 coordinates[j] = parseInt(relativeCoordinates[j] * height); 3244 } 3245 } 3246 3247 that._elements.areas[i].coords = coordinates; 3248 } 3249 } 3250 } 3251 } 3252 } 3253 3254 function cacheElements(wrapper) { 3255 that._elements = {}; 3256 that._elements.self = wrapper; 3257 var hooks = that._elements.self.querySelectorAll("[data-" + NS + "-hook-" + IS + "]"); 3258 3259 for (var i = 0; i < hooks.length; i++) { 3260 var hook = hooks[i]; 3261 var capitalized = IS; 3262 capitalized = capitalized.charAt(0).toUpperCase() + capitalized.slice(1); 3263 var key = hook.dataset[NS + "Hook" + capitalized]; 3264 that._elements[key] = hook; 3265 } 3266 } 3267 3268 function setupProperties(options) { 3269 that._properties = {}; 3270 3271 for (var key in properties) { 3272 if (Object.prototype.hasOwnProperty.call(properties, key)) { 3273 var property = properties[key]; 3274 if (options && options[key] != null) { 3275 if (property && typeof property.transform === "function") { 3276 that._properties[key] = property.transform(options[key]); 3277 } else { 3278 that._properties[key] = options[key]; 3279 } 3280 } else { 3281 that._properties[key] = properties[key]["default"]; 3282 } 3283 } 3284 } 3285 } 3286 3287 function onWindowResize() { 3288 that.update(); 3289 resizeAreas(); 3290 } 3291 3292 function onLoad() { 3293 resizeAreas(); 3294 } 3295 3296 that.update = function() { 3297 if (that._properties.lazy) { 3298 if (isLazyVisible()) { 3299 loadImage(); 3300 } 3301 } else { 3302 loadImage(); 3303 } 3304 }; 3305 3306 if (config && config.element) { 3307 init(config); 3308 } 3309 } 3310 3311 function onDocumentReady() { 3312 var elements = document.querySelectorAll(selectors.self); 3313 for (var i = 0; i < elements.length; i++) { 3314 new Image({ element: elements[i], options: readData(elements[i]) }); 3315 } 3316 3317 var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver; 3318 var body = document.querySelector("body"); 3319 var observer = new MutationObserver(function(mutations) { 3320 mutations.forEach(function(mutation) { 3321 // needed for IE 3322 var nodesArray = [].slice.call(mutation.addedNodes); 3323 if (nodesArray.length > 0) { 3324 nodesArray.forEach(function(addedNode) { 3325 if (addedNode.querySelectorAll) { 3326 var elementsArray = [].slice.call(addedNode.querySelectorAll(selectors.self)); 3327 elementsArray.forEach(function(element) { 3328 new Image({ element: element, options: readData(element) }); 3329 }); 3330 } 3331 }); 3332 } 3333 }); 3334 }); 3335 3336 observer.observe(body, { 3337 subtree: true, 3338 childList: true, 3339 characterData: true 3340 }); 3341 } 3342 3343 if (document.readyState !== "loading") { 3344 onDocumentReady(); 3345 } else { 3346 document.addEventListener("DOMContentLoaded", onDocumentReady); 3347 } 3348 3349 /* 3350 on drag & drop of the component into a parsys, noscript's content will be escaped multiple times by the editor which creates 3351 the DOM for editing; the HTML parser cannot be used here due to the multiple escaping 3352 */ 3353 function decodeNoscript(text) { 3354 text = text.replace(/&(amp;)*lt;/g, "<"); 3355 text = text.replace(/&(amp;)*gt;/g, ">"); 3356 return text; 3357 } 3358 3359})(); 3360 3361/******************************************************************************* 3362 * Copyright 2017 Adobe 3363 * 3364 * Licensed under the Apache License, Version 2.0 (the "License");
3365 * you may not use this file except in compliance with the License. 3366 * You may obtain a copy of the License at 3367 * 3368 * http://www.apache.org/licenses/LICENSE-2.0 3369 * 3370 * Unless required by applicable law or agreed to in writing, software 3371 * distributed under the License is distributed on an "AS IS" BASIS, 3372 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 3373 * See the License for the specific language governing permissions and 3374 * limitations under the License. 3375 ******************************************************************************/ 3376if (window.Element && !Element.prototype.closest) { 3377 // eslint valid-jsdoc: "off" 3378 Element.prototype.closest = 3379 function(s) { 3380 "use strict"; 3381 var matches = (this.document || this.ownerDocument).querySelectorAll(s); 3382 var el = this; 3383 var i; 3384 do { 3385 i = matches.length; 3386 while (--i >= 0 && matches.item(i) !== el) { 3387 // continue 3388 } 3389 } while ((i < 0) && (el = el.parentElement)); 3390 return el; 3391 }; 3392} 3393 3394if (window.Element && !Element.prototype.matches) { 3395 Element.prototype.matches = 3396 Element.prototype.matchesSelector || 3397 Element.prototype.mozMatchesSelector || 3398 Element.prototype.msMatchesSelector || 3399 Element.prototype.oMatchesSelector || 3400 Element.prototype.webkitMatchesSelector || 3401 function(s) { 3402 "use strict"; 3403 var matches = (this.document || this.ownerDocument).querySelectorAll(s); 3404 var i = matches.length; 3405 while (--i >= 0 && matches.item(i) !== this) { 3406 // continue 3407 } 3408 return i > -1; 3409 }; 3410} 3411 3412if (!Object.assign) { 3413 Object.assign = function(target, varArgs) { // .length of function is 2 3414 "use strict"; 3415 if (target === null) { 3416 throw new TypeError("Cannot convert undefined or null to object"); 3417 } 3418 3419 var to = Object(target); 3420 3421 for (var index = 1; index < arguments.length; index++) { 3422 var nextSource = arguments[index]; 3423 3424 if (nextSource !== null) { 3425 for (var nextKey in nextSource) { 3426 if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) { 3427 to[nextKey] = nextSource[nextKey]; 3428 } 3429 } 3430 } 3431 } 3432 return to; 3433 }; 3434} 3435 3436(function(arr) { 3437 "use strict"; 3438 arr.forEach(function(item) { 3439 if (Object.prototype.hasOwnProperty.call(item, "remove")) { 3440 return; 3441 } 3442 Object.defineProperty(item, "remove", { 3443 configurable: true, 3444 enumerable: true, 3445 writable: true, 3446 value: function remove() { 3447 this.parentNode.removeChild(this); 3448 } 3449 }); 3450 }); 3451})([Element.prototype, CharacterData.prototype, DocumentType.prototype]); 3452 3453/******************************************************************************* 3454 * Copyright 2016 Adobe 3455 * 3456 * Licensed under the Apache License, Version 2.0 (the "License"); 3457 * you may not use this file except in compliance with the License. 3458 * You may obtain a copy of the License at 3459 * 3460 * http://www.apache.org/licenses/LICENSE-2.0 3461 * 3462 * Unless required by applicable law or agreed to in writing, software 3463 * distributed under the License is distributed on an "AS IS" BASIS, 3464 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 3465 * See the License for the specific language governing permissions and 3466 * limitations under the License. 3467 ******************************************************************************/ 3468(function() { 3469 "use strict"; 3470 3471 var NS = "cmp"; 3472 var IS = "image"; 3473 3474 var EMPTY_PIXEL = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"; 3475 var LAZY_THRESHOLD_DEFAULT = 0; 3476 var SRC_URI_TEMPLATE_WIDTH_VAR = "{.width}"; 3477 var SRC_URI_TEMPLATE_WIDTH_VAR_ASSET_DELIVERY = "width={width}"; 3478 var SRC_URI_TEMPLATE_DPR_VAR = "{dpr}"; 3479 3480 var selectors = { 3481 self: "[data-" + NS + '-is="' + IS + '"]', 3482 image: '[data-cmp-hook-image="image"]', 3483 map: '[data-cmp-hook-image="map"]', 3484 area: '[data-cmp-hook-image="area"]' 3485 }; 3486 3487 var lazyLoader = { 3488 "cssClass": "cmp-image__image--is-loading", 3489 "style": { 3490 "height": 0, 3491 "padding-bottom": "" // will be replaced with % ratio 3492 } 3493 }; 3494 3495 var properties = { 3496 /** 3497 * An array of alternative image widths (in pixels). 3498 * Used to replace a {.width} variable in the src property with an optimal width if a URI template is provided. 3499 * 3500 * @memberof Image 3501 * @type {Number[]} 3502 * @default [] 3503 */ 3504 "widths": { 3505 "default": [], 3506 "transform": function(value) { 3507 var widths = []; 3508 value.split(",").forEach(function(item) { 3509 item = parseFloat(item); 3510 if (!isNaN(item)) { 3511 widths.push(item); 3512 } 3513 }); 3514 return widths; 3515 } 3516 }, 3517 /** 3518 * Indicates whether the image should be rendered lazily. 3519 * 3520 * @memberof Image 3521 * @type {Boolean} 3522 * @default false 3523 */ 3524 "lazy": { 3525 "default": false, 3526 "transform": function(value) { 3527 return !(value === null || typeof value === "undefined"); 3528 } 3529 }, 3530 /** 3531 * Indicates image is DynamicMedia image. 3532 * 3533 * @memberof Image 3534 * @type {Boolean} 3535 * @default false 3536 */ 3537 "dmimage": { 3538 "default": false, 3539 "transform": function(value) { 3540 return !(value === null || typeof value === "undefined"); 3541 } 3542 }, 3543 /** 3544 * The lazy threshold. 3545 * This is the number of pixels, in advance of becoming visible, when an lazy-loading image should begin 3546 * to load. 3547 * 3548 * @memberof Image 3549 * @type {Number} 3550 * @default 0 3551 */ 3552 "lazythreshold": { 3553 "default": 0, 3554 "transform": function(value) { 3555 var val = parseInt(value); 3556 if (isNaN(val)) { 3557 return LAZY_THRESHOLD_DEFAULT; 3558 } 3559 return val; 3560 } 3561 }, 3562 /** 3563 * The image source. 3564 * 3565 * Can be a simple image source, or a URI template representation that 3566 * can be variable expanded - useful for building an image configuration with an alternative width. 3567 * e.g. '/path/image.coreimg{.width}.jpeg/1506620954214.jpeg' 3568 * 3569 * @memberof Image 3570 * @type {String} 3571 */ 3572 "src": { 3573 "transform": function(value) { 3574 return decodeURIComponent(value); 3575 } 3576 } 3577 }; 3578 3579 var devicePixelRatio = window.devicePixelRatio || 1; 3580 3581 function readData(element) { 3582 var data = element.dataset; 3583 var options = []; 3584 var capitalized = IS; 3585 capitalized = capitalized.charAt(0).toUpperCase() + capitalized.slice(1); 3586 var reserved = ["is", "hook" + capitalized]; 3587 3588 for (var key in data) { 3589 if (Object.prototype.hasOwnProperty.call(data, key)) { 3590 var value = data[key]; 3591 3592 if (key.indexOf(NS) === 0) { 3593 key = key.slice(NS.length); 3594 key = key.charAt(0).toLowerCase() + key.substring(1); 3595 3596 if (reserved.indexOf(key) === -1) { 3597 options[key] = value; 3598 } 3599 } 3600 } 3601 } 3602 return options; 3603 } 3604 3605 function Image(config) { 3606 var that = this; 3607 3608 var smartCrops = {}; 3609 3610 var useAssetDelivery = false;
3611 var srcUriTemplateWidthVar = SRC_URI_TEMPLATE_WIDTH_VAR; 3612 3613 function init(config) { 3614 // prevents multiple initialization 3615 config.element.removeAttribute("data-" + NS + "-is"); 3616 3617 // check if asset delivery is used 3618 if (config.options.src && config.options.src.indexOf(SRC_URI_TEMPLATE_WIDTH_VAR_ASSET_DELIVERY) >= 0) { 3619 useAssetDelivery = true; 3620 srcUriTemplateWidthVar = SRC_URI_TEMPLATE_WIDTH_VAR_ASSET_DELIVERY; 3621 } 3622 3623 setupProperties(config.options); 3624 cacheElements(config.element); 3625 // check image is DM asset; if true try to make req=set 3626 if (config.options.src && Object.prototype.hasOwnProperty.call(config.options, "dmimage") && (config.options["smartcroprendition"] === "SmartCrop:Auto")) { 3627 var request = new XMLHttpRequest(); 3628 var urlTemplatePart = decodeURIComponent(config.options.src).split(srcUriTemplateWidthVar)[0]; 3629 var url = urlTemplatePart + (urlTemplatePart.indexOf("?") < 0 ? "?" : "") + "req=set,json"; 3630 3631 request.open("GET", url, false); 3632 request.onload = function() { 3633 if (request.status >= 200 && request.status < 400) { 3634 // success status 3635 var responseText = request.responseText; 3636 var rePayload = new RegExp(/^(?:\/\*jsonp\*\/)?\s*([^()]+)\(([\s\S]+),\s*"[0-9]*"\);?$/gmi); 3637 var rePayloadJSON = new RegExp(/^{[\s\S]*}$/gmi); 3638 var resPayload = rePayload.exec(responseText); 3639 var payload; 3640 if (resPayload) { 3641 var payloadStr = resPayload[2]; 3642 if (rePayloadJSON.test(payloadStr)) { 3643 payload = JSON.parse(payloadStr); 3644 } 3645 3646 } 3647 // check "relation" - only in case of smartcrop preset 3648 if (payload && payload.set.relation && payload.set.relation.length > 0) { 3649 for (var i = 0; i < payload.set.relation.length; i++) { 3650 smartCrops[parseInt(payload.set.relation[i].userdata.SmartCropWidth)] = 3651 ":" + payload.set.relation[i].userdata.SmartCropDef; 3652 } 3653 } 3654 } else { 3655 // error status 3656 } 3657 }; 3658 request.send(); 3659 } 3660 3661 if (!that._elements.noscript) { 3662 return; 3663 } 3664 3665 that._elements.container = that._elements.link ? that._elements.link : that._elements.self; 3666 3667 unwrapNoScript(); 3668 3669 if (that._properties.lazy) { 3670 addLazyLoader(); 3671 } 3672 3673 if (that._elements.map) { 3674 that._elements.image.addEventListener("load", onLoad); 3675 } 3676 3677 window.addEventListener("resize", onWindowResize); 3678 ["focus", "click", "load", "transitionend", "animationend", "scroll"].forEach(function(name) { 3679 document.addEventListener(name, that.update); 3680 }); 3681 3682 that._elements.image.addEventListener("cmp-image-redraw", that.update); 3683 that.update(); 3684 } 3685 3686 function loadImage() { 3687 var hasWidths = (that._properties.widths && that._properties.widths.length > 0) || Object.keys(smartCrops).length > 0; 3688 var replacement; 3689 if (Object.keys(smartCrops).length > 0) { 3690 var optimalWidth = getOptimalWidth(Object.keys(smartCrops), false); 3691 replacement = smartCrops[optimalWidth]; 3692 } else { 3693 replacement = hasWidths ? (that._properties.dmimage ? "" : ".") + getOptimalWidth(that._properties.widths, true) : ""; 3694 } 3695 if (useAssetDelivery) {
3696 replacement = replacement !== "" ? ("width=" + replacement.substring(1)) : ""; 3697 } 3698 var url = that._properties.src.replace(srcUriTemplateWidthVar, replacement); 3699 url = url.replace(SRC_URI_TEMPLATE_DPR_VAR, devicePixelRatio); 3700 3701 var imgSrcAttribute = that._elements.image.getAttribute("src"); 3702 3703 if (url !== imgSrcAttribute) { 3704 if (imgSrcAttribute === null || imgSrcAttribute === EMPTY_PIXEL) { 3705 that._elements.image.setAttribute("src", url); 3706 } else { 3707 var urlTemplateParts = that._properties.src.split(srcUriTemplateWidthVar); 3708 // check if image src was dynamically swapped meanwhile (e.g. by Target) 3709 var isImageRefSame = imgSrcAttribute.startsWith(urlTemplateParts[0]); 3710 if (isImageRefSame && urlTemplateParts.length > 1) { 3711 isImageRefSame = imgSrcAttribute.endsWith(urlTemplateParts[urlTemplateParts.length - 1]); 3712 } 3713 if (isImageRefSame) { 3714 that._elements.image.setAttribute("src", url); 3715 if (!hasWidths) { 3716 window.removeEventListener("scroll", that.update); 3717 } 3718 } 3719 } 3720 } 3721 if (that._lazyLoaderShowing) { 3722 that._elements.image.addEventListener("load", removeLazyLoader); 3723 } 3724 } 3725 3726 function getOptimalWidth(widths, useDevicePixelRatio) { 3727 var container = that._elements.self; 3728 var containerWidth = container.clientWidth; 3729 while (containerWidth === 0 && container.parentNode) { 3730 container = container.parentNode; 3731 containerWidth = container.clientWidth; 3732 } 3733 3734 var dpr = useDevicePixelRatio ? devicePixelRatio : 1; 3735 var optimalWidth = containerWidth * dpr; 3736 var len = widths.length; 3737 var key = 0; 3738 3739 while ((key < len - 1) && (widths[key] < optimalWidth)) { 3740 key++; 3741 } 3742 3743 return widths[key].toString(); 3744 } 3745 3746 function addLazyLoader() { 3747 var width = that._elements.image.getAttribute("width"); 3748 var height = that._elements.image.getAttribute("height"); 3749 3750 if (width && height) { 3751 var ratio = (height / width) * 100; 3752 var styles = lazyLoader.style; 3753 3754 styles["padding-bottom"] = ratio + "%"; 3755 3756 for (var s in styles) { 3757 if (Object.prototype.hasOwnProperty.call(styles, s)) { 3758 that._elements.image.style[s] = styles[s]; 3759 } 3760 } 3761 } 3762 that._elements.image.setAttribute("src", EMPTY_PIXEL); 3763 that._elements.image.classList.add(lazyLoader.cssClass); 3764 that._lazyLoaderShowing = true; 3765 } 3766 3767 function unwrapNoScript() { 3768 var markup = decodeNoscript(that._elements.noscript.textContent.trim()); 3769 var parser = new DOMParser(); 3770 3771 // temporary document avoids requesting the image before removing its src 3772 var temporaryDocument = parser.parseFromString(markup, "text/html"); 3773 var imageElement = temporaryDocument.querySelector(selectors.image); 3774 imageElement.removeAttribute("src"); 3775 that._elements.container.insertBefore(imageElement, that._elements.noscript); 3776 3777 var mapElement = temporaryDocument.querySelector(selectors.map); 3778 if (mapElement) { 3779 that._elements.container.insertBefore(mapElement, that._elements.noscript); 3780 } 3781 3782 that._elements.noscript.parentNode.removeChild(that._elements.noscript); 3783 if (that._elements.container.matches(selectors.image)) { 3784 that._elements.image = that._elements.container; 3785 } else { 3786 that._elements.image = that._elements.container.querySelector(selectors.image); 3787 } 3788 3789 that._elements.map = that._elements.container.querySelector(selectors.map); 3790 that._elements.areas = that._elements.container.querySelectorAll(selectors.area); 3791 } 3792 3793 function removeLazyLoader() { 3794 that._elements.image.classList.remove(lazyLoader.cssClass); 3795 for (var property in lazyLoader.style) { 3796 if (Object.prototype.hasOwnProperty.call(lazyLoader.style, property)) { 3797 that._elements.image.style[property] = ""; 3798 } 3799 } 3800 that._elements.image.removeEventListener("load", removeLazyLoader); 3801 that._lazyLoaderShowing = false;
3802 } 3803 3804 function isLazyVisible() { 3805 if (that._elements.container.offsetParent === null) { 3806 return false; 3807 } 3808 3809 var wt = window.pageYOffset; 3810 var wb = wt + document.documentElement.clientHeight; 3811 var et = that._elements.container.getBoundingClientRect().top + wt; 3812 var eb = et + that._elements.container.clientHeight; 3813 3814 return eb >= wt - that._properties.lazythreshold && et <= wb + that._properties.lazythreshold; 3815 } 3816 3817 function resizeAreas() { 3818 if (that._elements.areas && that._elements.areas.length > 0) { 3819 for (var i = 0; i < that._elements.areas.length; i++) { 3820 var width = that._elements.image.width; 3821 var height = that._elements.image.height; 3822 3823 if (width && height) { 3824 var relcoords = that._elements.areas[i].dataset.cmpRelcoords; 3825 if (relcoords) { 3826 var relativeCoordinates = relcoords.split(","); 3827 var coordinates = new Array(relativeCoordinates.length); 3828 3829 for (var j = 0; j < coordinates.length; j++) { 3830 if (j % 2 === 0) { 3831 coordinates[j] = parseInt(relativeCoordinates[j] * width); 3832 } else { 3833 coordinates[j] = parseInt(relativeCoordinates[j] * height); 3834 } 3835 } 3836 3837 that._elements.areas[i].coords = coordinates; 3838 } 3839 } 3840 } 3841 } 3842 } 3843 3844 function cacheElements(wrapper) { 3845 that._elements = {}; 3846 that._elements.self = wrapper; 3847 var hooks = that._elements.self.querySelectorAll("[data-" + NS + "-hook-" + IS + "]"); 3848 3849 for (var i = 0; i < hooks.length; i++) { 3850 var hook = hooks[i]; 3851 var capitalized = IS; 3852 capitalized = capitalized.charAt(0).toUpperCase() + capitalized.slice(1); 3853 var key = hook.dataset[NS + "Hook" + capitalized]; 3854 that._elements[key] = hook; 3855 } 3856 } 3857 3858 function setupProperties(options) { 3859 that._properties = {}; 3860 3861 for (var key in properties) { 3862 if (Object.prototype.hasOwnProperty.call(properties, key)) { 3863 var property = properties[key]; 3864 if (options && options[key] != null) { 3865 if (property && typeof property.transform === "function") { 3866 that._properties[key] = property.transform(options[key]); 3867 } else { 3868 that._properties[key] = options[key]; 3869 } 3870 } else { 3871 that._properties[key] = properties[key]["default"]; 3872 } 3873 } 3874 } 3875 } 3876 3877 function onWindowResize() { 3878 that.update(); 3879 resizeAreas(); 3880 } 3881 3882 function onLoad() { 3883 resizeAreas(); 3884 } 3885 3886 that.update = function() { 3887 if (that._properties.lazy) { 3888 if (isLazyVisible()) { 3889 loadImage(); 3890 } 3891 } else { 3892 loadImage(); 3893 } 3894 }; 3895 3896 if (config && config.element) { 3897 init(config); 3898 } 3899 } 3900 3901 function onDocumentReady() { 3902 var elements = document.querySelectorAll(selectors.self); 3903 for (var i = 0; i < elements.length; i++) { 3904 new Image({ element: elements[i], options: readData(elements[i]) }); 3905 } 3906 3907 var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver; 3908 var body = document.querySelector("body"); 3909 var observer = new MutationObserver(function(mutations) { 3910 mutations.forEach(function(mutation) { 3911 // needed for IE 3912 var nodesArray = [].slice.call(mutation.addedNodes); 3913 if (nodesArray.length > 0) { 3914 nodesArray.forEach(function(addedNode) { 3915 if (addedNode.querySelectorAll) { 3916 var elementsArray = [].slice.call(addedNode.querySelectorAll(selectors.self)); 3917 elementsArray.forEach(function(element) { 3918 new Image({ element: element, options: readData(element) }); 3919 }); 3920 } 3921 }); 3922 } 3923 }); 3924 }); 3925 3926 observer.observe(body, { 3927 subtree: true, 3928 childList: true, 3929 characterData: true 3930 }); 3931 } 3932 3933 if (document.readyState !== "loading") { 3934 onDocumentReady(); 3935 } else { 3936 document.addEventListener("DOMContentLoaded", onDocumentReady); 3937 } 3938 3939 /* 3940 on drag & drop of the component into a parsys, noscript's content will be escaped multiple times by the editor which creates 3941 the DOM for editing; the HTML parser cannot be used here due to the multiple escaping 3942 */ 3943 function decodeNoscript(text) { 3944 text = text.replace(/&(amp;)*lt;/g, "<"); 3945 text = text.replace(/&(amp;)*gt;/g, ">"); 3946 return text; 3947 } 3948 3949})(); 3950 3951/******************************************************************************* 3952 * Copyright 2017 Adobe 3953 * 3954 * Licensed under the Apache License, Version 2.0 (the "License");
3955 * you may not use this file except in compliance with the License. 3956 * You may obtain a copy of the License at 3957 * 3958 * http://www.apache.org/licenses/LICENSE-2.0 3959 * 3960 * Unless required by applicable law or agreed to in writing, software 3961 * distributed under the License is distributed on an "AS IS" BASIS, 3962 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 3963 * See the License for the specific language governing permissions and 3964 * limitations under the License. 3965 ******************************************************************************/ 3966if (window.Element && !Element.prototype.closest) { 3967 // eslint valid-jsdoc: "off" 3968 Element.prototype.closest = 3969 function(s) { 3970 "use strict"; 3971 var matches = (this.document || this.ownerDocument).querySelectorAll(s); 3972 var el = this; 3973 var i; 3974 do { 3975 i = matches.length; 3976 while (--i >= 0 && matches.item(i) !== el) { 3977 // continue 3978 } 3979 } while ((i < 0) && (el = el.parentElement)); 3980 return el; 3981 }; 3982} 3983 3984if (window.Element && !Element.prototype.matches) { 3985 Element.prototype.matches = 3986 Element.prototype.matchesSelector || 3987 Element.prototype.mozMatchesSelector || 3988 Element.prototype.msMatchesSelector || 3989 Element.prototype.oMatchesSelector || 3990 Element.prototype.webkitMatchesSelector || 3991 function(s) { 3992 "use strict"; 3993 var matches = (this.document || this.ownerDocument).querySelectorAll(s); 3994 var i = matches.length; 3995 while (--i >= 0 && matches.item(i) !== this) { 3996 // continue 3997 } 3998 return i > -1; 3999 }; 4000} 4001 4002if (!Object.assign) { 4003 Object.assign = function(target, varArgs) { // .length of function is 2 4004 "use strict"; 4005 if (target === null) { 4006 throw new TypeError("Cannot convert undefined or null to object"); 4007 } 4008 4009 var to = Object(target); 4010 4011 for (var index = 1; index < arguments.length; index++) { 4012 var nextSource = arguments[index]; 4013 4014 if (nextSource !== null) { 4015 for (var nextKey in nextSource) { 4016 if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) { 4017 to[nextKey] = nextSource[nextKey]; 4018 } 4019 } 4020 } 4021 } 4022 return to; 4023 }; 4024} 4025 4026(function(arr) { 4027 "use strict"; 4028 arr.forEach(function(item) { 4029 if (Object.prototype.hasOwnProperty.call(item, "remove")) { 4030 return; 4031 } 4032 Object.defineProperty(item, "remove", { 4033 configurable: true, 4034 enumerable: true, 4035 writable: true, 4036 value: function remove() { 4037 this.parentNode.removeChild(this); 4038 } 4039 }); 4040 }); 4041})([Element.prototype, CharacterData.prototype, DocumentType.prototype]); 4042 4043/******************************************************************************* 4044 * Copyright 2016 Adobe 4045 * 4046 * Licensed under the Apache License, Version 2.0 (the "License"); 4047 * you may not use this file except in compliance with the License. 4048 * You may obtain a copy of the License at 4049 * 4050 * http://www.apache.org/licenses/LICENSE-2.0 4051 * 4052 * Unless required by applicable law or agreed to in writing, software 4053 * distributed under the License is distributed on an "AS IS" BASIS, 4054 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 4055 * See the License for the specific language governing permissions and 4056 * limitations under the License. 4057 ******************************************************************************/ 4058(function() { 4059 "use strict"; 4060 4061 var NS = "cmp"; 4062 var IS = "image"; 4063 4064 var EMPTY_PIXEL = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"; 4065 var LAZY_THRESHOLD_DEFAULT = 0; 4066 var SRC_URI_TEMPLATE_WIDTH_VAR = "{.width}"; 4067 var SRC_URI_TEMPLATE_WIDTH_VAR_ASSET_DELIVERY = "width={width}"; 4068 var SRC_URI_TEMPLATE_DPR_VAR = "{dpr}"; 4069 4070 var selectors = { 4071 self: "[data-" + NS + '-is="' + IS + '"]', 4072 image: '[data-cmp-hook-image="image"]', 4073 map: '[data-cmp-hook-image="map"]', 4074 area: '[data-cmp-hook-image="area"]' 4075 }; 4076 4077 var lazyLoader = { 4078 "cssClass": "cmp-image__image--is-loading", 4079 "style": { 4080 "height": 0, 4081 "padding-bottom": "" // will be replaced with % ratio 4082 } 4083 }; 4084 4085 var properties = { 4086 /** 4087 * An array of alternative image widths (in pixels). 4088 * Used to replace a {.width} variable in the src property with an optimal width if a URI template is provided. 4089 * 4090 * @memberof Image 4091 * @type {Number[]} 4092 * @default [] 4093 */ 4094 "widths": { 4095 "default": [], 4096 "transform": function(value) { 4097 var widths = []; 4098 value.split(",").forEach(function(item) { 4099 item = parseFloat(item); 4100 if (!isNaN(item)) { 4101 widths.push(item); 4102 } 4103 }); 4104 return widths; 4105 } 4106 }, 4107 /** 4108 * Indicates whether the image should be rendered lazily. 4109 * 4110 * @memberof Image 4111 * @type {Boolean} 4112 * @default false 4113 */ 4114 "lazy": { 4115 "default": false, 4116 "transform": function(value) { 4117 return !(value === null || typeof value === "undefined"); 4118 } 4119 }, 4120 /** 4121 * Indicates image is DynamicMedia image. 4122 * 4123 * @memberof Image 4124 * @type {Boolean} 4125 * @default false 4126 */ 4127 "dmimage": { 4128 "default": false, 4129 "transform": function(value) { 4130 return !(value === null || typeof value === "undefined"); 4131 } 4132 }, 4133 /** 4134 * The lazy threshold. 4135 * This is the number of pixels, in advance of becoming visible, when an lazy-loading image should begin 4136 * to load. 4137 * 4138 * @memberof Image 4139 * @type {Number} 4140 * @default 0 4141 */ 4142 "lazythreshold": { 4143 "default": 0, 4144 "transform": function(value) { 4145 var val = parseInt(value); 4146 if (isNaN(val)) { 4147 return LAZY_THRESHOLD_DEFAULT; 4148 } 4149 return val; 4150 } 4151 }, 4152 /** 4153 * The image source. 4154 * 4155 * Can be a simple image source, or a URI template representation that 4156 * can be variable expanded - useful for building an image configuration with an alternative width. 4157 * e.g. '/path/image.coreimg{.width}.jpeg/1506620954214.jpeg' 4158 * 4159 * @memberof Image 4160 * @type {String} 4161 */ 4162 "src": { 4163 "transform": function(value) { 4164 return decodeURIComponent(value); 4165 } 4166 } 4167 }; 4168 4169 var devicePixelRatio = window.devicePixelRatio || 1; 4170 4171 function readData(element) { 4172 var data = element.dataset; 4173 var options = []; 4174 var capitalized = IS; 4175 capitalized = capitalized.charAt(0).toUpperCase() + capitalized.slice(1); 4176 var reserved = ["is", "hook" + capitalized]; 4177 4178 for (var key in data) { 4179 if (Object.prototype.hasOwnProperty.call(data, key)) { 4180 var value = data[key]; 4181 4182 if (key.indexOf(NS) === 0) { 4183 key = key.slice(NS.length); 4184 key = key.charAt(0).toLowerCase() + key.substring(1); 4185 4186 if (reserved.indexOf(key) === -1) { 4187 options[key] = value; 4188 } 4189 } 4190 } 4191 } 4192 return options; 4193 } 4194 4195 function Image(config) { 4196 var that = this; 4197 4198 var smartCrops = {}; 4199 4200 var useAssetDelivery = false;
4201 var srcUriTemplateWidthVar = SRC_URI_TEMPLATE_WIDTH_VAR; 4202 4203 function init(config) { 4204 // prevents multiple initialization 4205 config.element.removeAttribute("data-" + NS + "-is"); 4206 4207 // check if asset delivery is used 4208 if (config.options.src && config.options.src.indexOf(SRC_URI_TEMPLATE_WIDTH_VAR_ASSET_DELIVERY) >= 0) { 4209 useAssetDelivery = true; 4210 srcUriTemplateWidthVar = SRC_URI_TEMPLATE_WIDTH_VAR_ASSET_DELIVERY; 4211 } 4212 4213 setupProperties(config.options); 4214 cacheElements(config.element); 4215 // check image is DM asset; if true try to make req=set 4216 if (config.options.src && Object.prototype.hasOwnProperty.call(config.options, "dmimage") && (config.options["smartcroprendition"] === "SmartCrop:Auto")) { 4217 var request = new XMLHttpRequest(); 4218 var urlTemplatePart = decodeURIComponent(config.options.src).split(srcUriTemplateWidthVar)[0]; 4219 var url = urlTemplatePart + (urlTemplatePart.indexOf("?") < 0 ? "?" : "") + "req=set,json"; 4220 4221 request.open("GET", url, false); 4222 request.onload = function() { 4223 if (request.status >= 200 && request.status < 400) { 4224 // success status 4225 var responseText = request.responseText; 4226 var rePayload = new RegExp(/^(?:\/\*jsonp\*\/)?\s*([^()]+)\(([\s\S]+),\s*"[0-9]*"\);?$/gmi); 4227 var rePayloadJSON = new RegExp(/^{[\s\S]*}$/gmi); 4228 var resPayload = rePayload.exec(responseText); 4229 var payload; 4230 if (resPayload) { 4231 var payloadStr = resPayload[2]; 4232 if (rePayloadJSON.test(payloadStr)) { 4233 payload = JSON.parse(payloadStr); 4234 } 4235 4236 } 4237 // check "relation" - only in case of smartcrop preset 4238 if (payload && payload.set.relation && payload.set.relation.length > 0) { 4239 for (var i = 0; i < payload.set.relation.length; i++) { 4240 smartCrops[parseInt(payload.set.relation[i].userdata.SmartCropWidth)] = 4241 ":" + payload.set.relation[i].userdata.SmartCropDef; 4242 } 4243 } 4244 } else { 4245 // error status 4246 } 4247 }; 4248 request.send(); 4249 } 4250 4251 if (!that._elements.noscript) { 4252 return; 4253 } 4254 4255 that._elements.container = that._elements.link ? that._elements.link : that._elements.self; 4256 4257 unwrapNoScript(); 4258 4259 if (that._properties.lazy) { 4260 addLazyLoader(); 4261 } 4262 4263 if (that._elements.map) { 4264 that._elements.image.addEventListener("load", onLoad); 4265 } 4266 4267 window.addEventListener("resize", onWindowResize); 4268 ["focus", "click", "load", "transitionend", "animationend", "scroll"].forEach(function(name) { 4269 document.addEventListener(name, that.update); 4270 }); 4271 4272 that._elements.image.addEventListener("cmp-image-redraw", that.update); 4273 that.update(); 4274 } 4275 4276 function loadImage() { 4277 var hasWidths = (that._properties.widths && that._properties.widths.length > 0) || Object.keys(smartCrops).length > 0; 4278 var replacement; 4279 if (Object.keys(smartCrops).length > 0) { 4280 var optimalWidth = getOptimalWidth(Object.keys(smartCrops), false); 4281 replacement = smartCrops[optimalWidth]; 4282 } else { 4283 replacement = hasWidths ? (that._properties.dmimage ? "" : ".") + getOptimalWidth(that._properties.widths, true) : ""; 4284 } 4285 if (useAssetDelivery) {
4286 replacement = replacement !== "" ? ("width=" + replacement.substring(1)) : ""; 4287 } 4288 var url = that._properties.src.replace(srcUriTemplateWidthVar, replacement); 4289 url = url.replace(SRC_URI_TEMPLATE_DPR_VAR, devicePixelRatio); 4290 4291 var imgSrcAttribute = that._elements.image.getAttribute("src"); 4292 4293 if (url !== imgSrcAttribute) { 4294 if (imgSrcAttribute === null || imgSrcAttribute === EMPTY_PIXEL) { 4295 that._elements.image.setAttribute("src", url); 4296 } else { 4297 var urlTemplateParts = that._properties.src.split(srcUriTemplateWidthVar); 4298 // check if image src was dynamically swapped meanwhile (e.g. by Target) 4299 var isImageRefSame = imgSrcAttribute.startsWith(urlTemplateParts[0]); 4300 if (isImageRefSame && urlTemplateParts.length > 1) { 4301 isImageRefSame = imgSrcAttribute.endsWith(urlTemplateParts[urlTemplateParts.length - 1]); 4302 } 4303 if (isImageRefSame) { 4304 that._elements.image.setAttribute("src", url); 4305 if (!hasWidths) { 4306 window.removeEventListener("scroll", that.update); 4307 } 4308 } 4309 } 4310 } 4311 if (that._lazyLoaderShowing) { 4312 that._elements.image.addEventListener("load", removeLazyLoader); 4313 } 4314 } 4315 4316 function getOptimalWidth(widths, useDevicePixelRatio) { 4317 var container = that._elements.self; 4318 var containerWidth = container.clientWidth; 4319 while (containerWidth === 0 && container.parentNode) { 4320 container = container.parentNode; 4321 containerWidth = container.clientWidth; 4322 } 4323 4324 var dpr = useDevicePixelRatio ? devicePixelRatio : 1; 4325 var optimalWidth = containerWidth * dpr; 4326 var len = widths.length; 4327 var key = 0; 4328 4329 while ((key < len - 1) && (widths[key] < optimalWidth)) { 4330 key++; 4331 } 4332 4333 return widths[key].toString(); 4334 } 4335 4336 function addLazyLoader() { 4337 var width = that._elements.image.getAttribute("width"); 4338 var height = that._elements.image.getAttribute("height"); 4339 4340 if (width && height) { 4341 var ratio = (height / width) * 100; 4342 var styles = lazyLoader.style; 4343 4344 styles["padding-bottom"] = ratio + "%"; 4345 4346 for (var s in styles) { 4347 if (Object.prototype.hasOwnProperty.call(styles, s)) { 4348 that._elements.image.style[s] = styles[s]; 4349 } 4350 } 4351 } 4352 that._elements.image.setAttribute("src", EMPTY_PIXEL); 4353 that._elements.image.classList.add(lazyLoader.cssClass); 4354 that._lazyLoaderShowing = true; 4355 } 4356 4357 function unwrapNoScript() { 4358 var markup = decodeNoscript(that._elements.noscript.textContent.trim()); 4359 var parser = new DOMParser(); 4360 4361 // temporary document avoids requesting the image before removing its src 4362 var temporaryDocument = parser.parseFromString(markup, "text/html"); 4363 var imageElement = temporaryDocument.querySelector(selectors.image); 4364 imageElement.removeAttribute("src"); 4365 that._elements.container.insertBefore(imageElement, that._elements.noscript); 4366 4367 var mapElement = temporaryDocument.querySelector(selectors.map); 4368 if (mapElement) { 4369 that._elements.container.insertBefore(mapElement, that._elements.noscript); 4370 } 4371 4372 that._elements.noscript.parentNode.removeChild(that._elements.noscript); 4373 if (that._elements.container.matches(selectors.image)) { 4374 that._elements.image = that._elements.container; 4375 } else { 4376 that._elements.image = that._elements.container.querySelector(selectors.image); 4377 } 4378 4379 that._elements.map = that._elements.container.querySelector(selectors.map); 4380 that._elements.areas = that._elements.container.querySelectorAll(selectors.area); 4381 } 4382 4383 function removeLazyLoader() { 4384 that._elements.image.classList.remove(lazyLoader.cssClass); 4385 for (var property in lazyLoader.style) { 4386 if (Object.prototype.hasOwnProperty.call(lazyLoader.style, property)) { 4387 that._elements.image.style[property] = ""; 4388 } 4389 } 4390 that._elements.image.removeEventListener("load", removeLazyLoader); 4391 that._lazyLoaderShowing = false;
4392 } 4393 4394 function isLazyVisible() { 4395 if (that._elements.container.offsetParent === null) { 4396 return false; 4397 } 4398 4399 var wt = window.pageYOffset; 4400 var wb = wt + document.documentElement.clientHeight; 4401 var et = that._elements.container.getBoundingClientRect().top + wt; 4402 var eb = et + that._elements.container.clientHeight; 4403 4404 return eb >= wt - that._properties.lazythreshold && et <= wb + that._properties.lazythreshold; 4405 } 4406 4407 function resizeAreas() { 4408 if (that._elements.areas && that._elements.areas.length > 0) { 4409 for (var i = 0; i < that._elements.areas.length; i++) { 4410 var width = that._elements.image.width; 4411 var height = that._elements.image.height; 4412 4413 if (width && height) { 4414 var relcoords = that._elements.areas[i].dataset.cmpRelcoords; 4415 if (relcoords) { 4416 var relativeCoordinates = relcoords.split(","); 4417 var coordinates = new Array(relativeCoordinates.length); 4418 4419 for (var j = 0; j < coordinates.length; j++) { 4420 if (j % 2 === 0) { 4421 coordinates[j] = parseInt(relativeCoordinates[j] * width); 4422 } else { 4423 coordinates[j] = parseInt(relativeCoordinates[j] * height); 4424 } 4425 } 4426 4427 that._elements.areas[i].coords = coordinates; 4428 } 4429 } 4430 } 4431 } 4432 } 4433 4434 function cacheElements(wrapper) { 4435 that._elements = {}; 4436 that._elements.self = wrapper; 4437 var hooks = that._elements.self.querySelectorAll("[data-" + NS + "-hook-" + IS + "]"); 4438 4439 for (var i = 0; i < hooks.length; i++) { 4440 var hook = hooks[i]; 4441 var capitalized = IS; 4442 capitalized = capitalized.charAt(0).toUpperCase() + capitalized.slice(1); 4443 var key = hook.dataset[NS + "Hook" + capitalized]; 4444 that._elements[key] = hook; 4445 } 4446 } 4447 4448 function setupProperties(options) { 4449 that._properties = {}; 4450 4451 for (var key in properties) { 4452 if (Object.prototype.hasOwnProperty.call(properties, key)) { 4453 var property = properties[key]; 4454 if (options && options[key] != null) { 4455 if (property && typeof property.transform === "function") { 4456 that._properties[key] = property.transform(options[key]); 4457 } else { 4458 that._properties[key] = options[key]; 4459 } 4460 } else { 4461 that._properties[key] = properties[key]["default"]; 4462 } 4463 } 4464 } 4465 } 4466 4467 function onWindowResize() { 4468 that.update(); 4469 resizeAreas(); 4470 } 4471 4472 function onLoad() { 4473 resizeAreas(); 4474 } 4475 4476 that.update = function() { 4477 if (that._properties.lazy) { 4478 if (isLazyVisible()) { 4479 loadImage(); 4480 } 4481 } else { 4482 loadImage(); 4483 } 4484 }; 4485 4486 if (config && config.element) { 4487 init(config); 4488 } 4489 } 4490 4491 function onDocumentReady() { 4492 var elements = document.querySelectorAll(selectors.self); 4493 for (var i = 0; i < elements.length; i++) { 4494 new Image({ element: elements[i], options: readData(elements[i]) }); 4495 } 4496 4497 var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver; 4498 var body = document.querySelector("body"); 4499 var observer = new MutationObserver(function(mutations) { 4500 mutations.forEach(function(mutation) { 4501 // needed for IE 4502 var nodesArray = [].slice.call(mutation.addedNodes); 4503 if (nodesArray.length > 0) { 4504 nodesArray.forEach(function(addedNode) { 4505 if (addedNode.querySelectorAll) { 4506 var elementsArray = [].slice.call(addedNode.querySelectorAll(selectors.self)); 4507 elementsArray.forEach(function(element) { 4508 new Image({ element: element, options: readData(element) }); 4509 }); 4510 } 4511 }); 4512 } 4513 }); 4514 }); 4515 4516 observer.observe(body, { 4517 subtree: true, 4518 childList: true, 4519 characterData: true 4520 }); 4521 } 4522 4523 if (document.readyState !== "loading") { 4524 onDocumentReady(); 4525 } else { 4526 document.addEventListener("DOMContentLoaded", onDocumentReady); 4527 } 4528 4529 /* 4530 on drag & drop of the component into a parsys, noscript's content will be escaped multiple times by the editor which creates 4531 the DOM for editing; the HTML parser cannot be used here due to the multiple escaping 4532 */ 4533 function decodeNoscript(text) { 4534 text = text.replace(/&(amp;)*lt;/g, "<"); 4535 text = text.replace(/&(amp;)*gt;/g, ">"); 4536 return text; 4537 } 4538 4539})(); 4540 4541/******************************************************************************* 4542 * Copyright 2017 Adobe 4543 * 4544 * Licensed under the Apache License, Version 2.0 (the "License");
4545 * you may not use this file except in compliance with the License. 4546 * You may obtain a copy of the License at 4547 * 4548 * http://www.apache.org/licenses/LICENSE-2.0 4549 * 4550 * Unless required by applicable law or agreed to in writing, software 4551 * distributed under the License is distributed on an "AS IS" BASIS, 4552 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 4553 * See the License for the specific language governing permissions and 4554 * limitations under the License. 4555 ******************************************************************************/ 4556if (window.Element && !Element.prototype.closest) { 4557 // eslint valid-jsdoc: "off" 4558 Element.prototype.closest = 4559 function(s) { 4560 "use strict"; 4561 var matches = (this.document || this.ownerDocument).querySelectorAll(s); 4562 var el = this; 4563 var i; 4564 do { 4565 i = matches.length; 4566 while (--i >= 0 && matches.item(i) !== el) { 4567 // continue 4568 } 4569 } while ((i < 0) && (el = el.parentElement)); 4570 return el; 4571 }; 4572} 4573 4574if (window.Element && !Element.prototype.matches) { 4575 Element.prototype.matches = 4576 Element.prototype.matchesSelector || 4577 Element.prototype.mozMatchesSelector || 4578 Element.prototype.msMatchesSelector || 4579 Element.prototype.oMatchesSelector || 4580 Element.prototype.webkitMatchesSelector || 4581 function(s) { 4582 "use strict"; 4583 var matches = (this.document || this.ownerDocument).querySelectorAll(s); 4584 var i = matches.length; 4585 while (--i >= 0 && matches.item(i) !== this) { 4586 // continue 4587 } 4588 return i > -1; 4589 }; 4590} 4591 4592if (!Object.assign) { 4593 Object.assign = function(target, varArgs) { // .length of function is 2 4594 "use strict"; 4595 if (target === null) { 4596 throw new TypeError("Cannot convert undefined or null to object"); 4597 } 4598 4599 var to = Object(target); 4600 4601 for (var index = 1; index < arguments.length; index++) { 4602 var nextSource = arguments[index]; 4603 4604 if (nextSource !== null) { 4605 for (var nextKey in nextSource) { 4606 if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) { 4607 to[nextKey] = nextSource[nextKey]; 4608 } 4609 } 4610 } 4611 } 4612 return to; 4613 }; 4614} 4615 4616(function(arr) { 4617 "use strict"; 4618 arr.forEach(function(item) { 4619 if (Object.prototype.hasOwnProperty.call(item, "remove")) { 4620 return; 4621 } 4622 Object.defineProperty(item, "remove", { 4623 configurable: true, 4624 enumerable: true, 4625 writable: true, 4626 value: function remove() { 4627 this.parentNode.removeChild(this); 4628 } 4629 }); 4630 }); 4631})([Element.prototype, CharacterData.prototype, DocumentType.prototype]); 4632 4633/******************************************************************************* 4634 * Copyright 2016 Adobe 4635 * 4636 * Licensed under the Apache License, Version 2.0 (the "License"); 4637 * you may not use this file except in compliance with the License. 4638 * You may obtain a copy of the License at 4639 * 4640 * http://www.apache.org/licenses/LICENSE-2.0 4641 * 4642 * Unless required by applicable law or agreed to in writing, software 4643 * distributed under the License is distributed on an "AS IS" BASIS, 4644 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 4645 * See the License for the specific language governing permissions and 4646 * limitations under the License. 4647 ******************************************************************************/ 4648(function() { 4649 "use strict"; 4650 4651 var NS = "cmp"; 4652 var IS = "image"; 4653 4654 var EMPTY_PIXEL = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"; 4655 var LAZY_THRESHOLD_DEFAULT = 0; 4656 var SRC_URI_TEMPLATE_WIDTH_VAR = "{.width}"; 4657 var SRC_URI_TEMPLATE_WIDTH_VAR_ASSET_DELIVERY = "width={width}"; 4658 var SRC_URI_TEMPLATE_DPR_VAR = "{dpr}"; 4659 4660 var selectors = { 4661 self: "[data-" + NS + '-is="' + IS + '"]', 4662 image: '[data-cmp-hook-image="image"]', 4663 map: '[data-cmp-hook-image="map"]', 4664 area: '[data-cmp-hook-image="area"]' 4665 }; 4666 4667 var lazyLoader = { 4668 "cssClass": "cmp-image__image--is-loading", 4669 "style": { 4670 "height": 0, 4671 "padding-bottom": "" // will be replaced with % ratio 4672 } 4673 }; 4674 4675 var properties = { 4676 /** 4677 * An array of alternative image widths (in pixels). 4678 * Used to replace a {.width} variable in the src property with an optimal width if a URI template is provided. 4679 * 4680 * @memberof Image 4681 * @type {Number[]} 4682 * @default [] 4683 */ 4684 "widths": { 4685 "default": [], 4686 "transform": function(value) { 4687 var widths = []; 4688 value.split(",").forEach(function(item) { 4689 item = parseFloat(item); 4690 if (!isNaN(item)) { 4691 widths.push(item); 4692 } 4693 }); 4694 return widths; 4695 } 4696 }, 4697 /** 4698 * Indicates whether the image should be rendered lazily. 4699 * 4700 * @memberof Image 4701 * @type {Boolean} 4702 * @default false 4703 */ 4704 "lazy": { 4705 "default": false, 4706 "transform": function(value) { 4707 return !(value === null || typeof value === "undefined"); 4708 } 4709 }, 4710 /** 4711 * Indicates image is DynamicMedia image. 4712 * 4713 * @memberof Image 4714 * @type {Boolean} 4715 * @default false 4716 */ 4717 "dmimage": { 4718 "default": false, 4719 "transform": function(value) { 4720 return !(value === null || typeof value === "undefined"); 4721 } 4722 }, 4723 /** 4724 * The lazy threshold. 4725 * This is the number of pixels, in advance of becoming visible, when an lazy-loading image should begin 4726 * to load. 4727 * 4728 * @memberof Image 4729 * @type {Number} 4730 * @default 0 4731 */ 4732 "lazythreshold": { 4733 "default": 0, 4734 "transform": function(value) { 4735 var val = parseInt(value); 4736 if (isNaN(val)) { 4737 return LAZY_THRESHOLD_DEFAULT; 4738 } 4739 return val; 4740 } 4741 }, 4742 /** 4743 * The image source. 4744 * 4745 * Can be a simple image source, or a URI template representation that 4746 * can be variable expanded - useful for building an image configuration with an alternative width. 4747 * e.g. '/path/image.coreimg{.width}.jpeg/1506620954214.jpeg' 4748 * 4749 * @memberof Image 4750 * @type {String} 4751 */ 4752 "src": { 4753 "transform": function(value) { 4754 return decodeURIComponent(value); 4755 } 4756 } 4757 }; 4758 4759 var devicePixelRatio = window.devicePixelRatio || 1; 4760 4761 function readData(element) { 4762 var data = element.dataset; 4763 var options = []; 4764 var capitalized = IS; 4765 capitalized = capitalized.charAt(0).toUpperCase() + capitalized.slice(1); 4766 var reserved = ["is", "hook" + capitalized]; 4767 4768 for (var key in data) { 4769 if (Object.prototype.hasOwnProperty.call(data, key)) { 4770 var value = data[key]; 4771 4772 if (key.indexOf(NS) === 0) { 4773 key = key.slice(NS.length); 4774 key = key.charAt(0).toLowerCase() + key.substring(1); 4775 4776 if (reserved.indexOf(key) === -1) { 4777 options[key] = value; 4778 } 4779 } 4780 } 4781 } 4782 return options; 4783 } 4784 4785 function Image(config) { 4786 var that = this; 4787 4788 var smartCrops = {}; 4789 4790 var useAssetDelivery = false;
4791 var srcUriTemplateWidthVar = SRC_URI_TEMPLATE_WIDTH_VAR; 4792 4793 function init(config) { 4794 // prevents multiple initialization 4795 config.element.removeAttribute("data-" + NS + "-is"); 4796 4797 // check if asset delivery is used 4798 if (config.options.src && config.options.src.indexOf(SRC_URI_TEMPLATE_WIDTH_VAR_ASSET_DELIVERY) >= 0) { 4799 useAssetDelivery = true; 4800 srcUriTemplateWidthVar = SRC_URI_TEMPLATE_WIDTH_VAR_ASSET_DELIVERY; 4801 } 4802 4803 setupProperties(config.options); 4804 cacheElements(config.element); 4805 // check image is DM asset; if true try to make req=set 4806 if (config.options.src && Object.prototype.hasOwnProperty.call(config.options, "dmimage") && (config.options["smartcroprendition"] === "SmartCrop:Auto")) { 4807 var request = new XMLHttpRequest(); 4808 var urlTemplatePart = decodeURIComponent(config.options.src).split(srcUriTemplateWidthVar)[0]; 4809 var url = urlTemplatePart + (urlTemplatePart.indexOf("?") < 0 ? "?" : "") + "req=set,json"; 4810 4811 request.open("GET", url, false); 4812 request.onload = function() { 4813 if (request.status >= 200 && request.status < 400) { 4814 // success status 4815 var responseText = request.responseText; 4816 var rePayload = new RegExp(/^(?:\/\*jsonp\*\/)?\s*([^()]+)\(([\s\S]+),\s*"[0-9]*"\);?$/gmi); 4817 var rePayloadJSON = new RegExp(/^{[\s\S]*}$/gmi); 4818 var resPayload = rePayload.exec(responseText); 4819 var payload; 4820 if (resPayload) { 4821 var payloadStr = resPayload[2]; 4822 if (rePayloadJSON.test(payloadStr)) { 4823 payload = JSON.parse(payloadStr); 4824 } 4825 4826 } 4827 // check "relation" - only in case of smartcrop preset 4828 if (payload && payload.set.relation && payload.set.relation.length > 0) { 4829 for (var i = 0; i < payload.set.relation.length; i++) { 4830 smartCrops[parseInt(payload.set.relation[i].userdata.SmartCropWidth)] = 4831 ":" + payload.set.relation[i].userdata.SmartCropDef; 4832 } 4833 } 4834 } else { 4835 // error status 4836 } 4837 }; 4838 request.send(); 4839 } 4840 4841 if (!that._elements.noscript) { 4842 return; 4843 } 4844 4845 that._elements.container = that._elements.link ? that._elements.link : that._elements.self; 4846 4847 unwrapNoScript(); 4848 4849 if (that._properties.lazy) { 4850 addLazyLoader(); 4851 } 4852 4853 if (that._elements.map) { 4854 that._elements.image.addEventListener("load", onLoad); 4855 } 4856 4857 window.addEventListener("resize", onWindowResize); 4858 ["focus", "click", "load", "transitionend", "animationend", "scroll"].forEach(function(name) { 4859 document.addEventListener(name, that.update); 4860 }); 4861 4862 that._elements.image.addEventListener("cmp-image-redraw", that.update); 4863 that.update(); 4864 } 4865 4866 function loadImage() { 4867 var hasWidths = (that._properties.widths && that._properties.widths.length > 0) || Object.keys(smartCrops).length > 0; 4868 var replacement; 4869 if (Object.keys(smartCrops).length > 0) { 4870 var optimalWidth = getOptimalWidth(Object.keys(smartCrops), false); 4871 replacement = smartCrops[optimalWidth]; 4872 } else { 4873 replacement = hasWidths ? (that._properties.dmimage ? "" : ".") + getOptimalWidth(that._properties.widths, true) : ""; 4874 } 4875 if (useAssetDelivery) {
4876 replacement = replacement !== "" ? ("width=" + replacement.substring(1)) : ""; 4877 } 4878 var url = that._properties.src.replace(srcUriTemplateWidthVar, replacement); 4879 url = url.replace(SRC_URI_TEMPLATE_DPR_VAR, devicePixelRatio); 4880 4881 var imgSrcAttribute = that._elements.image.getAttribute("src"); 4882 4883 if (url !== imgSrcAttribute) { 4884 if (imgSrcAttribute === null || imgSrcAttribute === EMPTY_PIXEL) { 4885 that._elements.image.setAttribute("src", url); 4886 } else { 4887 var urlTemplateParts = that._properties.src.split(srcUriTemplateWidthVar); 4888 // check if image src was dynamically swapped meanwhile (e.g. by Target) 4889 var isImageRefSame = imgSrcAttribute.startsWith(urlTemplateParts[0]); 4890 if (isImageRefSame && urlTemplateParts.length > 1) { 4891 isImageRefSame = imgSrcAttribute.endsWith(urlTemplateParts[urlTemplateParts.length - 1]); 4892 } 4893 if (isImageRefSame) { 4894 that._elements.image.setAttribute("src", url); 4895 if (!hasWidths) { 4896 window.removeEventListener("scroll", that.update); 4897 } 4898 } 4899 } 4900 } 4901 if (that._lazyLoaderShowing) { 4902 that._elements.image.addEventListener("load", removeLazyLoader); 4903 } 4904 } 4905 4906 function getOptimalWidth(widths, useDevicePixelRatio) { 4907 var container = that._elements.self; 4908 var containerWidth = container.clientWidth; 4909 while (containerWidth === 0 && container.parentNode) { 4910 container = container.parentNode; 4911 containerWidth = container.clientWidth; 4912 } 4913 4914 var dpr = useDevicePixelRatio ? devicePixelRatio : 1; 4915 var optimalWidth = containerWidth * dpr; 4916 var len = widths.length; 4917 var key = 0; 4918 4919 while ((key < len - 1) && (widths[key] < optimalWidth)) { 4920 key++; 4921 } 4922 4923 return widths[key].toString(); 4924 } 4925 4926 function addLazyLoader() { 4927 var width = that._elements.image.getAttribute("width"); 4928 var height = that._elements.image.getAttribute("height"); 4929 4930 if (width && height) { 4931 var ratio = (height / width) * 100; 4932 var styles = lazyLoader.style; 4933 4934 styles["padding-bottom"] = ratio + "%"; 4935 4936 for (var s in styles) { 4937 if (Object.prototype.hasOwnProperty.call(styles, s)) { 4938 that._elements.image.style[s] = styles[s]; 4939 } 4940 } 4941 } 4942 that._elements.image.setAttribute("src", EMPTY_PIXEL); 4943 that._elements.image.classList.add(lazyLoader.cssClass); 4944 that._lazyLoaderShowing = true; 4945 } 4946 4947 function unwrapNoScript() { 4948 var markup = decodeNoscript(that._elements.noscript.textContent.trim()); 4949 var parser = new DOMParser(); 4950 4951 // temporary document avoids requesting the image before removing its src 4952 var temporaryDocument = parser.parseFromString(markup, "text/html"); 4953 var imageElement = temporaryDocument.querySelector(selectors.image); 4954 imageElement.removeAttribute("src"); 4955 that._elements.container.insertBefore(imageElement, that._elements.noscript); 4956 4957 var mapElement = temporaryDocument.querySelector(selectors.map); 4958 if (mapElement) { 4959 that._elements.container.insertBefore(mapElement, that._elements.noscript); 4960 } 4961 4962 that._elements.noscript.parentNode.removeChild(that._elements.noscript); 4963 if (that._elements.container.matches(selectors.image)) { 4964 that._elements.image = that._elements.container; 4965 } else { 4966 that._elements.image = that._elements.container.querySelector(selectors.image); 4967 } 4968 4969 that._elements.map = that._elements.container.querySelector(selectors.map); 4970 that._elements.areas = that._elements.container.querySelectorAll(selectors.area); 4971 } 4972 4973 function removeLazyLoader() { 4974 that._elements.image.classList.remove(lazyLoader.cssClass); 4975 for (var property in lazyLoader.style) { 4976 if (Object.prototype.hasOwnProperty.call(lazyLoader.style, property)) { 4977 that._elements.image.style[property] = ""; 4978 } 4979 } 4980 that._elements.image.removeEventListener("load", removeLazyLoader); 4981 that._lazyLoaderShowing = false;
4982 } 4983 4984 function isLazyVisible() { 4985 if (that._elements.container.offsetParent === null) { 4986 return false; 4987 } 4988 4989 var wt = window.pageYOffset; 4990 var wb = wt + document.documentElement.clientHeight; 4991 var et = that._elements.container.getBoundingClientRect().top + wt; 4992 var eb = et + that._elements.container.clientHeight; 4993 4994 return eb >= wt - that._properties.lazythreshold && et <= wb + that._properties.lazythreshold; 4995 } 4996 4997 function resizeAreas() { 4998 if (that._elements.areas && that._elements.areas.length > 0) { 4999 for (var i = 0; i < that._elements.areas.length; i++) { 5000 var width = that._elements.image.width; 5001 var height = that._elements.image.height; 5002 5003 if (width && height) { 5004 var relcoords = that._elements.areas[i].dataset.cmpRelcoords; 5005 if (relcoords) { 5006 var relativeCoordinates = relcoords.split(","); 5007 var coordinates = new Array(relativeCoordinates.length); 5008 5009 for (var j = 0; j < coordinates.length; j++) { 5010 if (j % 2 === 0) { 5011 coordinates[j] = parseInt(relativeCoordinates[j] * width); 5012 } else { 5013 coordinates[j] = parseInt(relativeCoordinates[j] * height); 5014 } 5015 } 5016 5017 that._elements.areas[i].coords = coordinates; 5018 } 5019 } 5020 } 5021 } 5022 } 5023 5024 function cacheElements(wrapper) { 5025 that._elements = {}; 5026 that._elements.self = wrapper; 5027 var hooks = that._elements.self.querySelectorAll("[data-" + NS + "-hook-" + IS + "]"); 5028 5029 for (var i = 0; i < hooks.length; i++) { 5030 var hook = hooks[i]; 5031 var capitalized = IS; 5032 capitalized = capitalized.charAt(0).toUpperCase() + capitalized.slice(1); 5033 var key = hook.dataset[NS + "Hook" + capitalized]; 5034 that._elements[key] = hook; 5035 } 5036 } 5037 5038 function setupProperties(options) { 5039 that._properties = {}; 5040 5041 for (var key in properties) { 5042 if (Object.prototype.hasOwnProperty.call(properties, key)) { 5043 var property = properties[key]; 5044 if (options && options[key] != null) { 5045 if (property && typeof property.transform === "function") { 5046 that._properties[key] = property.transform(options[key]); 5047 } else { 5048 that._properties[key] = options[key]; 5049 } 5050 } else { 5051 that._properties[key] = properties[key]["default"]; 5052 } 5053 } 5054 } 5055 } 5056 5057 function onWindowResize() { 5058 that.update(); 5059 resizeAreas(); 5060 } 5061 5062 function onLoad() { 5063 resizeAreas(); 5064 } 5065 5066 that.update = function() { 5067 if (that._properties.lazy) { 5068 if (isLazyVisible()) { 5069 loadImage(); 5070 } 5071 } else { 5072 loadImage(); 5073 } 5074 }; 5075 5076 if (config && config.element) { 5077 init(config); 5078 } 5079 } 5080 5081 function onDocumentReady() { 5082 var elements = document.querySelectorAll(selectors.self); 5083 for (var i = 0; i < elements.length; i++) { 5084 new Image({ element: elements[i], options: readData(elements[i]) }); 5085 } 5086 5087 var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver; 5088 var body = document.querySelector("body"); 5089 var observer = new MutationObserver(function(mutations) { 5090 mutations.forEach(function(mutation) { 5091 // needed for IE 5092 var nodesArray = [].slice.call(mutation.addedNodes); 5093 if (nodesArray.length > 0) { 5094 nodesArray.forEach(function(addedNode) { 5095 if (addedNode.querySelectorAll) { 5096 var elementsArray = [].slice.call(addedNode.querySelectorAll(selectors.self)); 5097 elementsArray.forEach(function(element) { 5098 new Image({ element: element, options: readData(element) }); 5099 }); 5100 } 5101 }); 5102 } 5103 }); 5104 }); 5105 5106 observer.observe(body, { 5107 subtree: true, 5108 childList: true, 5109 characterData: true 5110 }); 5111 } 5112 5113 if (document.readyState !== "loading") { 5114 onDocumentReady(); 5115 } else { 5116 document.addEventListener("DOMContentLoaded", onDocumentReady); 5117 } 5118 5119 /* 5120 on drag & drop of the component into a parsys, noscript's content will be escaped multiple times by the editor which creates 5121 the DOM for editing; the HTML parser cannot be used here due to the multiple escaping 5122 */ 5123 function decodeNoscript(text) { 5124 text = text.replace(/&(amp;)*lt;/g, "<"); 5125 text = text.replace(/&(amp;)*gt;/g, ">"); 5126 return text; 5127 } 5128 5129})(); 5130 5131/******************************************************************************* 5132 * Copyright 2017 Adobe 5133 * 5134 * Licensed under the Apache License, Version 2.0 (the "License");
5135 * you may not use this file except in compliance with the License. 5136 * You may obtain a copy of the License at 5137 * 5138 * http://www.apache.org/licenses/LICENSE-2.0 5139 * 5140 * Unless required by applicable law or agreed to in writing, software 5141 * distributed under the License is distributed on an "AS IS" BASIS, 5142 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 5143 * See the License for the specific language governing permissions and 5144 * limitations under the License. 5145 ******************************************************************************/ 5146if (window.Element && !Element.prototype.closest) { 5147 // eslint valid-jsdoc: "off" 5148 Element.prototype.closest = 5149 function(s) { 5150 "use strict"; 5151 var matches = (this.document || this.ownerDocument).querySelectorAll(s); 5152 var el = this; 5153 var i; 5154 do { 5155 i = matches.length; 5156 while (--i >= 0 && matches.item(i) !== el) { 5157 // continue 5158 } 5159 } while ((i < 0) && (el = el.parentElement)); 5160 return el; 5161 }; 5162} 5163 5164if (window.Element && !Element.prototype.matches) { 5165 Element.prototype.matches = 5166 Element.prototype.matchesSelector || 5167 Element.prototype.mozMatchesSelector || 5168 Element.prototype.msMatchesSelector || 5169 Element.prototype.oMatchesSelector || 5170 Element.prototype.webkitMatchesSelector || 5171 function(s) { 5172 "use strict"; 5173 var matches = (this.document || this.ownerDocument).querySelectorAll(s); 5174 var i = matches.length; 5175 while (--i >= 0 && matches.item(i) !== this) { 5176 // continue 5177 } 5178 return i > -1; 5179 }; 5180} 5181 5182if (!Object.assign) { 5183 Object.assign = function(target, varArgs) { // .length of function is 2 5184 "use strict"; 5185 if (target === null) { 5186 throw new TypeError("Cannot convert undefined or null to object"); 5187 } 5188 5189 var to = Object(target); 5190 5191 for (var index = 1; index < arguments.length; index++) { 5192 var nextSource = arguments[index]; 5193 5194 if (nextSource !== null) { 5195 for (var nextKey in nextSource) { 5196 if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) { 5197 to[nextKey] = nextSource[nextKey]; 5198 } 5199 } 5200 } 5201 } 5202 return to; 5203 }; 5204} 5205 5206(function(arr) { 5207 "use strict"; 5208 arr.forEach(function(item) { 5209 if (Object.prototype.hasOwnProperty.call(item, "remove")) { 5210 return; 5211 } 5212 Object.defineProperty(item, "remove", { 5213 configurable: true, 5214 enumerable: true, 5215 writable: true, 5216 value: function remove() { 5217 this.parentNode.removeChild(this); 5218 } 5219 }); 5220 }); 5221})([Element.prototype, CharacterData.prototype, DocumentType.prototype]); 5222 5223/******************************************************************************* 5224 * Copyright 2016 Adobe 5225 * 5226 * Licensed under the Apache License, Version 2.0 (the "License"); 5227 * you may not use this file except in compliance with the License. 5228 * You may obtain a copy of the License at 5229 * 5230 * http://www.apache.org/licenses/LICENSE-2.0 5231 * 5232 * Unless required by applicable law or agreed to in writing, software 5233 * distributed under the License is distributed on an "AS IS" BASIS, 5234 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 5235 * See the License for the specific language governing permissions and 5236 * limitations under the License. 5237 ******************************************************************************/ 5238(function() { 5239 "use strict"; 5240 5241 var NS = "cmp"; 5242 var IS = "image"; 5243 5244 var EMPTY_PIXEL = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"; 5245 var LAZY_THRESHOLD_DEFAULT = 0; 5246 var SRC_URI_TEMPLATE_WIDTH_VAR = "{.width}"; 5247 var SRC_URI_TEMPLATE_WIDTH_VAR_ASSET_DELIVERY = "width={width}"; 5248 var SRC_URI_TEMPLATE_DPR_VAR = "{dpr}"; 5249 5250 var selectors = { 5251 self: "[data-" + NS + '-is="' + IS + '"]', 5252 image: '[data-cmp-hook-image="image"]', 5253 map: '[data-cmp-hook-image="map"]', 5254 area: '[data-cmp-hook-image="area"]' 5255 }; 5256 5257 var lazyLoader = { 5258 "cssClass": "cmp-image__image--is-loading", 5259 "style": { 5260 "height": 0, 5261 "padding-bottom": "" // will be replaced with % ratio 5262 } 5263 }; 5264 5265 var properties = { 5266 /** 5267 * An array of alternative image widths (in pixels). 5268 * Used to replace a {.width} variable in the src property with an optimal width if a URI template is provided. 5269 * 5270 * @memberof Image 5271 * @type {Number[]} 5272 * @default [] 5273 */ 5274 "widths": { 5275 "default": [], 5276 "transform": function(value) { 5277 var widths = []; 5278 value.split(",").forEach(function(item) { 5279 item = parseFloat(item); 5280 if (!isNaN(item)) { 5281 widths.push(item); 5282 } 5283 }); 5284 return widths; 5285 } 5286 }, 5287 /** 5288 * Indicates whether the image should be rendered lazily. 5289 * 5290 * @memberof Image 5291 * @type {Boolean} 5292 * @default false 5293 */ 5294 "lazy": { 5295 "default": false, 5296 "transform": function(value) { 5297 return !(value === null || typeof value === "undefined"); 5298 } 5299 }, 5300 /** 5301 * Indicates image is DynamicMedia image. 5302 * 5303 * @memberof Image 5304 * @type {Boolean} 5305 * @default false 5306 */ 5307 "dmimage": { 5308 "default": false, 5309 "transform": function(value) { 5310 return !(value === null || typeof value === "undefined"); 5311 } 5312 }, 5313 /** 5314 * The lazy threshold. 5315 * This is the number of pixels, in advance of becoming visible, when an lazy-loading image should begin 5316 * to load. 5317 * 5318 * @memberof Image 5319 * @type {Number} 5320 * @default 0 5321 */ 5322 "lazythreshold": { 5323 "default": 0, 5324 "transform": function(value) { 5325 var val = parseInt(value); 5326 if (isNaN(val)) { 5327 return LAZY_THRESHOLD_DEFAULT; 5328 } 5329 return val; 5330 } 5331 }, 5332 /** 5333 * The image source. 5334 * 5335 * Can be a simple image source, or a URI template representation that 5336 * can be variable expanded - useful for building an image configuration with an alternative width. 5337 * e.g. '/path/image.coreimg{.width}.jpeg/1506620954214.jpeg' 5338 * 5339 * @memberof Image 5340 * @type {String} 5341 */ 5342 "src": { 5343 "transform": function(value) { 5344 return decodeURIComponent(value); 5345 } 5346 } 5347 }; 5348 5349 var devicePixelRatio = window.devicePixelRatio || 1; 5350 5351 function readData(element) { 5352 var data = element.dataset; 5353 var options = []; 5354 var capitalized = IS; 5355 capitalized = capitalized.charAt(0).toUpperCase() + capitalized.slice(1); 5356 var reserved = ["is", "hook" + capitalized]; 5357 5358 for (var key in data) { 5359 if (Object.prototype.hasOwnProperty.call(data, key)) { 5360 var value = data[key]; 5361 5362 if (key.indexOf(NS) === 0) { 5363 key = key.slice(NS.length); 5364 key = key.charAt(0).toLowerCase() + key.substring(1); 5365 5366 if (reserved.indexOf(key) === -1) { 5367 options[key] = value; 5368 } 5369 } 5370 } 5371 } 5372 return options; 5373 } 5374 5375 function Image(config) { 5376 var that = this; 5377 5378 var smartCrops = {}; 5379 5380 var useAssetDelivery = false;
5381 var srcUriTemplateWidthVar = SRC_URI_TEMPLATE_WIDTH_VAR; 5382 5383 function init(config) { 5384 // prevents multiple initialization 5385 config.element.removeAttribute("data-" + NS + "-is"); 5386 5387 // check if asset delivery is used 5388 if (config.options.src && config.options.src.indexOf(SRC_URI_TEMPLATE_WIDTH_VAR_ASSET_DELIVERY) >= 0) { 5389 useAssetDelivery = true; 5390 srcUriTemplateWidthVar = SRC_URI_TEMPLATE_WIDTH_VAR_ASSET_DELIVERY; 5391 } 5392 5393 setupProperties(config.options); 5394 cacheElements(config.element); 5395 // check image is DM asset; if true try to make req=set 5396 if (config.options.src && Object.prototype.hasOwnProperty.call(config.options, "dmimage") && (config.options["smartcroprendition"] === "SmartCrop:Auto")) { 5397 var request = new XMLHttpRequest(); 5398 var urlTemplatePart = decodeURIComponent(config.options.src).split(srcUriTemplateWidthVar)[0]; 5399 var url = urlTemplatePart + (urlTemplatePart.indexOf("?") < 0 ? "?" : "") + "req=set,json"; 5400 5401 request.open("GET", url, false); 5402 request.onload = function() { 5403 if (request.status >= 200 && request.status < 400) { 5404 // success status 5405 var responseText = request.responseText; 5406 var rePayload = new RegExp(/^(?:\/\*jsonp\*\/)?\s*([^()]+)\(([\s\S]+),\s*"[0-9]*"\);?$/gmi); 5407 var rePayloadJSON = new RegExp(/^{[\s\S]*}$/gmi); 5408 var resPayload = rePayload.exec(responseText); 5409 var payload; 5410 if (resPayload) { 5411 var payloadStr = resPayload[2]; 5412 if (rePayloadJSON.test(payloadStr)) { 5413 payload = JSON.parse(payloadStr); 5414 } 5415 5416 } 5417 // check "relation" - only in case of smartcrop preset 5418 if (payload && payload.set.relation && payload.set.relation.length > 0) { 5419 for (var i = 0; i < payload.set.relation.length; i++) { 5420 smartCrops[parseInt(payload.set.relation[i].userdata.SmartCropWidth)] = 5421 ":" + payload.set.relation[i].userdata.SmartCropDef; 5422 } 5423 } 5424 } else { 5425 // error status 5426 } 5427 }; 5428 request.send(); 5429 } 5430 5431 if (!that._elements.noscript) { 5432 return; 5433 } 5434 5435 that._elements.container = that._elements.link ? that._elements.link : that._elements.self; 5436 5437 unwrapNoScript(); 5438 5439 if (that._properties.lazy) { 5440 addLazyLoader(); 5441 } 5442 5443 if (that._elements.map) { 5444 that._elements.image.addEventListener("load", onLoad); 5445 } 5446 5447 window.addEventListener("resize", onWindowResize); 5448 ["focus", "click", "load", "transitionend", "animationend", "scroll"].forEach(function(name) { 5449 document.addEventListener(name, that.update); 5450 }); 5451 5452 that._elements.image.addEventListener("cmp-image-redraw", that.update); 5453 that.update(); 5454 } 5455 5456 function loadImage() { 5457 var hasWidths = (that._properties.widths && that._properties.widths.length > 0) || Object.keys(smartCrops).length > 0; 5458 var replacement; 5459 if (Object.keys(smartCrops).length > 0) { 5460 var optimalWidth = getOptimalWidth(Object.keys(smartCrops), false); 5461 replacement = smartCrops[optimalWidth]; 5462 } else { 5463 replacement = hasWidths ? (that._properties.dmimage ? "" : ".") + getOptimalWidth(that._properties.widths, true) : ""; 5464 } 5465 if (useAssetDelivery) {
5466 replacement = replacement !== "" ? ("width=" + replacement.substring(1)) : ""; 5467 } 5468 var url = that._properties.src.replace(srcUriTemplateWidthVar, replacement); 5469 url = url.replace(SRC_URI_TEMPLATE_DPR_VAR, devicePixelRatio); 5470 5471 var imgSrcAttribute = that._elements.image.getAttribute("src"); 5472 5473 if (url !== imgSrcAttribute) { 5474 if (imgSrcAttribute === null || imgSrcAttribute === EMPTY_PIXEL) { 5475 that._elements.image.setAttribute("src", url); 5476 } else { 5477 var urlTemplateParts = that._properties.src.split(srcUriTemplateWidthVar); 5478 // check if image src was dynamically swapped meanwhile (e.g. by Target) 5479 var isImageRefSame = imgSrcAttribute.startsWith(urlTemplateParts[0]); 5480 if (isImageRefSame && urlTemplateParts.length > 1) { 5481 isImageRefSame = imgSrcAttribute.endsWith(urlTemplateParts[urlTemplateParts.length - 1]); 5482 } 5483 if (isImageRefSame) { 5484 that._elements.image.setAttribute("src", url); 5485 if (!hasWidths) { 5486 window.removeEventListener("scroll", that.update); 5487 } 5488 } 5489 } 5490 } 5491 if (that._lazyLoaderShowing) { 5492 that._elements.image.addEventListener("load", removeLazyLoader); 5493 } 5494 } 5495 5496 function getOptimalWidth(widths, useDevicePixelRatio) { 5497 var container = that._elements.self; 5498 var containerWidth = container.clientWidth; 5499 while (containerWidth === 0 && container.parentNode) { 5500 container = container.parentNode; 5501 containerWidth = container.clientWidth; 5502 } 5503 5504 var dpr = useDevicePixelRatio ? devicePixelRatio : 1; 5505 var optimalWidth = containerWidth * dpr; 5506 var len = widths.length; 5507 var key = 0; 5508 5509 while ((key < len - 1) && (widths[key] < optimalWidth)) { 5510 key++; 5511 } 5512 5513 return widths[key].toString(); 5514 } 5515 5516 function addLazyLoader() { 5517 var width = that._elements.image.getAttribute("width"); 5518 var height = that._elements.image.getAttribute("height"); 5519 5520 if (width && height) { 5521 var ratio = (height / width) * 100; 5522 var styles = lazyLoader.style; 5523 5524 styles["padding-bottom"] = ratio + "%"; 5525 5526 for (var s in styles) { 5527 if (Object.prototype.hasOwnProperty.call(styles, s)) { 5528 that._elements.image.style[s] = styles[s]; 5529 } 5530 } 5531 } 5532 that._elements.image.setAttribute("src", EMPTY_PIXEL); 5533 that._elements.image.classList.add(lazyLoader.cssClass); 5534 that._lazyLoaderShowing = true; 5535 } 5536 5537 function unwrapNoScript() { 5538 var markup = decodeNoscript(that._elements.noscript.textContent.trim()); 5539 var parser = new DOMParser(); 5540 5541 // temporary document avoids requesting the image before removing its src 5542 var temporaryDocument = parser.parseFromString(markup, "text/html"); 5543 var imageElement = temporaryDocument.querySelector(selectors.image); 5544 imageElement.removeAttribute("src"); 5545 that._elements.container.insertBefore(imageElement, that._elements.noscript); 5546 5547 var mapElement = temporaryDocument.querySelector(selectors.map); 5548 if (mapElement) { 5549 that._elements.container.insertBefore(mapElement, that._elements.noscript); 5550 } 5551 5552 that._elements.noscript.parentNode.removeChild(that._elements.noscript); 5553 if (that._elements.container.matches(selectors.image)) { 5554 that._elements.image = that._elements.container; 5555 } else { 5556 that._elements.image = that._elements.container.querySelector(selectors.image); 5557 } 5558 5559 that._elements.map = that._elements.container.querySelector(selectors.map); 5560 that._elements.areas = that._elements.container.querySelectorAll(selectors.area); 5561 } 5562 5563 function removeLazyLoader() { 5564 that._elements.image.classList.remove(lazyLoader.cssClass); 5565 for (var property in lazyLoader.style) { 5566 if (Object.prototype.hasOwnProperty.call(lazyLoader.style, property)) { 5567 that._elements.image.style[property] = ""; 5568 } 5569 } 5570 that._elements.image.removeEventListener("load", removeLazyLoader); 5571 that._lazyLoaderShowing = false;
5572 } 5573 5574 function isLazyVisible() { 5575 if (that._elements.container.offsetParent === null) { 5576 return false; 5577 } 5578 5579 var wt = window.pageYOffset; 5580 var wb = wt + document.documentElement.clientHeight; 5581 var et = that._elements.container.getBoundingClientRect().top + wt; 5582 var eb = et + that._elements.container.clientHeight; 5583 5584 return eb >= wt - that._properties.lazythreshold && et <= wb + that._properties.lazythreshold; 5585 } 5586 5587 function resizeAreas() { 5588 if (that._elements.areas && that._elements.areas.length > 0) { 5589 for (var i = 0; i < that._elements.areas.length; i++) { 5590 var width = that._elements.image.width; 5591 var height = that._elements.image.height; 5592 5593 if (width && height) { 5594 var relcoords = that._elements.areas[i].dataset.cmpRelcoords; 5595 if (relcoords) { 5596 var relativeCoordinates = relcoords.split(","); 5597 var coordinates = new Array(relativeCoordinates.length); 5598 5599 for (var j = 0; j < coordinates.length; j++) { 5600 if (j % 2 === 0) { 5601 coordinates[j] = parseInt(relativeCoordinates[j] * width); 5602 } else { 5603 coordinates[j] = parseInt(relativeCoordinates[j] * height); 5604 } 5605 } 5606 5607 that._elements.areas[i].coords = coordinates; 5608 } 5609 } 5610 } 5611 } 5612 } 5613 5614 function cacheElements(wrapper) { 5615 that._elements = {}; 5616 that._elements.self = wrapper; 5617 var hooks = that._elements.self.querySelectorAll("[data-" + NS + "-hook-" + IS + "]"); 5618 5619 for (var i = 0; i < hooks.length; i++) { 5620 var hook = hooks[i]; 5621 var capitalized = IS; 5622 capitalized = capitalized.charAt(0).toUpperCase() + capitalized.slice(1); 5623 var key = hook.dataset[NS + "Hook" + capitalized]; 5624 that._elements[key] = hook; 5625 } 5626 } 5627 5628 function setupProperties(options) { 5629 that._properties = {}; 5630 5631 for (var key in properties) { 5632 if (Object.prototype.hasOwnProperty.call(properties, key)) { 5633 var property = properties[key]; 5634 if (options && options[key] != null) { 5635 if (property && typeof property.transform === "function") { 5636 that._properties[key] = property.transform(options[key]); 5637 } else { 5638 that._properties[key] = options[key]; 5639 } 5640 } else { 5641 that._properties[key] = properties[key]["default"]; 5642 } 5643 } 5644 } 5645 } 5646 5647 function onWindowResize() { 5648 that.update(); 5649 resizeAreas(); 5650 } 5651 5652 function onLoad() { 5653 resizeAreas(); 5654 } 5655 5656 that.update = function() { 5657 if (that._properties.lazy) { 5658 if (isLazyVisible()) { 5659 loadImage(); 5660 } 5661 } else { 5662 loadImage(); 5663 } 5664 }; 5665 5666 if (config && config.element) { 5667 init(config); 5668 } 5669 } 5670 5671 function onDocumentReady() { 5672 var elements = document.querySelectorAll(selectors.self); 5673 for (var i = 0; i < elements.length; i++) { 5674 new Image({ element: elements[i], options: readData(elements[i]) }); 5675 } 5676 5677 var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver; 5678 var body = document.querySelector("body"); 5679 var observer = new MutationObserver(function(mutations) { 5680 mutations.forEach(function(mutation) { 5681 // needed for IE 5682 var nodesArray = [].slice.call(mutation.addedNodes); 5683 if (nodesArray.length > 0) { 5684 nodesArray.forEach(function(addedNode) { 5685 if (addedNode.querySelectorAll) { 5686 var elementsArray = [].slice.call(addedNode.querySelectorAll(selectors.self)); 5687 elementsArray.forEach(function(element) { 5688 new Image({ element: element, options: readData(element) }); 5689 }); 5690 } 5691 }); 5692 } 5693 }); 5694 }); 5695 5696 observer.observe(body, { 5697 subtree: true, 5698 childList: true, 5699 characterData: true 5700 }); 5701 } 5702 5703 if (document.readyState !== "loading") { 5704 onDocumentReady(); 5705 } else { 5706 document.addEventListener("DOMContentLoaded", onDocumentReady); 5707 } 5708 5709 /* 5710 on drag & drop of the component into a parsys, noscript's content will be escaped multiple times by the editor which creates 5711 the DOM for editing; the HTML parser cannot be used here due to the multiple escaping 5712 */ 5713 function decodeNoscript(text) { 5714 text = text.replace(/&(amp;)*lt;/g, "<"); 5715 text = text.replace(/&(amp;)*gt;/g, ">"); 5716 return text; 5717 } 5718 5719})(); 5720 5721/******************************************************************************* 5722 * Copyright 2017 Adobe 5723 * 5724 * Licensed under the Apache License, Version 2.0 (the "License");
5725 * you may not use this file except in compliance with the License. 5726 * You may obtain a copy of the License at 5727 * 5728 * http://www.apache.org/licenses/LICENSE-2.0 5729 * 5730 * Unless required by applicable law or agreed to in writing, software 5731 * distributed under the License is distributed on an "AS IS" BASIS, 5732 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 5733 * See the License for the specific language governing permissions and 5734 * limitations under the License. 5735 ******************************************************************************/ 5736if (window.Element && !Element.prototype.closest) { 5737 // eslint valid-jsdoc: "off" 5738 Element.prototype.closest = 5739 function(s) { 5740 "use strict"; 5741 var matches = (this.document || this.ownerDocument).querySelectorAll(s); 5742 var el = this; 5743 var i; 5744 do { 5745 i = matches.length; 5746 while (--i >= 0 && matches.item(i) !== el) { 5747 // continue 5748 } 5749 } while ((i < 0) && (el = el.parentElement)); 5750 return el; 5751 }; 5752} 5753 5754if (window.Element && !Element.prototype.matches) { 5755 Element.prototype.matches = 5756 Element.prototype.matchesSelector || 5757 Element.prototype.mozMatchesSelector || 5758 Element.prototype.msMatchesSelector || 5759 Element.prototype.oMatchesSelector || 5760 Element.prototype.webkitMatchesSelector || 5761 function(s) { 5762 "use strict"; 5763 var matches = (this.document || this.ownerDocument).querySelectorAll(s); 5764 var i = matches.length; 5765 while (--i >= 0 && matches.item(i) !== this) { 5766 // continue 5767 } 5768 return i > -1; 5769 }; 5770} 5771 5772if (!Object.assign) { 5773 Object.assign = function(target, varArgs) { // .length of function is 2 5774 "use strict"; 5775 if (target === null) { 5776 throw new TypeError("Cannot convert undefined or null to object"); 5777 } 5778 5779 var to = Object(target); 5780 5781 for (var index = 1; index < arguments.length; index++) { 5782 var nextSource = arguments[index]; 5783 5784 if (nextSource !== null) { 5785 for (var nextKey in nextSource) { 5786 if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) { 5787 to[nextKey] = nextSource[nextKey]; 5788 } 5789 } 5790 } 5791 } 5792 return to; 5793 }; 5794} 5795 5796(function(arr) { 5797 "use strict"; 5798 arr.forEach(function(item) { 5799 if (Object.prototype.hasOwnProperty.call(item, "remove")) { 5800 return; 5801 } 5802 Object.defineProperty(item, "remove", { 5803 configurable: true, 5804 enumerable: true, 5805 writable: true, 5806 value: function remove() { 5807 this.parentNode.removeChild(this); 5808 } 5809 }); 5810 }); 5811})([Element.prototype, CharacterData.prototype, DocumentType.prototype]); 5812 5813/******************************************************************************* 5814 * Copyright 2016 Adobe 5815 * 5816 * Licensed under the Apache License, Version 2.0 (the "License"); 5817 * you may not use this file except in compliance with the License. 5818 * You may obtain a copy of the License at 5819 * 5820 * http://www.apache.org/licenses/LICENSE-2.0 5821 * 5822 * Unless required by applicable law or agreed to in writing, software 5823 * distributed under the License is distributed on an "AS IS" BASIS, 5824 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 5825 * See the License for the specific language governing permissions and 5826 * limitations under the License. 5827 ******************************************************************************/ 5828(function() { 5829 "use strict"; 5830 5831 var NS = "cmp"; 5832 var IS = "image"; 5833 var EMPTY_PIXEL = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"; 5834 var LAZY_THRESHOLD_DEFAULT = 0; 5835 var SRC_URI_TEMPLATE_WIDTH_VAR = "{.width}"; 5836 var SRC_URI_TEMPLATE_WIDTH_VAR_ASSET_DELIVERY = "width={width}"; 5837 var SRC_URI_TEMPLATE_DPR_VAR = "{dpr}"; 5838 5839 var selectors = { 5840// self: "[data-" + NS + '-is="' + IS + '"]', 5841 self: '[data-test-primary="image"]', 5842 image: '[data-cmp-hook-image="image"]', 5843 map: '[data-cmp-hook-image="map"]', 5844 area: '[data-cmp-hook-image="area"]' 5845 }; 5846 5847 var lazyLoader = { 5848 "cssClass": "cmp-image__image--is-loading", 5849 "style": { 5850 "height": 0, 5851 "padding-bottom": "" // will be replaced with % ratio 5852 } 5853 }; 5854 5855 var properties = { 5856 /** 5857 * An array of alternative image widths (in pixels). 5858 * Used to replace a {.width} variable in the src property with an optimal width if a URI template is provided. 5859 * 5860 * @memberof Image 5861 * @type {Number[]} 5862 * @default [] 5863 */ 5864 "widths": { 5865 "default": [], 5866 "transform": function(value) { 5867 var widths = []; 5868 value.split(",").forEach(function(item) { 5869 item = parseFloat(item); 5870 if (!isNaN(item)) { 5871 widths.push(item); 5872 } 5873 }); 5874 return widths; 5875 } 5876 }, 5877 /** 5878 * Indicates whether the image should be rendered lazily. 5879 * 5880 * @memberof Image 5881 * @type {Boolean} 5882 * @default false 5883 */ 5884 "lazy": { 5885 "default": false, 5886 "transform": function(value) { 5887 return !(value === null || typeof value === "undefined"); 5888 } 5889 }, 5890 /** 5891 * Indicates image is DynamicMedia image. 5892 * 5893 * @memberof Image 5894 * @type {Boolean} 5895 * @default false 5896 */ 5897 "dmimage": { 5898 "default": false, 5899 "transform": function(value) { 5900 return !(value === null || typeof value === "undefined"); 5901 } 5902 }, 5903 /** 5904 * The lazy threshold. 5905 * This is the number of pixels, in advance of becoming visible, when an lazy-loading image should begin 5906 * to load. 5907 * 5908 * @memberof Image 5909 * @type {Number} 5910 * @default 0 5911 */ 5912 "lazythreshold": { 5913 "default": 0, 5914 "transform": function(value) { 5915 var val = parseInt(value); 5916 if (isNaN(val)) { 5917 return LAZY_THRESHOLD_DEFAULT; 5918 } 5919 return val; 5920 } 5921 }, 5922 /** 5923 * The image source. 5924 * 5925 * Can be a simple image source, or a URI template representation that 5926 * can be variable expanded - useful for building an image configuration with an alternative width. 5927 * e.g. '/path/image.coreimg{.width}.jpeg/1506620954214.jpeg' 5928 * 5929 * @memberof Image 5930 * @type {String} 5931 */ 5932 "src": { 5933 "transform": function(value) { 5934 return decodeURIComponent(value); 5935 } 5936 } 5937 }; 5938 5939 var devicePixelRatio = window.devicePixelRatio || 1; 5940 5941 function readData(element) { 5942 var data = element.dataset; 5943 var options = []; 5944 var capitalized = IS; 5945 capitalized = capitalized.charAt(0).toUpperCase() + capitalized.slice(1); 5946 var reserved = ["is", "hook" + capitalized]; 5947 5948 for (var key in data) { 5949 if (Object.prototype.hasOwnProperty.call(data, key)) { 5950 var value = data[key]; 5951 5952 if (key.indexOf(NS) === 0) { 5953 key = key.slice(NS.length); 5954 key = key.charAt(0).toLowerCase() + key.substring(1); 5955 5956 if (reserved.indexOf(key) === -1) { 5957 options[key] = value; 5958 } 5959 } 5960 } 5961 } 5962 return options; 5963 } 5964 5965 function Image(config) { 5966 var that = this; 5967 5968 var smartCrops = {}; 5969 5970 var useAssetDelivery = false;
5971 var srcUriTemplateWidthVar = SRC_URI_TEMPLATE_WIDTH_VAR; 5972 5973 function init(config) { 5974 // prevents multiple initialization 5975 config.element.removeAttribute("data-" + NS + "-is"); 5976 5977 // check if asset delivery is used 5978 if (config.options.src && config.options.src.indexOf(SRC_URI_TEMPLATE_WIDTH_VAR_ASSET_DELIVERY) >= 0) { 5979 useAssetDelivery = true; 5980 srcUriTemplateWidthVar = SRC_URI_TEMPLATE_WIDTH_VAR_ASSET_DELIVERY; 5981 } 5982 5983 setupProperties(config.options); 5984 cacheElements(config.element); 5985 // check image is DM asset; if true try to make req=set 5986 if (config.options.src && Object.prototype.hasOwnProperty.call(config.options, "dmimage") && (config.options["smartcroprendition"] === "SmartCrop:Auto")) { 5987 var request = new XMLHttpRequest(); 5988 var urlTemplatePart = decodeURIComponent(config.options.src).split(srcUriTemplateWidthVar)[0]; 5989 var url = urlTemplatePart + (urlTemplatePart.indexOf("?") < 0 ? "?" : "") + "req=set,json"; 5990 request.open("GET", url, false); 5991 request.onload = function() { 5992 if (request.status >= 200 && request.status < 400) { 5993 // success status 5994 var responseText = request.responseText; 5995 var rePayload = new RegExp(/^(?:\/\*jsonp\*\/)?\s*([^()]+)\(([\s\S]+),\s*"[0-9]*"\);?$/gmi); 5996 var rePayloadJSON = new RegExp(/^{[\s\S]*}$/gmi); 5997 var resPayload = rePayload.exec(responseText); 5998 var payload; 5999 if (resPayload) { 6000 var payloadStr = resPayload[2]; 6001 if (rePayloadJSON.test(payloadStr)) { 6002 payload = JSON.parse(payloadStr); 6003 } 6004 6005 } 6006 // check "relation" - only in case of smartcrop preset 6007 if (payload && payload.set.relation && payload.set.relation.length > 0) { 6008 for (var i = 0; i < payload.set.relation.length; i++) { 6009 smartCrops[parseInt(payload.set.relation[i].userdata.SmartCropWidth)] = 6010 ":" + payload.set.relation[i].userdata.SmartCropDef; 6011 } 6012 } 6013 } else { 6014 // error status 6015 } 6016 }; 6017 request.send(); 6018 } 6019 6020 if (!that._elements.noscript) { 6021 return; 6022 } 6023 6024 that._elements.container = that._elements.link ? that._elements.link : that._elements.self; 6025 6026 unwrapNoScript(); 6027 6028 if (that._properties.lazy) { 6029 addLazyLoader(); 6030 } 6031 6032 if (that._elements.map) { 6033 that._elements.image.addEventListener("load", onLoad); 6034 } 6035 6036 window.addEventListener("resize", onWindowResize); 6037 ["focus", "click", "load", "transitionend", "animationend", "scroll"].forEach(function(name) { 6038 document.addEventListener(name, that.update); 6039 }); 6040 6041 that._elements.image.addEventListener("cmp-image-redraw", that.update); 6042 that.update(); 6043 } 6044 6045 function loadImage() { 6046 var hasWidths = (that._properties.widths && that._properties.widths.length > 0) || Object.keys(smartCrops).length > 0; 6047 var replacement; 6048 if (Object.keys(smartCrops).length > 0) { 6049 var optimalWidth = getOptimalWidth(Object.keys(smartCrops), false); 6050 replacement = smartCrops[optimalWidth]; 6051 } else { 6052 replacement = hasWidths ? (that._properties.dmimage ? "" : ".") + getOptimalWidth(that._properties.widths, true) : ""; 6053 } 6054 if (useAssetDelivery) {
6055 replacement = replacement !== "" ? ("width=" + replacement.substring(1)) : ""; 6056 } 6057 var url = that._properties.src.replace(srcUriTemplateWidthVar, replacement); 6058 url = url.replace(SRC_URI_TEMPLATE_DPR_VAR, devicePixelRatio); 6059 6060 var imgSrcAttribute = that._elements.image.getAttribute("src"); 6061 6062 if (url !== imgSrcAttribute) { 6063 if (imgSrcAttribute === null || imgSrcAttribute === EMPTY_PIXEL) { 6064 that._elements.image.setAttribute("src", url); 6065 } else { 6066 var urlTemplateParts = that._properties.src.split(srcUriTemplateWidthVar); 6067 // check if image src was dynamically swapped meanwhile (e.g. by Target) 6068 var isImageRefSame = imgSrcAttribute.startsWith(urlTemplateParts[0]); 6069 if (isImageRefSame && urlTemplateParts.length > 1) { 6070 isImageRefSame = imgSrcAttribute.endsWith(urlTemplateParts[urlTemplateParts.length - 1]); 6071 } 6072 if (isImageRefSame) { 6073 that._elements.image.setAttribute("src", url); 6074 if (!hasWidths) { 6075 window.removeEventListener("scroll", that.update); 6076 } 6077 } 6078 } 6079 } 6080 if (that._lazyLoaderShowing) { 6081 that._elements.image.addEventListener("load", removeLazyLoader); 6082 } 6083 } 6084 6085 function getOptimalWidth(widths, useDevicePixelRatio) { 6086 var container = that._elements.self; 6087 var containerWidth = container.clientWidth; 6088 while (containerWidth === 0 && container.parentNode) { 6089 container = container.parentNode; 6090 containerWidth = container.clientWidth; 6091 } 6092 6093 var dpr = useDevicePixelRatio ? devicePixelRatio : 1; 6094 var optimalWidth = containerWidth * dpr; 6095 var len = widths.length; 6096 var key = 0; 6097 6098 while ((key < len - 1) && (widths[key] < optimalWidth)) { 6099 key++; 6100 } 6101 6102 return widths[key].toString(); 6103 } 6104 6105 function addLazyLoader() { 6106 var width = that._elements.image.getAttribute("width"); 6107 var height = that._elements.image.getAttribute("height"); 6108 6109 if (width && height) { 6110 var ratio = (height / width) * 100; 6111 var styles = lazyLoader.style; 6112 6113 styles["padding-bottom"] = ratio + "%"; 6114 6115 for (var s in styles) { 6116 if (Object.prototype.hasOwnProperty.call(styles, s)) { 6117 that._elements.image.style[s] = styles[s]; 6118 } 6119 } 6120 } 6121 that._elements.image.setAttribute("src", EMPTY_PIXEL); 6122 that._elements.image.classList.add(lazyLoader.cssClass); 6123 that._lazyLoaderShowing = true; 6124 } 6125 6126 function unwrapNoScript() { 6127 var markup = decodeNoscript(that._elements.noscript.textContent.trim()); 6128 var parser = new DOMParser(); 6129 6130 // temporary document avoids requesting the image before removing its src 6131 var temporaryDocument = parser.parseFromString(markup, "text/html"); 6132 var imageElement = temporaryDocument.querySelector(selectors.image); 6133 imageElement.removeAttribute("src"); 6134 that._elements.container.insertBefore(imageElement, that._elements.noscript); 6135 6136 var mapElement = temporaryDocument.querySelector(selectors.map); 6137 if (mapElement) { 6138 that._elements.container.insertBefore(mapElement, that._elements.noscript); 6139 } 6140 6141 that._elements.noscript.parentNode.removeChild(that._elements.noscript); 6142 if (that._elements.container.matches(selectors.image)) { 6143 that._elements.image = that._elements.container; 6144 } else { 6145 that._elements.image = that._elements.container.querySelector(selectors.image); 6146 } 6147 6148 that._elements.map = that._elements.container.querySelector(selectors.map); 6149 that._elements.areas = that._elements.container.querySelectorAll(selectors.area); 6150 } 6151 6152 function removeLazyLoader() { 6153 that._elements.image.classList.remove(lazyLoader.cssClass); 6154 for (var property in lazyLoader.style) { 6155 if (Object.prototype.hasOwnProperty.call(lazyLoader.style, property)) { 6156 that._elements.image.style[property] = ""; 6157 } 6158 } 6159 that._elements.image.removeEventListener("load", removeLazyLoader); 6160 that._lazyLoaderShowing = false;
6161 } 6162 6163 function isLazyVisible() { 6164 if (that._elements.container.offsetParent === null) { 6165 return false; 6166 } 6167 6168 var wt = window.pageYOffset; 6169 var wb = wt + document.documentElement.clientHeight; 6170 var et = that._elements.container.getBoundingClientRect().top + wt; 6171 var eb = et + that._elements.container.clientHeight; 6172 6173 return eb >= wt - that._properties.lazythreshold && et <= wb + that._properties.lazythreshold; 6174 } 6175 6176 function resizeAreas() { 6177 if (that._elements.areas && that._elements.areas.length > 0) { 6178 for (var i = 0; i < that._elements.areas.length; i++) { 6179 var width = that._elements.image.width; 6180 var height = that._elements.image.height; 6181 6182 if (width && height) { 6183 var relcoords = that._elements.areas[i].dataset.cmpRelcoords; 6184 if (relcoords) { 6185 var relativeCoordinates = relcoords.split(","); 6186 var coordinates = new Array(relativeCoordinates.length); 6187 6188 for (var j = 0; j < coordinates.length; j++) { 6189 if (j % 2 === 0) { 6190 coordinates[j] = parseInt(relativeCoordinates[j] * width); 6191 } else { 6192 coordinates[j] = parseInt(relativeCoordinates[j] * height); 6193 } 6194 } 6195 6196 that._elements.areas[i].coords = coordinates; 6197 } 6198 } 6199 } 6200 } 6201 } 6202 6203 function cacheElements(wrapper) { 6204 that._elements = {}; 6205 that._elements.self = wrapper; 6206 var hooks = that._elements.self.querySelectorAll("[data-" + NS + "-hook-" + IS + "]"); 6207 6208 for (var i = 0; i < hooks.length; i++) { 6209 var hook = hooks[i]; 6210 var capitalized = IS; 6211 capitalized = capitalized.charAt(0).toUpperCase() + capitalized.slice(1); 6212 var key = hook.dataset[NS + "Hook" + capitalized]; 6213 that._elements[key] = hook; 6214 } 6215 } 6216 6217 function setupProperties(options) { 6218 that._properties = {}; 6219 6220 for (var key in properties) { 6221 if (Object.prototype.hasOwnProperty.call(properties, key)) { 6222 var property = properties[key]; 6223 if (options && options[key] != null) { 6224 if (property && typeof property.transform === "function") { 6225 that._properties[key] = property.transform(options[key]); 6226 } else { 6227 that._properties[key] = options[key]; 6228 } 6229 } else { 6230 that._properties[key] = properties[key]["default"]; 6231 } 6232 } 6233 } 6234 } 6235 6236 function onWindowResize() { 6237 that.update(); 6238 resizeAreas(); 6239 } 6240 6241 function onLoad() { 6242 resizeAreas(); 6243 } 6244 6245 that.update = function() { 6246 if (that._properties.lazy) { 6247 if (isLazyVisible()) { 6248 loadImage(); 6249 } 6250 } else { 6251 loadImage(); 6252 } 6253 }; 6254 6255 if (config && config.element) { 6256 init(config); 6257 } 6258 } 6259 6260 function onDocumentReady() { 6261 var elements = document.querySelectorAll(selectors.self); 6262 for (var i = 0; i < elements.length; i++) { 6263 new Image({ element: elements[i], options: readData(elements[i]) }); 6264 } 6265 6266 var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver; 6267 var body = document.querySelector("body"); 6268 var observer = new MutationObserver(function(mutations) { 6269 mutations.forEach(function(mutation) { 6270 6271 // needed for IE 6272 var nodesArray = [].slice.call(mutation.addedNodes); 6273 if (nodesArray.length > 0) { 6274 nodesArray.forEach(function(addedNode) { 6275 if (addedNode.querySelectorAll) { 6276 var elementsArray = [].slice.call(addedNode.querySelectorAll(selectors.self)); 6277 elementsArray.forEach(function(element) { 6278 new Image({ element: element, options: readData(element) }); 6279 }); 6280 } 6281 }); 6282 } 6283 }); 6284 }); 6285 6286 observer.observe(body, { 6287 subtree: true, 6288 childList: true, 6289 characterData: true 6290 }); 6291 } 6292 6293 if (document.readyState !== "loading") { 6294 onDocumentReady(); 6295 } else { 6296 document.addEventListener("DOMContentLoaded", onDocumentReady); 6297 } 6298 6299 /* 6300 on drag & drop of the component into a parsys, noscript's content will be escaped multiple times by the editor which creates 6301 the DOM for editing; the HTML parser cannot be used here due to the multiple escaping 6302 */ 6303 function decodeNoscript(text) { 6304 text = text.replace(/&(amp;)*lt;/g, "<"); 6305 text = text.replace(/&(amp;)*gt;/g, ">"); 6306 return text; 6307 } 6308 6309})(); 6310 6311/******************************************************************************* 6312 * Copyright 2017 Adobe 6313 * 6314 * Licensed under the Apache License, Version 2.0 (the "License");
6315 * you may not use this file except in compliance with the License. 6316 * You may obtain a copy of the License at 6317 * 6318 * http://www.apache.org/licenses/LICENSE-2.0 6319 * 6320 * Unless required by applicable law or agreed to in writing, software 6321 * distributed under the License is distributed on an "AS IS" BASIS, 6322 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 6323 * See the License for the specific language governing permissions and 6324 * limitations under the License. 6325 ******************************************************************************/ 6326if (window.Element && !Element.prototype.closest) { 6327 // eslint valid-jsdoc: "off" 6328 Element.prototype.closest = 6329 function(s) { 6330 "use strict"; 6331 var matches = (this.document || this.ownerDocument).querySelectorAll(s); 6332 var el = this; 6333 var i; 6334 do { 6335 i = matches.length; 6336 while (--i >= 0 && matches.item(i) !== el) { 6337 // continue 6338 } 6339 } while ((i < 0) && (el = el.parentElement)); 6340 return el; 6341 }; 6342} 6343 6344if (window.Element && !Element.prototype.matches) { 6345 Element.prototype.matches = 6346 Element.prototype.matchesSelector || 6347 Element.prototype.mozMatchesSelector || 6348 Element.prototype.msMatchesSelector || 6349 Element.prototype.oMatchesSelector || 6350 Element.prototype.webkitMatchesSelector || 6351 function(s) { 6352 "use strict"; 6353 var matches = (this.document || this.ownerDocument).querySelectorAll(s); 6354 var i = matches.length; 6355 while (--i >= 0 && matches.item(i) !== this) { 6356 // continue 6357 } 6358 return i > -1; 6359 }; 6360} 6361 6362if (!Object.assign) { 6363 Object.assign = function(target, varArgs) { // .length of function is 2 6364 "use strict"; 6365 if (target === null) { 6366 throw new TypeError("Cannot convert undefined or null to object"); 6367 } 6368 6369 var to = Object(target); 6370 6371 for (var index = 1; index < arguments.length; index++) { 6372 var nextSource = arguments[index]; 6373 6374 if (nextSource !== null) { 6375 for (var nextKey in nextSource) { 6376 if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) { 6377 to[nextKey] = nextSource[nextKey]; 6378 } 6379 } 6380 } 6381 } 6382 return to; 6383 }; 6384} 6385 6386(function(arr) { 6387 "use strict"; 6388 arr.forEach(function(item) { 6389 if (Object.prototype.hasOwnProperty.call(item, "remove")) { 6390 return; 6391 } 6392 Object.defineProperty(item, "remove", { 6393 configurable: true, 6394 enumerable: true, 6395 writable: true, 6396 value: function remove() { 6397 this.parentNode.removeChild(this); 6398 } 6399 }); 6400 }); 6401})([Element.prototype, CharacterData.prototype, DocumentType.prototype]); 6402 6403/******************************************************************************* 6404 * Copyright 2016 Adobe 6405 * 6406 * Licensed under the Apache License, Version 2.0 (the "License"); 6407 * you may not use this file except in compliance with the License. 6408 * You may obtain a copy of the License at 6409 * 6410 * http://www.apache.org/licenses/LICENSE-2.0 6411 * 6412 * Unless required by applicable law or agreed to in writing, software 6413 * distributed under the License is distributed on an "AS IS" BASIS, 6414 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 6415 * See the License for the specific language governing permissions and 6416 * limitations under the License. 6417 ******************************************************************************/ 6418(function() { 6419 "use strict"; 6420 6421 var NS = "cmp"; 6422 var IS = "image"; 6423 var EMPTY_PIXEL = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"; 6424 var LAZY_THRESHOLD_DEFAULT = 0; 6425 var SRC_URI_TEMPLATE_WIDTH_VAR = "{.width}"; 6426 var SRC_URI_TEMPLATE_WIDTH_VAR_ASSET_DELIVERY = "width={width}"; 6427 var SRC_URI_TEMPLATE_DPR_VAR = "{dpr}"; 6428 6429 var selectors = { 6430// self: "[data-" + NS + '-is="' + IS + '"]', 6431 self: '[data-test-primary="image"]', 6432 image: '[data-cmp-hook-image="image"]', 6433 map: '[data-cmp-hook-image="map"]', 6434 area: '[data-cmp-hook-image="area"]' 6435 }; 6436 6437 var lazyLoader = { 6438 "cssClass": "cmp-image__image--is-loading", 6439 "style": { 6440 "height": 0, 6441 "padding-bottom": "" // will be replaced with % ratio 6442 } 6443 }; 6444 6445 var properties = { 6446 /** 6447 * An array of alternative image widths (in pixels). 6448 * Used to replace a {.width} variable in the src property with an optimal width if a URI template is provided. 6449 * 6450 * @memberof Image 6451 * @type {Number[]} 6452 * @default [] 6453 */ 6454 "widths": { 6455 "default": [], 6456 "transform": function(value) { 6457 var widths = []; 6458 value.split(",").forEach(function(item) { 6459 item = parseFloat(item); 6460 if (!isNaN(item)) { 6461 widths.push(item); 6462 } 6463 }); 6464 return widths; 6465 } 6466 }, 6467 /** 6468 * Indicates whether the image should be rendered lazily. 6469 * 6470 * @memberof Image 6471 * @type {Boolean} 6472 * @default false 6473 */ 6474 "lazy": { 6475 "default": false, 6476 "transform": function(value) { 6477 return !(value === null || typeof value === "undefined"); 6478 } 6479 }, 6480 /** 6481 * Indicates image is DynamicMedia image. 6482 * 6483 * @memberof Image 6484 * @type {Boolean} 6485 * @default false 6486 */ 6487 "dmimage": { 6488 "default": false, 6489 "transform": function(value) { 6490 return !(value === null || typeof value === "undefined"); 6491 } 6492 }, 6493 /** 6494 * The lazy threshold. 6495 * This is the number of pixels, in advance of becoming visible, when an lazy-loading image should begin 6496 * to load. 6497 * 6498 * @memberof Image 6499 * @type {Number} 6500 * @default 0 6501 */ 6502 "lazythreshold": { 6503 "default": 0, 6504 "transform": function(value) { 6505 var val = parseInt(value); 6506 if (isNaN(val)) { 6507 return LAZY_THRESHOLD_DEFAULT; 6508 } 6509 return val; 6510 } 6511 }, 6512 /** 6513 * The image source. 6514 * 6515 * Can be a simple image source, or a URI template representation that 6516 * can be variable expanded - useful for building an image configuration with an alternative width. 6517 * e.g. '/path/image.coreimg{.width}.jpeg/1506620954214.jpeg' 6518 * 6519 * @memberof Image 6520 * @type {String} 6521 */ 6522 "src": { 6523 "transform": function(value) { 6524 return decodeURIComponent(value); 6525 } 6526 } 6527 }; 6528 6529 var devicePixelRatio = window.devicePixelRatio || 1; 6530 6531 function readData(element) { 6532 var data = element.dataset; 6533 var options = []; 6534 var capitalized = IS; 6535 capitalized = capitalized.charAt(0).toUpperCase() + capitalized.slice(1); 6536 var reserved = ["is", "hook" + capitalized]; 6537 6538 for (var key in data) { 6539 if (Object.prototype.hasOwnProperty.call(data, key)) { 6540 var value = data[key]; 6541 6542 if (key.indexOf(NS) === 0) { 6543 key = key.slice(NS.length); 6544 key = key.charAt(0).toLowerCase() + key.substring(1); 6545 6546 if (reserved.indexOf(key) === -1) { 6547 options[key] = value; 6548 } 6549 } 6550 } 6551 } 6552 return options; 6553 } 6554 6555 function Image(config) { 6556 var that = this; 6557 6558 var smartCrops = {}; 6559 6560 var useAssetDelivery = false;
6561 var srcUriTemplateWidthVar = SRC_URI_TEMPLATE_WIDTH_VAR; 6562 6563 function init(config) { 6564 // prevents multiple initialization 6565 config.element.removeAttribute("data-" + NS + "-is"); 6566 6567 // check if asset delivery is used 6568 if (config.options.src && config.options.src.indexOf(SRC_URI_TEMPLATE_WIDTH_VAR_ASSET_DELIVERY) >= 0) { 6569 useAssetDelivery = true; 6570 srcUriTemplateWidthVar = SRC_URI_TEMPLATE_WIDTH_VAR_ASSET_DELIVERY; 6571 } 6572 6573 setupProperties(config.options); 6574 cacheElements(config.element); 6575 // check image is DM asset; if true try to make req=set 6576 if (config.options.src && Object.prototype.hasOwnProperty.call(config.options, "dmimage") && (config.options["smartcroprendition"] === "SmartCrop:Auto")) { 6577 var request = new XMLHttpRequest(); 6578 var urlTemplatePart = decodeURIComponent(config.options.src).split(srcUriTemplateWidthVar)[0]; 6579 var url = urlTemplatePart + (urlTemplatePart.indexOf("?") < 0 ? "?" : "") + "req=set,json"; 6580 request.open("GET", url, false); 6581 request.onload = function() { 6582 if (request.status >= 200 && request.status < 400) { 6583 // success status 6584 var responseText = request.responseText; 6585 var rePayload = new RegExp(/^(?:\/\*jsonp\*\/)?\s*([^()]+)\(([\s\S]+),\s*"[0-9]*"\);?$/gmi); 6586 var rePayloadJSON = new RegExp(/^{[\s\S]*}$/gmi); 6587 var resPayload = rePayload.exec(responseText); 6588 var payload; 6589 if (resPayload) { 6590 var payloadStr = resPayload[2]; 6591 if (rePayloadJSON.test(payloadStr)) { 6592 payload = JSON.parse(payloadStr); 6593 } 6594 6595 } 6596 // check "relation" - only in case of smartcrop preset 6597 if (payload && payload.set.relation && payload.set.relation.length > 0) { 6598 for (var i = 0; i < payload.set.relation.length; i++) { 6599 smartCrops[parseInt(payload.set.relation[i].userdata.SmartCropWidth)] = 6600 ":" + payload.set.relation[i].userdata.SmartCropDef; 6601 } 6602 } 6603 } else { 6604 // error status 6605 } 6606 }; 6607 request.send(); 6608 } 6609 6610 if (!that._elements.noscript) { 6611 return; 6612 } 6613 6614 that._elements.container = that._elements.link ? that._elements.link : that._elements.self; 6615 6616 unwrapNoScript(); 6617 6618 if (that._properties.lazy) { 6619 addLazyLoader(); 6620 } 6621 6622 if (that._elements.map) { 6623 that._elements.image.addEventListener("load", onLoad); 6624 } 6625 6626 window.addEventListener("resize", onWindowResize); 6627 ["focus", "click", "load", "transitionend", "animationend", "scroll"].forEach(function(name) { 6628 document.addEventListener(name, that.update); 6629 }); 6630 6631 that._elements.image.addEventListener("cmp-image-redraw", that.update); 6632 that.update(); 6633 } 6634 6635 function loadImage() { 6636 var hasWidths = (that._properties.widths && that._properties.widths.length > 0) || Object.keys(smartCrops).length > 0; 6637 var replacement; 6638 if (Object.keys(smartCrops).length > 0) { 6639 var optimalWidth = getOptimalWidth(Object.keys(smartCrops), false); 6640 replacement = smartCrops[optimalWidth]; 6641 } else { 6642 replacement = hasWidths ? (that._properties.dmimage ? "" : ".") + getOptimalWidth(that._properties.widths, true) : ""; 6643 } 6644 if (useAssetDelivery) {
6645 replacement = replacement !== "" ? ("width=" + replacement.substring(1)) : ""; 6646 } 6647 var url = that._properties.src.replace(srcUriTemplateWidthVar, replacement); 6648 url = url.replace(SRC_URI_TEMPLATE_DPR_VAR, devicePixelRatio); 6649 6650 var imgSrcAttribute = that._elements.image.getAttribute("src"); 6651 6652 if (url !== imgSrcAttribute) { 6653 if (imgSrcAttribute === null || imgSrcAttribute === EMPTY_PIXEL) { 6654 that._elements.image.setAttribute("src", url); 6655 } else { 6656 var urlTemplateParts = that._properties.src.split(srcUriTemplateWidthVar); 6657 // check if image src was dynamically swapped meanwhile (e.g. by Target) 6658 var isImageRefSame = imgSrcAttribute.startsWith(urlTemplateParts[0]); 6659 if (isImageRefSame && urlTemplateParts.length > 1) { 6660 isImageRefSame = imgSrcAttribute.endsWith(urlTemplateParts[urlTemplateParts.length - 1]); 6661 } 6662 if (isImageRefSame) { 6663 that._elements.image.setAttribute("src", url); 6664 if (!hasWidths) { 6665 window.removeEventListener("scroll", that.update); 6666 } 6667 } 6668 } 6669 } 6670 if (that._lazyLoaderShowing) { 6671 that._elements.image.addEventListener("load", removeLazyLoader); 6672 } 6673 } 6674 6675 function getOptimalWidth(widths, useDevicePixelRatio) { 6676 var container = that._elements.self; 6677 var containerWidth = container.clientWidth; 6678 while (containerWidth === 0 && container.parentNode) { 6679 container = container.parentNode; 6680 containerWidth = container.clientWidth; 6681 } 6682 6683 var dpr = useDevicePixelRatio ? devicePixelRatio : 1; 6684 var optimalWidth = containerWidth * dpr; 6685 var len = widths.length; 6686 var key = 0; 6687 6688 while ((key < len - 1) && (widths[key] < optimalWidth)) { 6689 key++; 6690 } 6691 6692 return widths[key].toString(); 6693 } 6694 6695 function addLazyLoader() { 6696 var width = that._elements.image.getAttribute("width"); 6697 var height = that._elements.image.getAttribute("height"); 6698 6699 if (width && height) { 6700 var ratio = (height / width) * 100; 6701 var styles = lazyLoader.style; 6702 6703 styles["padding-bottom"] = ratio + "%"; 6704 6705 for (var s in styles) { 6706 if (Object.prototype.hasOwnProperty.call(styles, s)) { 6707 that._elements.image.style[s] = styles[s]; 6708 } 6709 } 6710 } 6711 that._elements.image.setAttribute("src", EMPTY_PIXEL); 6712 that._elements.image.classList.add(lazyLoader.cssClass); 6713 that._lazyLoaderShowing = true; 6714 } 6715 6716 function unwrapNoScript() { 6717 var markup = decodeNoscript(that._elements.noscript.textContent.trim()); 6718 var parser = new DOMParser(); 6719 6720 // temporary document avoids requesting the image before removing its src 6721 var temporaryDocument = parser.parseFromString(markup, "text/html"); 6722 var imageElement = temporaryDocument.querySelector(selectors.image); 6723 imageElement.removeAttribute("src"); 6724 that._elements.container.insertBefore(imageElement, that._elements.noscript); 6725 6726 var mapElement = temporaryDocument.querySelector(selectors.map); 6727 if (mapElement) { 6728 that._elements.container.insertBefore(mapElement, that._elements.noscript); 6729 } 6730 6731 that._elements.noscript.parentNode.removeChild(that._elements.noscript); 6732 if (that._elements.container.matches(selectors.image)) { 6733 that._elements.image = that._elements.container; 6734 } else { 6735 that._elements.image = that._elements.container.querySelector(selectors.image); 6736 } 6737 6738 that._elements.map = that._elements.container.querySelector(selectors.map); 6739 that._elements.areas = that._elements.container.querySelectorAll(selectors.area); 6740 } 6741 6742 function removeLazyLoader() { 6743 that._elements.image.classList.remove(lazyLoader.cssClass); 6744 for (var property in lazyLoader.style) { 6745 if (Object.prototype.hasOwnProperty.call(lazyLoader.style, property)) { 6746 that._elements.image.style[property] = ""; 6747 } 6748 } 6749 that._elements.image.removeEventListener("load", removeLazyLoader); 6750 that._lazyLoaderShowing = false;
6751 } 6752 6753 function isLazyVisible() { 6754 if (that._elements.container.offsetParent === null) { 6755 return false; 6756 } 6757 6758 var wt = window.pageYOffset; 6759 var wb = wt + document.documentElement.clientHeight; 6760 var et = that._elements.container.getBoundingClientRect().top + wt; 6761 var eb = et + that._elements.container.clientHeight; 6762 6763 return eb >= wt - that._properties.lazythreshold && et <= wb + that._properties.lazythreshold; 6764 } 6765 6766 function resizeAreas() { 6767 if (that._elements.areas && that._elements.areas.length > 0) { 6768 for (var i = 0; i < that._elements.areas.length; i++) { 6769 var width = that._elements.image.width; 6770 var height = that._elements.image.height; 6771 6772 if (width && height) { 6773 var relcoords = that._elements.areas[i].dataset.cmpRelcoords; 6774 if (relcoords) { 6775 var relativeCoordinates = relcoords.split(","); 6776 var coordinates = new Array(relativeCoordinates.length); 6777 6778 for (var j = 0; j < coordinates.length; j++) { 6779 if (j % 2 === 0) { 6780 coordinates[j] = parseInt(relativeCoordinates[j] * width); 6781 } else { 6782 coordinates[j] = parseInt(relativeCoordinates[j] * height); 6783 } 6784 } 6785 6786 that._elements.areas[i].coords = coordinates; 6787 } 6788 } 6789 } 6790 } 6791 } 6792 6793 function cacheElements(wrapper) { 6794 that._elements = {}; 6795 that._elements.self = wrapper; 6796 var hooks = that._elements.self.querySelectorAll("[data-" + NS + "-hook-" + IS + "]"); 6797 6798 for (var i = 0; i < hooks.length; i++) { 6799 var hook = hooks[i]; 6800 var capitalized = IS; 6801 capitalized = capitalized.charAt(0).toUpperCase() + capitalized.slice(1); 6802 var key = hook.dataset[NS + "Hook" + capitalized]; 6803 that._elements[key] = hook; 6804 } 6805 } 6806 6807 function setupProperties(options) { 6808 that._properties = {}; 6809 6810 for (var key in properties) { 6811 if (Object.prototype.hasOwnProperty.call(properties, key)) { 6812 var property = properties[key]; 6813 if (options && options[key] != null) { 6814 if (property && typeof property.transform === "function") { 6815 that._properties[key] = property.transform(options[key]); 6816 } else { 6817 that._properties[key] = options[key]; 6818 } 6819 } else { 6820 that._properties[key] = properties[key]["default"]; 6821 } 6822 } 6823 } 6824 } 6825 6826 function onWindowResize() { 6827 that.update(); 6828 resizeAreas(); 6829 } 6830 6831 function onLoad() { 6832 resizeAreas(); 6833 } 6834 6835 that.update = function() { 6836 if (that._properties.lazy) { 6837 if (isLazyVisible()) { 6838 loadImage(); 6839 } 6840 } else { 6841 loadImage(); 6842 } 6843 }; 6844 6845 if (config && config.element) { 6846 init(config); 6847 } 6848 } 6849 6850 function onDocumentReady() { 6851 var elements = document.querySelectorAll(selectors.self); 6852 for (var i = 0; i < elements.length; i++) { 6853 new Image({ element: elements[i], options: readData(elements[i]) }); 6854 } 6855 6856 var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver; 6857 var body = document.querySelector("body"); 6858 var observer = new MutationObserver(function(mutations) { 6859 mutations.forEach(function(mutation) { 6860 6861 // needed for IE 6862 var nodesArray = [].slice.call(mutation.addedNodes); 6863 if (nodesArray.length > 0) { 6864 nodesArray.forEach(function(addedNode) { 6865 if (addedNode.querySelectorAll) { 6866 var elementsArray = [].slice.call(addedNode.querySelectorAll(selectors.self)); 6867 elementsArray.forEach(function(element) { 6868 new Image({ element: element, options: readData(element) }); 6869 }); 6870 } 6871 }); 6872 } 6873 }); 6874 }); 6875 6876 observer.observe(body, { 6877 subtree: true, 6878 childList: true, 6879 characterData: true 6880 }); 6881 } 6882 6883 if (document.readyState !== "loading") { 6884 onDocumentReady(); 6885 } else { 6886 document.addEventListener("DOMContentLoaded", onDocumentReady); 6887 } 6888 6889 /* 6890 on drag & drop of the component into a parsys, noscript's content will be escaped multiple times by the editor which creates 6891 the DOM for editing; the HTML parser cannot be used here due to the multiple escaping 6892 */ 6893 function decodeNoscript(text) { 6894 text = text.replace(/&(amp;)*lt;/g, "<"); 6895 text = text.replace(/&(amp;)*gt;/g, ">"); 6896 return text; 6897 } 6898 6899})(); 6900 6901/******************************************************************************* 6902 * Copyright 2017 Adobe 6903 * 6904 * Licensed under the Apache License, Version 2.0 (the "License");
6905 * you may not use this file except in compliance with the License. 6906 * You may obtain a copy of the License at 6907 * 6908 * http://www.apache.org/licenses/LICENSE-2.0 6909 * 6910 * Unless required by applicable law or agreed to in writing, software 6911 * distributed under the License is distributed on an "AS IS" BASIS, 6912 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 6913 * See the License for the specific language governing permissions and 6914 * limitations under the License. 6915 ******************************************************************************/ 6916if (window.Element && !Element.prototype.closest) { 6917 // eslint valid-jsdoc: "off" 6918 Element.prototype.closest = 6919 function(s) { 6920 "use strict"; 6921 var matches = (this.document || this.ownerDocument).querySelectorAll(s); 6922 var el = this; 6923 var i; 6924 do { 6925 i = matches.length; 6926 while (--i >= 0 && matches.item(i) !== el) { 6927 // continue 6928 } 6929 } while ((i < 0) && (el = el.parentElement)); 6930 return el; 6931 }; 6932} 6933 6934if (window.Element && !Element.prototype.matches) { 6935 Element.prototype.matches = 6936 Element.prototype.matchesSelector || 6937 Element.prototype.mozMatchesSelector || 6938 Element.prototype.msMatchesSelector || 6939 Element.prototype.oMatchesSelector || 6940 Element.prototype.webkitMatchesSelector || 6941 function(s) { 6942 "use strict"; 6943 var matches = (this.document || this.ownerDocument).querySelectorAll(s); 6944 var i = matches.length; 6945 while (--i >= 0 && matches.item(i) !== this) { 6946 // continue 6947 } 6948 return i > -1; 6949 }; 6950} 6951 6952if (!Object.assign) { 6953 Object.assign = function(target, varArgs) { // .length of function is 2 6954 "use strict"; 6955 if (target === null) { 6956 throw new TypeError("Cannot convert undefined or null to object"); 6957 } 6958 6959 var to = Object(target); 6960 6961 for (var index = 1; index < arguments.length; index++) { 6962 var nextSource = arguments[index]; 6963 6964 if (nextSource !== null) { 6965 for (var nextKey in nextSource) { 6966 if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) { 6967 to[nextKey] = nextSource[nextKey]; 6968 } 6969 } 6970 } 6971 } 6972 return to; 6973 }; 6974} 6975 6976(function(arr) { 6977 "use strict"; 6978 arr.forEach(function(item) { 6979 if (Object.prototype.hasOwnProperty.call(item, "remove")) { 6980 return; 6981 } 6982 Object.defineProperty(item, "remove", { 6983 configurable: true, 6984 enumerable: true, 6985 writable: true, 6986 value: function remove() { 6987 this.parentNode.removeChild(this); 6988 } 6989 }); 6990 }); 6991})([Element.prototype, CharacterData.prototype, DocumentType.prototype]); 6992 6993/******************************************************************************* 6994 * Copyright 2016 Adobe 6995 * 6996 * Licensed under the Apache License, Version 2.0 (the "License"); 6997 * you may not use this file except in compliance with the License. 6998 * You may obtain a copy of the License at 6999 * 7000 * http://www.apache.org/licenses/LICENSE-2.0 7001 * 7002 * Unless required by applicable law or agreed to in writing, software 7003 * distributed under the License is distributed on an "AS IS" BASIS, 7004 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 7005 * See the License for the specific language governing permissions and 7006 * limitations under the License. 7007 ******************************************************************************/ 7008(function() { 7009 "use strict"; 7010 7011 var NS = "cmp"; 7012 var IS = "image"; 7013 7014 var EMPTY_PIXEL = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"; 7015 var LAZY_THRESHOLD_DEFAULT = 0; 7016 var SRC_URI_TEMPLATE_WIDTH_VAR = "{.width}"; 7017 var SRC_URI_TEMPLATE_WIDTH_VAR_ASSET_DELIVERY = "width={width}"; 7018 var SRC_URI_TEMPLATE_DPR_VAR = "{dpr}"; 7019 7020 var selectors = { 7021 self: "[data-" + NS + '-is="' + IS + '"]', 7022 image: '[data-cmp-hook-image="image"]', 7023 map: '[data-cmp-hook-image="map"]', 7024 area: '[data-cmp-hook-image="area"]' 7025 }; 7026 7027 var lazyLoader = { 7028 "cssClass": "cmp-image__image--is-loading", 7029 "style": { 7030 "height": 0, 7031 "padding-bottom": "" // will be replaced with % ratio 7032 } 7033 }; 7034 7035 var properties = { 7036 /** 7037 * An array of alternative image widths (in pixels). 7038 * Used to replace a {.width} variable in the src property with an optimal width if a URI template is provided. 7039 * 7040 * @memberof Image 7041 * @type {Number[]} 7042 * @default [] 7043 */ 7044 "widths": { 7045 "default": [], 7046 "transform": function(value) { 7047 var widths = []; 7048 value.split(",").forEach(function(item) { 7049 item = parseFloat(item); 7050 if (!isNaN(item)) { 7051 widths.push(item); 7052 } 7053 }); 7054 return widths; 7055 } 7056 }, 7057 /** 7058 * Indicates whether the image should be rendered lazily. 7059 * 7060 * @memberof Image 7061 * @type {Boolean} 7062 * @default false 7063 */ 7064 "lazy": { 7065 "default": false, 7066 "transform": function(value) { 7067 return !(value === null || typeof value === "undefined"); 7068 } 7069 }, 7070 /** 7071 * Indicates image is DynamicMedia image. 7072 * 7073 * @memberof Image 7074 * @type {Boolean} 7075 * @default false 7076 */ 7077 "dmimage": { 7078 "default": false, 7079 "transform": function(value) { 7080 return !(value === null || typeof value === "undefined"); 7081 } 7082 }, 7083 /** 7084 * The lazy threshold. 7085 * This is the number of pixels, in advance of becoming visible, when an lazy-loading image should begin 7086 * to load. 7087 * 7088 * @memberof Image 7089 * @type {Number} 7090 * @default 0 7091 */ 7092 "lazythreshold": { 7093 "default": 0, 7094 "transform": function(value) { 7095 var val = parseInt(value); 7096 if (isNaN(val)) { 7097 return LAZY_THRESHOLD_DEFAULT; 7098 } 7099 return val; 7100 } 7101 }, 7102 /** 7103 * The image source. 7104 * 7105 * Can be a simple image source, or a URI template representation that 7106 * can be variable expanded - useful for building an image configuration with an alternative width. 7107 * e.g. '/path/image.coreimg{.width}.jpeg/1506620954214.jpeg' 7108 * 7109 * @memberof Image 7110 * @type {String} 7111 */ 7112 "src": { 7113 "transform": function(value) { 7114 return decodeURIComponent(value); 7115 } 7116 } 7117 }; 7118 7119 var devicePixelRatio = window.devicePixelRatio || 1; 7120 7121 function readData(element) { 7122 var data = element.dataset; 7123 var options = []; 7124 var capitalized = IS; 7125 capitalized = capitalized.charAt(0).toUpperCase() + capitalized.slice(1); 7126 var reserved = ["is", "hook" + capitalized]; 7127 7128 for (var key in data) { 7129 if (Object.prototype.hasOwnProperty.call(data, key)) { 7130 var value = data[key]; 7131 7132 if (key.indexOf(NS) === 0) { 7133 key = key.slice(NS.length); 7134 key = key.charAt(0).toLowerCase() + key.substring(1); 7135 7136 if (reserved.indexOf(key) === -1) { 7137 options[key] = value; 7138 } 7139 } 7140 } 7141 } 7142 return options; 7143 } 7144 7145 function Image(config) { 7146 var that = this; 7147 7148 var smartCrops = {}; 7149 7150 var useAssetDelivery = false;
7151 var srcUriTemplateWidthVar = SRC_URI_TEMPLATE_WIDTH_VAR; 7152 7153 function init(config) { 7154 // prevents multiple initialization 7155 config.element.removeAttribute("data-" + NS + "-is"); 7156 7157 // check if asset delivery is used 7158 if (config.options.src && config.options.src.indexOf(SRC_URI_TEMPLATE_WIDTH_VAR_ASSET_DELIVERY) >= 0) { 7159 useAssetDelivery = true; 7160 srcUriTemplateWidthVar = SRC_URI_TEMPLATE_WIDTH_VAR_ASSET_DELIVERY; 7161 } 7162 7163 setupProperties(config.options); 7164 cacheElements(config.element); 7165 // check image is DM asset; if true try to make req=set 7166 if (config.options.src && Object.prototype.hasOwnProperty.call(config.options, "dmimage") && (config.options["smartcroprendition"] === "SmartCrop:Auto")) { 7167 var request = new XMLHttpRequest(); 7168 var urlTemplatePart = decodeURIComponent(config.options.src).split(srcUriTemplateWidthVar)[0]; 7169 var url = urlTemplatePart + (urlTemplatePart.indexOf("?") < 0 ? "?" : "") + "req=set,json"; 7170 7171 request.open("GET", url, false); 7172 request.onload = function() { 7173 if (request.status >= 200 && request.status < 400) { 7174 // success status 7175 var responseText = request.responseText; 7176 var rePayload = new RegExp(/^(?:\/\*jsonp\*\/)?\s*([^()]+)\(([\s\S]+),\s*"[0-9]*"\);?$/gmi); 7177 var rePayloadJSON = new RegExp(/^{[\s\S]*}$/gmi); 7178 var resPayload = rePayload.exec(responseText); 7179 var payload; 7180 if (resPayload) { 7181 var payloadStr = resPayload[2]; 7182 if (rePayloadJSON.test(payloadStr)) { 7183 payload = JSON.parse(payloadStr); 7184 } 7185 7186 } 7187 // check "relation" - only in case of smartcrop preset 7188 if (payload && payload.set.relation && payload.set.relation.length > 0) { 7189 for (var i = 0; i < payload.set.relation.length; i++) { 7190 smartCrops[parseInt(payload.set.relation[i].userdata.SmartCropWidth)] = 7191 ":" + payload.set.relation[i].userdata.SmartCropDef; 7192 } 7193 } 7194 } else { 7195 // error status 7196 } 7197 }; 7198 request.send(); 7199 } 7200 7201 if (!that._elements.noscript) { 7202 return; 7203 } 7204 7205 that._elements.container = that._elements.link ? that._elements.link : that._elements.self; 7206 7207 unwrapNoScript(); 7208 7209 if (that._properties.lazy) { 7210 addLazyLoader(); 7211 } 7212 7213 if (that._elements.map) { 7214 that._elements.image.addEventListener("load", onLoad); 7215 } 7216 7217 window.addEventListener("resize", onWindowResize); 7218 ["focus", "click", "load", "transitionend", "animationend", "scroll"].forEach(function(name) { 7219 document.addEventListener(name, that.update); 7220 }); 7221 7222 that._elements.image.addEventListener("cmp-image-redraw", that.update); 7223 that.update(); 7224 } 7225 7226 function loadImage() { 7227 var hasWidths = (that._properties.widths && that._properties.widths.length > 0) || Object.keys(smartCrops).length > 0; 7228 var replacement; 7229 if (Object.keys(smartCrops).length > 0) { 7230 var optimalWidth = getOptimalWidth(Object.keys(smartCrops), false); 7231 replacement = smartCrops[optimalWidth]; 7232 } else { 7233 replacement = hasWidths ? (that._properties.dmimage ? "" : ".") + getOptimalWidth(that._properties.widths, true) : ""; 7234 } 7235 if (useAssetDelivery) {
7236 replacement = replacement !== "" ? ("width=" + replacement.substring(1)) : ""; 7237 } 7238 var url = that._properties.src.replace(srcUriTemplateWidthVar, replacement); 7239 url = url.replace(SRC_URI_TEMPLATE_DPR_VAR, devicePixelRatio); 7240 7241 var imgSrcAttribute = that._elements.image.getAttribute("src"); 7242 7243 if (url !== imgSrcAttribute) { 7244 if (imgSrcAttribute === null || imgSrcAttribute === EMPTY_PIXEL) { 7245 that._elements.image.setAttribute("src", url); 7246 } else { 7247 var urlTemplateParts = that._properties.src.split(srcUriTemplateWidthVar); 7248 // check if image src was dynamically swapped meanwhile (e.g. by Target) 7249 var isImageRefSame = imgSrcAttribute.startsWith(urlTemplateParts[0]); 7250 if (isImageRefSame && urlTemplateParts.length > 1) { 7251 isImageRefSame = imgSrcAttribute.endsWith(urlTemplateParts[urlTemplateParts.length - 1]); 7252 } 7253 if (isImageRefSame) { 7254 that._elements.image.setAttribute("src", url); 7255 if (!hasWidths) { 7256 window.removeEventListener("scroll", that.update); 7257 } 7258 } 7259 } 7260 } 7261 if (that._lazyLoaderShowing) { 7262 that._elements.image.addEventListener("load", removeLazyLoader); 7263 } 7264 } 7265 7266 function getOptimalWidth(widths, useDevicePixelRatio) { 7267 var container = that._elements.self; 7268 var containerWidth = container.clientWidth; 7269 while (containerWidth === 0 && container.parentNode) { 7270 container = container.parentNode; 7271 containerWidth = container.clientWidth; 7272 } 7273 7274 var dpr = useDevicePixelRatio ? devicePixelRatio : 1; 7275 var optimalWidth = containerWidth * dpr; 7276 var len = widths.length; 7277 var key = 0; 7278 7279 while ((key < len - 1) && (widths[key] < optimalWidth)) { 7280 key++; 7281 } 7282 7283 return widths[key].toString(); 7284 } 7285 7286 function addLazyLoader() { 7287 var width = that._elements.image.getAttribute("width"); 7288 var height = that._elements.image.getAttribute("height"); 7289 7290 if (width && height) { 7291 var ratio = (height / width) * 100; 7292 var styles = lazyLoader.style; 7293 7294 styles["padding-bottom"] = ratio + "%"; 7295 7296 for (var s in styles) { 7297 if (Object.prototype.hasOwnProperty.call(styles, s)) { 7298 that._elements.image.style[s] = styles[s]; 7299 } 7300 } 7301 } 7302 that._elements.image.setAttribute("src", EMPTY_PIXEL); 7303 that._elements.image.classList.add(lazyLoader.cssClass); 7304 that._lazyLoaderShowing = true; 7305 } 7306 7307 function unwrapNoScript() { 7308 var markup = decodeNoscript(that._elements.noscript.textContent.trim()); 7309 var parser = new DOMParser(); 7310 7311 // temporary document avoids requesting the image before removing its src 7312 var temporaryDocument = parser.parseFromString(markup, "text/html"); 7313 var imageElement = temporaryDocument.querySelector(selectors.image); 7314 imageElement.removeAttribute("src"); 7315 that._elements.container.insertBefore(imageElement, that._elements.noscript); 7316 7317 var mapElement = temporaryDocument.querySelector(selectors.map); 7318 if (mapElement) { 7319 that._elements.container.insertBefore(mapElement, that._elements.noscript); 7320 } 7321 7322 that._elements.noscript.parentNode.removeChild(that._elements.noscript); 7323 if (that._elements.container.matches(selectors.image)) { 7324 that._elements.image = that._elements.container; 7325 } else { 7326 that._elements.image = that._elements.container.querySelector(selectors.image); 7327 } 7328 7329 that._elements.map = that._elements.container.querySelector(selectors.map); 7330 that._elements.areas = that._elements.container.querySelectorAll(selectors.area); 7331 } 7332 7333 function removeLazyLoader() { 7334 that._elements.image.classList.remove(lazyLoader.cssClass); 7335 for (var property in lazyLoader.style) { 7336 if (Object.prototype.hasOwnProperty.call(lazyLoader.style, property)) { 7337 that._elements.image.style[property] = ""; 7338 } 7339 } 7340 that._elements.image.removeEventListener("load", removeLazyLoader); 7341 that._lazyLoaderShowing = false;
7342 } 7343 7344 function isLazyVisible() { 7345 if (that._elements.container.offsetParent === null) { 7346 return false; 7347 } 7348 7349 var wt = window.pageYOffset; 7350 var wb = wt + document.documentElement.clientHeight; 7351 var et = that._elements.container.getBoundingClientRect().top + wt; 7352 var eb = et + that._elements.container.clientHeight; 7353 7354 return eb >= wt - that._properties.lazythreshold && et <= wb + that._properties.lazythreshold; 7355 } 7356 7357 function resizeAreas() { 7358 if (that._elements.areas && that._elements.areas.length > 0) { 7359 for (var i = 0; i < that._elements.areas.length; i++) { 7360 var width = that._elements.image.width; 7361 var height = that._elements.image.height; 7362 7363 if (width && height) { 7364 var relcoords = that._elements.areas[i].dataset.cmpRelcoords; 7365 if (relcoords) { 7366 var relativeCoordinates = relcoords.split(","); 7367 var coordinates = new Array(relativeCoordinates.length); 7368 7369 for (var j = 0; j < coordinates.length; j++) { 7370 if (j % 2 === 0) { 7371 coordinates[j] = parseInt(relativeCoordinates[j] * width); 7372 } else { 7373 coordinates[j] = parseInt(relativeCoordinates[j] * height); 7374 } 7375 } 7376 7377 that._elements.areas[i].coords = coordinates; 7378 } 7379 } 7380 } 7381 } 7382 } 7383 7384 function cacheElements(wrapper) { 7385 that._elements = {}; 7386 that._elements.self = wrapper; 7387 var hooks = that._elements.self.querySelectorAll("[data-" + NS + "-hook-" + IS + "]"); 7388 7389 for (var i = 0; i < hooks.length; i++) { 7390 var hook = hooks[i]; 7391 var capitalized = IS; 7392 capitalized = capitalized.charAt(0).toUpperCase() + capitalized.slice(1); 7393 var key = hook.dataset[NS + "Hook" + capitalized]; 7394 that._elements[key] = hook; 7395 } 7396 } 7397 7398 function setupProperties(options) { 7399 that._properties = {}; 7400 7401 for (var key in properties) { 7402 if (Object.prototype.hasOwnProperty.call(properties, key)) { 7403 var property = properties[key]; 7404 if (options && options[key] != null) { 7405 if (property && typeof property.transform === "function") { 7406 that._properties[key] = property.transform(options[key]); 7407 } else { 7408 that._properties[key] = options[key]; 7409 } 7410 } else { 7411 that._properties[key] = properties[key]["default"]; 7412 } 7413 } 7414 } 7415 } 7416 7417 function onWindowResize() { 7418 that.update(); 7419 resizeAreas(); 7420 } 7421 7422 function onLoad() { 7423 resizeAreas(); 7424 } 7425 7426 that.update = function() { 7427 if (that._properties.lazy) { 7428 if (isLazyVisible()) { 7429 loadImage(); 7430 } 7431 } else { 7432 loadImage(); 7433 } 7434 }; 7435 7436 if (config && config.element) { 7437 init(config); 7438 } 7439 } 7440 7441 function onDocumentReady() { 7442 var elements = document.querySelectorAll(selectors.self); 7443 for (var i = 0; i < elements.length; i++) { 7444 new Image({ element: elements[i], options: readData(elements[i]) }); 7445 } 7446 7447 var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver; 7448 var body = document.querySelector("body"); 7449 var observer = new MutationObserver(function(mutations) { 7450 mutations.forEach(function(mutation) { 7451 // needed for IE 7452 var nodesArray = [].slice.call(mutation.addedNodes); 7453 if (nodesArray.length > 0) { 7454 nodesArray.forEach(function(addedNode) { 7455 if (addedNode.querySelectorAll) { 7456 var elementsArray = [].slice.call(addedNode.querySelectorAll(selectors.self)); 7457 elementsArray.forEach(function(element) { 7458 new Image({ element: element, options: readData(element) }); 7459 }); 7460 } 7461 }); 7462 } 7463 }); 7464 }); 7465 7466 observer.observe(body, { 7467 subtree: true, 7468 childList: true, 7469 characterData: true 7470 }); 7471 } 7472 7473 if (document.readyState !== "loading") { 7474 onDocumentReady(); 7475 } else { 7476 document.addEventListener("DOMContentLoaded", onDocumentReady); 7477 } 7478 7479 /* 7480 on drag & drop of the component into a parsys, noscript's content will be escaped multiple times by the editor which creates 7481 the DOM for editing; the HTML parser cannot be used here due to the multiple escaping 7482 */ 7483 function decodeNoscript(text) { 7484 text = text.replace(/&(amp;)*lt;/g, "<"); 7485 text = text.replace(/&(amp;)*gt;/g, ">"); 7486 return text; 7487 } 7488 7489})(); 7490 7491/******************************************************************************* 7492 * Copyright 2022 Adobe 7493 * 7494 * Licensed under the Apache License, Version 2.0 (the "License");
7495 * you may not use this file except in compliance with the License. 7496 * You may obtain a copy of the License at 7497 * 7498 * http://www.apache.org/licenses/LICENSE-2.0 7499 * 7500 * Unless required by applicable law or agreed to in writing, software 7501 * distributed under the License is distributed on an "AS IS" BASIS, 7502 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 7503 * See the License for the specific language governing permissions and 7504 * limitations under the License. 7505 ******************************************************************************/ 7506(function() { 7507 "use strict"; 7508 7509 var NS = "cmp"; 7510 var IS = "search"; 7511 7512 var DELAY = 300; // time before fetching new results when the user is typing a search string 7513 var LOADING_DISPLAY_DELAY = 300; // minimum time during which the loading indicator is displayed 7514 var PARAM_RESULTS_OFFSET = "resultsOffset"; 7515 7516 var keyCodes = { 7517 TAB: 9, 7518 ENTER: 13, 7519 ESCAPE: 27, 7520 ARROW_UP: 38, 7521 ARROW_DOWN: 40 7522 }; 7523 7524 var selectors = { 7525 self: "[data-" + NS + '-is="' + IS + '"]', 7526 item: { 7527 self: "[data-" + NS + "-hook-" + IS + '="item"]', 7528 title: "[data-" + NS + "-hook-" + IS + '="itemTitle"]', 7529 focused: "." + NS + "-search__item--is-focused" 7530 } 7531 }; 7532 7533 var properties = { 7534 /** 7535 * The minimum required length of the search term before results are fetched. 7536 * 7537 * @memberof Search 7538 * @type {Number} 7539 * @default 3 7540 */ 7541 minLength: { 7542 "default": 3, 7543 transform: function(value) { 7544 value = parseFloat(value); 7545 return isNaN(value) ? null : value; 7546 } 7547 }, 7548 /** 7549 * The maximal number of results fetched by a search request. 7550 * 7551 * @memberof Search 7552 * @type {Number} 7553 * @default 10 7554 */ 7555 resultsSize: { 7556 "default": 10, 7557 transform: function(value) { 7558 value = parseFloat(value); 7559 return isNaN(value) ? null : value; 7560 } 7561 } 7562 }; 7563 7564 var idCount = 0; 7565 7566 function readData(element) { 7567 var data = element.dataset; 7568 var options = []; 7569 var capitalized = IS; 7570 capitalized = capitalized.charAt(0).toUpperCase() + capitalized.slice(1); 7571 var reserved = ["is", "hook" + capitalized]; 7572 7573 for (var key in data) { 7574 if (Object.prototype.hasOwnProperty.call(data, key)) { 7575 var value = data[key]; 7576 7577 if (key.indexOf(NS) === 0) { 7578 key = key.slice(NS.length); 7579 key = key.charAt(0).toLowerCase() + key.substring(1); 7580 7581 if (reserved.indexOf(key) === -1) { 7582 options[key] = value; 7583 } 7584 } 7585 } 7586 } 7587 7588 return options; 7589 } 7590 7591 function toggleShow(element, show) { 7592 if (element) { 7593 if (show !== false) { 7594 element.style.display = "block"; 7595 element.setAttribute("aria-hidden", false); 7596 } else { 7597 element.style.display = "none"; 7598 element.setAttribute("aria-hidden", true); 7599 } 7600 } 7601 } 7602 7603 function serialize(form) { 7604 var query = []; 7605 if (form && form.elements) { 7606 for (var i = 0; i < form.elements.length; i++) { 7607 var node = form.elements[i]; 7608 if (!node.disabled && node.name) { 7609 var param = [node.name, encodeURIComponent(node.value)]; 7610 query.push(param.join("=")); 7611 } 7612 } 7613 } 7614 return query.join("&"); 7615 } 7616 7617 function mark(node, regex) { 7618 if (!node || !regex) { 7619 return; 7620 } 7621 7622 // text nodes 7623 if (node.nodeType === 3) { 7624 var nodeValue = node.nodeValue; 7625 var match = regex.exec(nodeValue); 7626 7627 if (nodeValue && match) { 7628 var element = document.createElement("mark"); 7629 element.className = NS + "-search__item-mark"; 7630 element.appendChild(document.createTextNode(match[0])); 7631 7632 var after = node.splitText(match.index); 7633 after.nodeValue = after.nodeValue.substring(match[0].length); 7634 node.parentNode.insertBefore(element, after); 7635 } 7636 } else if (node.hasChildNodes()) { 7637 for (var i = 0; i < node.childNodes.length; i++) { 7638 // recurse 7639 mark(node.childNodes[i], regex); 7640 } 7641 } 7642 } 7643 7644 function localizeMessage(searchElementId, message, values = []) { 7645 const i18nMessages = JSON.parse(document.querySelector("#" + searchElementId).getAttribute("data-i18n-messages")); 7646 let translation = i18nMessages[message]; 7647 // Insert values 7648 if (values.length > 0) { 7649 translation = translation.replace(/{(\d+)}/g, function(match, index) { 7650 return typeof values[index] !== "undefined" ? values[index] : match; 7651 }); 7652 } 7653 return translation; 7654 } 7655 7656 // useful for Accessibility, helping users with low vision and users with cognitive disabilities to identify the change in results 7657 function updateSearchResultsStatusMessageElement(searchElementId, totalResults) { 7658 var searchResultsStatusMessage = document.querySelector("#" + searchElementId + "> .cmp_search__info"); 7659 searchResultsStatusMessage.style.visibility = "visible"; 7660 var searchResultsFoundMessage = localizeMessage(searchElementId, totalResults === 1 ? "{0} result" : "{0} results", [totalResults]); 7661 var searchResultsNotFoundMessage = localizeMessage(searchElementId, "No results"); 7662 searchResultsStatusMessage.innerText = totalResults > 0 ? searchResultsFoundMessage : searchResultsNotFoundMessage; 7663 } 7664 7665 function Search(config) { 7666 if (config.element) { 7667 // prevents multiple initialization 7668 config.element.removeAttribute("data-" + NS + "-is"); 7669 } 7670 7671 this._cacheElements(config.element); 7672 this._setupProperties(config.options); 7673 7674 this._action = this._elements.form.getAttribute("action"); 7675 this._resultsOffset = 0; 7676 this._hasMoreResults = true; 7677 7678 this._elements.input.addEventListener("input", this._onInput.bind(this)); 7679 this._elements.input.addEventListener("focus", this._onInput.bind(this)); 7680 this._elements.input.addEventListener("keydown", this._onKeydown.bind(this)); 7681 this._elements.clear.addEventListener("click", this._onClearClick.bind(this)); 7682 document.addEventListener("click", this._onDocumentClick.bind(this)); 7683 this._elements.results.addEventListener("scroll", this._onScroll.bind(this)); 7684 7685 this._makeAccessible(); 7686 } 7687 7688 Search.prototype._displayResults = function() { 7689 if (this._elements.input.value.length === 0) { 7690 toggleShow(this._elements.clear, false); 7691 this._cancelResults(); 7692 } else if (this._elements.input.value.length < this._properties.minLength) { 7693 toggleShow(this._elements.clear, true); 7694 } else { 7695 this._updateResults(); 7696 toggleShow(this._elements.clear, true); 7697 } 7698 }; 7699 7700 Search.prototype._onScroll = function(event) { 7701 // fetch new results when the results to be scrolled down are less than the visible results 7702 if (this._elements.results.scrollTop + 2 * this._elements.results.clientHeight >= this._elements.results.scrollHeight) { 7703 this._resultsOffset += this._properties.resultsSize; 7704 this._displayResults(); 7705 } 7706 }; 7707 7708 Search.prototype._onInput = function(event) { 7709 var self = this; 7710 self._cancelResults(); 7711 // start searching when the search term reaches the minimum length 7712 this._timeout = setTimeout(function() { 7713 self._displayResults(); 7714 }, DELAY); 7715 }; 7716 7717 Search.prototype._onKeydown = function(event) { 7718 var self = this; 7719 7720 switch (event.keyCode) { 7721 case keyCodes.TAB: 7722 if (self._resultsOpen()) { 7723 toggleShow(self._elements.results, false); 7724 self._elements.input.setAttribute("aria-expanded", "false"); 7725 this._hideSearchResultsStatusMessage(); 7726 } 7727 break;
7728 case keyCodes.ENTER: 7729 event.preventDefault(); 7730 if (self._resultsOpen()) { 7731 var focused = self._elements.results.querySelector(selectors.item.focused); 7732 if (focused) { 7733 focused.click(); 7734 } 7735 } 7736 break; 7737 case keyCodes.ESCAPE: 7738 self._cancelResults(); 7739 break; 7740 case keyCodes.ARROW_UP: 7741 if (self._resultsOpen()) { 7742 event.preventDefault(); 7743 self._stepResultFocus(true); 7744 } 7745 break; 7746 case keyCodes.ARROW_DOWN: 7747 if (self._resultsOpen()) { 7748 event.preventDefault(); 7749 self._stepResultFocus(); 7750 } else { 7751 // test the input and if necessary fetch and display the results 7752 self._onInput(); 7753 } 7754 break; 7755 default: 7756 return; 7757 } 7758 }; 7759 7760 Search.prototype._onClearClick = function(event) { 7761 event.preventDefault(); 7762 this._elements.input.value = ""; 7763 toggleShow(this._elements.clear, false); 7764 toggleShow(this._elements.results, false); 7765 this._elements.input.setAttribute("aria-expanded", "false"); 7766 this._hideSearchResultsStatusMessage(); 7767 }; 7768 7769 Search.prototype._onDocumentClick = function(event) { 7770 var inputContainsTarget = this._elements.input.contains(event.target); 7771 var resultsContainTarget = this._elements.results.contains(event.target); 7772 7773 if (!(inputContainsTarget || resultsContainTarget)) { 7774 toggleShow(this._elements.results, false); 7775 this._elements.input.setAttribute("aria-expanded", "false"); 7776 this._hideSearchResultsStatusMessage(); 7777 } 7778 }; 7779 7780 Search.prototype._resultsOpen = function() { 7781 return this._elements.results.style.display !== "none"; 7782 }; 7783 7784 Search.prototype._makeAccessible = function() { 7785 var id = NS + "-search-results-" + idCount; 7786 this._elements.input.setAttribute("aria-owns", id); 7787 this._elements.results.id = id; 7788 idCount++; 7789 }; 7790 7791 Search.prototype._generateItems = function(data, results) { 7792 var self = this; 7793 7794 data.forEach(function(item) { 7795 var el = document.createElement("span"); 7796 el.innerHTML = self._elements.itemTemplate.innerHTML; 7797 el.querySelectorAll(selectors.item.title)[0].appendChild(document.createTextNode(item.title)); 7798 el.querySelectorAll(selectors.item.self)[0].setAttribute("href", self._safeHref(item.url)); 7799 results.innerHTML += el.innerHTML; 7800 }); 7801 }; 7802 7803 Search.prototype._safeHref = function(href) { 7804 var a = document.createElement("a"); 7805 a.href = href; 7806 return a.pathname; 7807 }; 7808 7809 Search.prototype._markResults = function() { 7810 var nodeList = this._elements.results.querySelectorAll(selectors.item.self); 7811 var escapedTerm = this._elements.input.value.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"); 7812 var regex = new RegExp("(" + escapedTerm + ")", "gi"); 7813 7814 for (var i = this._resultsOffset - 1; i < nodeList.length; ++i) { 7815 var result = nodeList[i]; 7816 mark(result, regex); 7817 } 7818 }; 7819 7820 Search.prototype._stepResultFocus = function(reverse) { 7821 var results = this._elements.results.querySelectorAll(selectors.item.self); 7822 var focused = this._elements.results.querySelector(selectors.item.focused); 7823 var newFocused; 7824 var index = Array.prototype.indexOf.call(results, focused); 7825 var focusedCssClass = NS + "-search__item--is-focused"; 7826 7827 if (results.length > 0) { 7828 7829 if (!reverse) { 7830 // highlight the next result 7831 if (index < 0) { 7832 results[0].classList.add(focusedCssClass); 7833 results[0].setAttribute("aria-selected", "true"); 7834 } else if (index + 1 < results.length) { 7835 results[index].classList.remove(focusedCssClass); 7836 results[index].setAttribute("aria-selected", "false"); 7837 results[index + 1].classList.add(focusedCssClass); 7838 results[index + 1].setAttribute("aria-selected", "true"); 7839 } 7840 7841 // if the last visible result is partially hidden, scroll up until it's completely visible 7842 newFocused = this._elements.results.querySelector(selectors.item.focused); 7843 if (newFocused) { 7844 var bottomHiddenHeight = newFocused.offsetTop + newFocused.offsetHeight - this._elements.results.scrollTop - this._elements.results.clientHeight; 7845 if (bottomHiddenHeight > 0) { 7846 this._elements.results.scrollTop += bottomHiddenHeight; 7847 } else { 7848 this._onScroll(); 7849 } 7850 } 7851 7852 } else { 7853 // highlight the previous result 7854 if (index >= 1) { 7855 results[index].classList.remove(focusedCssClass); 7856 results[index].setAttribute("aria-selected", "false"); 7857 results[index - 1].classList.add(focusedCssClass); 7858 results[index - 1].setAttribute("aria-selected", "true"); 7859 } 7860 7861 // if the first visible result is partially hidden, scroll down until it's completely visible 7862 newFocused = this._elements.results.querySelector(selectors.item.focused); 7863 if (newFocused) { 7864 var topHiddenHeight = this._elements.results.scrollTop - newFocused.offsetTop; 7865 if (topHiddenHeight > 0) { 7866 this._elements.results.scrollTop -= topHiddenHeight; 7867 } 7868 } 7869 } 7870 } 7871 }; 7872 7873 Search.prototype._updateResults = function() { 7874 var self = this; 7875 if (self._hasMoreResults) { 7876 var request = new XMLHttpRequest(); 7877 var url = self._action + "?" + serialize(self._elements.form) + "&" + PARAM_RESULTS_OFFSET + "=" + self._resultsOffset; 7878 7879 request.open("GET", url, true); 7880 request.onload = function() { 7881 // when the results are loaded: hide the loading indicator and display the search icon after a minimum period 7882 setTimeout(function() { 7883 toggleShow(self._elements.loadingIndicator, false); 7884 toggleShow(self._elements.icon, true); 7885 }, LOADING_DISPLAY_DELAY); 7886 if (request.status >= 200 && request.status < 400) { 7887 // success status 7888 var data = JSON.parse(request.responseText); 7889 updateSearchResultsStatusMessageElement(self._elements.self.id, data.length); 7890 if (data.length > 0) { 7891 self._generateItems(data, self._elements.results); 7892 self._markResults(); 7893 toggleShow(self._elements.results, true); 7894 self._elements.input.setAttribute("aria-expanded", "true"); 7895 } else { 7896 self._hasMoreResults = false;
7897 } 7898 // the total number of results is not a multiple of the fetched results: 7899 // -> we reached the end of the query 7900 if (self._elements.results.querySelectorAll(selectors.item.self).length % self._properties.resultsSize > 0) { 7901 self._hasMoreResults = false; 7902 } 7903 } else { 7904 // error status 7905 } 7906 }; 7907 // when the results are loading: display the loading indicator and hide the search icon 7908 toggleShow(self._elements.loadingIndicator, true); 7909 toggleShow(self._elements.icon, false); 7910 request.send(); 7911 } 7912 }; 7913 7914 Search.prototype._cancelResults = function() { 7915 clearTimeout(this._timeout); 7916 this._elements.results.scrollTop = 0; 7917 this._resultsOffset = 0; 7918 this._hasMoreResults = true; 7919 this._elements.results.innerHTML = ""; 7920 this._elements.input.setAttribute("aria-expanded", "false"); 7921 this._hideSearchResultsStatusMessage(); 7922 }; 7923 7924 Search.prototype._hideSearchResultsStatusMessage = function() { 7925 var searchResultsStatusMessage = document.querySelector("#" + this._elements.self.id + "> .cmp_search__info"); 7926 searchResultsStatusMessage.style.visibility = "hidden"; 7927 }; 7928 7929 Search.prototype._cacheElements = function(wrapper) { 7930 this._elements = {}; 7931 this._elements.self = wrapper; 7932 var hooks = this._elements.self.querySelectorAll("[data-" + NS + "-hook-" + IS + "]"); 7933 7934 for (var i = 0; i < hooks.length; i++) { 7935 var hook = hooks[i]; 7936 var capitalized = IS; 7937 capitalized = capitalized.charAt(0).toUpperCase() + capitalized.slice(1); 7938 var key = hook.dataset[NS + "Hook" + capitalized]; 7939 this._elements[key] = hook; 7940 } 7941 }; 7942 7943 Search.prototype._setupProperties = function(options) { 7944 this._properties = {}; 7945 7946 for (var key in properties) { 7947 if (Object.prototype.hasOwnProperty.call(properties, key)) { 7948 var property = properties[key]; 7949 if (options && options[key] != null) { 7950 if (property && typeof property.transform === "function") { 7951 this._properties[key] = property.transform(options[key]); 7952 } else { 7953 this._properties[key] = options[key]; 7954 } 7955 } else { 7956 this._properties[key] = properties[key]["default"]; 7957 } 7958 } 7959 } 7960 }; 7961 7962 function onDocumentReady() { 7963 var elements = document.querySelectorAll(selectors.self); 7964 for (var i = 0; i < elements.length; i++) { 7965 new Search({ element: elements[i], options: readData(elements[i]) }); 7966 } 7967 7968 var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver; 7969 var body = document.querySelector("body"); 7970 var observer = new MutationObserver(function(mutations) { 7971 mutations.forEach(function(mutation) { 7972 // needed for IE 7973 var nodesArray = [].slice.call(mutation.addedNodes); 7974 if (nodesArray.length > 0) { 7975 nodesArray.forEach(function(addedNode) { 7976 if (addedNode.querySelectorAll) { 7977 var elementsArray = [].slice.call(addedNode.querySelectorAll(selectors.self)); 7978 elementsArray.forEach(function(element) { 7979 new Search({ element: element, options: readData(element) }); 7980 }); 7981 } 7982 }); 7983 } 7984 }); 7985 }); 7986 7987 observer.observe(body, { 7988 subtree: true, 7989 childList: true, 7990 characterData: true 7991 }); 7992 } 7993 7994 if (document.readyState !== "loading") { 7995 onDocumentReady(); 7996 } else { 7997 document.addEventListener("DOMContentLoaded", onDocumentReady); 7998 } 7999 8000})(); 8001 8002/******************************************************************************* 8003 * Copyright 2016 Adobe 8004 * 8005 * Licensed under the Apache License, Version 2.0 (the "License");
8006 * you may not use this file except in compliance with the License. 8007 * You may obtain a copy of the License at 8008 * 8009 * http://www.apache.org/licenses/LICENSE-2.0 8010 * 8011 * Unless required by applicable law or agreed to in writing, software 8012 * distributed under the License is distributed on an "AS IS" BASIS, 8013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 8014 * See the License for the specific language governing permissions and 8015 * limitations under the License. 8016 ******************************************************************************/ 8017(function() { 8018 "use strict"; 8019 8020 var NS = "cmp"; 8021 var IS = "formText"; 8022 var IS_DASH = "form-text"; 8023 var SELF_SELECTOR = "[data-" + NS + '-is="' + IS + '"]'; 8024 8025 var selectors = { 8026 self: SELF_SELECTOR, 8027 validationMessage: SELF_SELECTOR + " .cmp-form-text__validation-message" 8028 }; 8029 8030 var displayValidationMessage = false; 8031 8032 var properties = { 8033 /** 8034 * A validation message to display if there is a type mismatch between the user input and expected input. 8035 * 8036 * @type {String} 8037 */ 8038 constraintMessage: "", 8039 /** 8040 * A validation message to display if no input is supplied, but input is expected for the field. 8041 * 8042 * @type {String} 8043 */ 8044 requiredMessage: "" 8045 }; 8046 8047 function readData(element) { 8048 var data = element.dataset; 8049 var options = []; 8050 var capitalized = IS; 8051 capitalized = capitalized.charAt(0).toUpperCase() + capitalized.slice(1); 8052 var reserved = ["is", "hook" + capitalized]; 8053 8054 for (var key in data) { 8055 if (Object.prototype.hasOwnProperty.call(data, key)) { 8056 var value = data[key]; 8057 8058 if (key.indexOf(NS) === 0) { 8059 key = key.slice(NS.length); 8060 key = key.charAt(0).toLowerCase() + key.substring(1); 8061 8062 if (reserved.indexOf(key) === -1) { 8063 options[key] = value; 8064 } 8065 } 8066 } 8067 } 8068 8069 return options; 8070 } 8071 8072 function FormText(config) { 8073 if (config.element) { 8074 // prevents multiple initialization 8075 config.element.removeAttribute("data-" + NS + "-is"); 8076 } 8077 8078 this._cacheElements(config.element); 8079 this._setupProperties(config.options); 8080 8081 this._elements.input.addEventListener("invalid", this._onInvalid.bind(this)); 8082 this._elements.input.addEventListener("input", this._onInput.bind(this)); 8083 if (displayValidationMessage) { 8084 this._elements.input.checkValidity(); 8085 } 8086 } 8087 8088 FormText.prototype._onInvalid = function(event) { 8089 event.target.setCustomValidity(""); 8090 if (event.target.validity.typeMismatch) { 8091 if (this._properties.constraintMessage) { 8092 event.target.setCustomValidity(this._properties.constraintMessage); 8093 } 8094 } else if (event.target.validity.valueMissing) { 8095 if (this._properties.requiredMessage) { 8096 event.target.setCustomValidity(this._properties.requiredMessage); 8097 } 8098 } 8099 if (displayValidationMessage) { 8100 var validationMessage = event.target.parentElement.querySelector(".cmp-form-text__validation-message"); 8101 if (validationMessage) { 8102 validationMessage.innerText = event.target.validationMessage; 8103 } 8104 } 8105 }; 8106 8107 FormText.prototype._onInput = function(event) { 8108 event.target.setCustomValidity(""); 8109 if (displayValidationMessage) { 8110 event.target.checkValidity(); 8111 } 8112 }; 8113 8114 FormText.prototype._cacheElements = function(wrapper) { 8115 this._elements = {}; 8116 this._elements.self = wrapper; 8117 var hooks = this._elements.self.querySelectorAll("[data-" + NS + "-hook-" + IS_DASH + "]"); 8118 for (var i = 0; i < hooks.length; i++) { 8119 var hook = hooks[i]; 8120 var capitalized = IS; 8121 capitalized = capitalized.charAt(0).toUpperCase() + capitalized.slice(1); 8122 var key = hook.dataset[NS + "Hook" + capitalized]; 8123 this._elements[key] = hook; 8124 } 8125 }; 8126 8127 FormText.prototype._setupProperties = function(options) { 8128 this._properties = {}; 8129 8130 for (var key in properties) { 8131 if (Object.prototype.hasOwnProperty.call(properties, key)) { 8132 var property = properties[key]; 8133 if (options && options[key] != null) { 8134 if (property && typeof property.transform === "function") { 8135 this._properties[key] = property.transform(options[key]); 8136 } else { 8137 this._properties[key] = options[key]; 8138 } 8139 } else { 8140 this._properties[key] = properties[key]["default"]; 8141 } 8142 } 8143 } 8144 }; 8145 8146 function onDocumentReady() {
8147 var validationMessages = document.querySelectorAll(selectors.validationMessage); 8148 if (validationMessages && validationMessages.length > 0) { 8149 displayValidationMessage = true; 8150 } 8151 8152 var elements = document.querySelectorAll(selectors.self); 8153 for (var i = 0; i < elements.length; i++) { 8154 new FormText({ element: elements[i], options: readData(elements[i]) }); 8155 } 8156 8157 var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver; 8158 var body = document.querySelector("body"); 8159 var observer = new MutationObserver(function(mutations) { 8160 mutations.forEach(function(mutation) { 8161 // needed for IE 8162 var nodesArray = [].slice.call(mutation.addedNodes); 8163 if (nodesArray.length > 0) { 8164 nodesArray.forEach(function(addedNode) { 8165 if (addedNode.querySelectorAll) { 8166 var elementsArray = [].slice.call(addedNode.querySelectorAll(selectors.self)); 8167 elementsArray.forEach(function(element) { 8168 new FormText({ element: element, options: readData(element) }); 8169 }); 8170 } 8171 }); 8172 } 8173 }); 8174 }); 8175 8176 observer.observe(body, { 8177 subtree: true, 8178 childList: true, 8179 characterData: true 8180 }); 8181 } 8182 8183 if (document.readyState !== "loading") { 8184 onDocumentReady(); 8185 } else { 8186 document.addEventListener("DOMContentLoaded", onDocumentReady); 8187 } 8188 8189})(); 8190 8191/******************************************************************************* 8192 * Copyright 2016 Adobe 8193 * 8194 * Licensed under the Apache License, Version 2.0 (the "License"); 8195 * you may not use this file except in compliance with the License. 8196 * You may obtain a copy of the License at 8197 * 8198 * http://www.apache.org/licenses/LICENSE-2.0 8199 * 8200 * Unless required by applicable law or agreed to in writing, software 8201 * distributed under the License is distributed on an "AS IS" BASIS, 8202 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 8203 * See the License for the specific language governing permissions and 8204 * limitations under the License. 8205 ******************************************************************************/ 8206(function() { 8207 "use strict"; 8208 8209 var NS = "cmp"; 8210 var IS = "formText"; 8211 var IS_DASH = "form-text"; 8212 8213 var selectors = { 8214 self: "[data-" + NS + '-is="' + IS + '"]' 8215 }; 8216 8217 var properties = { 8218 /** 8219 * A validation message to display if there is a type mismatch between the user input and expected input. 8220 * 8221 * @type {String} 8222 */ 8223 constraintMessage: "", 8224 /** 8225 * A validation message to display if no input is supplied, but input is expected for the field. 8226 * 8227 * @type {String} 8228 */ 8229 requiredMessage: "" 8230 }; 8231 8232 function readData(element) { 8233 var data = element.dataset; 8234 var options = []; 8235 var capitalized = IS; 8236 capitalized = capitalized.charAt(0).toUpperCase() + capitalized.slice(1); 8237 var reserved = ["is", "hook" + capitalized]; 8238 8239 for (var key in data) { 8240 if (Object.prototype.hasOwnProperty.call(data, key)) { 8241 var value = data[key]; 8242 8243 if (key.indexOf(NS) === 0) { 8244 key = key.slice(NS.length); 8245 key = key.charAt(0).toLowerCase() + key.substring(1); 8246 8247 if (reserved.indexOf(key) === -1) { 8248 options[key] = value; 8249 } 8250 } 8251 } 8252 } 8253 8254 return options; 8255 } 8256 8257 function FormText(config) { 8258 if (config.element) { 8259 // prevents multiple initialization 8260 config.element.removeAttribute("data-" + NS + "-is"); 8261 } 8262 8263 this._cacheElements(config.element); 8264 this._setupProperties(config.options); 8265 8266 this._elements.input.addEventListener("invalid", this._onInvalid.bind(this)); 8267 this._elements.input.addEventListener("input", this._onInput.bind(this)); 8268 } 8269 8270 FormText.prototype._onInvalid = function(event) { 8271 event.target.setCustomValidity(""); 8272 if (event.target.validity.typeMismatch) { 8273 if (this._properties.constraintMessage) { 8274 event.target.setCustomValidity(this._properties.constraintMessage); 8275 } 8276 } else if (event.target.validity.valueMissing) { 8277 if (this._properties.requiredMessage) { 8278 event.target.setCustomValidity(this._properties.requiredMessage); 8279 } 8280 } 8281 }; 8282 8283 FormText.prototype._onInput = function(event) { 8284 event.target.setCustomValidity(""); 8285 }; 8286 8287 FormText.prototype._cacheElements = function(wrapper) { 8288 this._elements = {}; 8289 this._elements.self = wrapper; 8290 var hooks = this._elements.self.querySelectorAll("[data-" + NS + "-hook-" + IS_DASH + "]"); 8291 for (var i = 0; i < hooks.length; i++) { 8292 var hook = hooks[i]; 8293 var capitalized = IS; 8294 capitalized = capitalized.charAt(0).toUpperCase() + capitalized.slice(1); 8295 var key = hook.dataset[NS + "Hook" + capitalized]; 8296 this._elements[key] = hook; 8297 } 8298 }; 8299 8300 FormText.prototype._setupProperties = function(options) { 8301 this._properties = {}; 8302 8303 for (var key in properties) { 8304 if (Object.prototype.hasOwnProperty.call(properties, key)) { 8305 var property = properties[key]; 8306 if (options && options[key] != null) { 8307 if (property && typeof property.transform === "function") { 8308 this._properties[key] = property.transform(options[key]); 8309 } else { 8310 this._properties[key] = options[key]; 8311 } 8312 } else { 8313 this._properties[key] = properties[key]["default"]; 8314 } 8315 } 8316 } 8317 }; 8318 8319 function onDocumentReady() { 8320 var elements = document.querySelectorAll(selectors.self); 8321 for (var i = 0; i < elements.length; i++) { 8322 new FormText({ element: elements[i], options: readData(elements[i]) }); 8323 } 8324 8325 var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver; 8326 var body = document.querySelector("body"); 8327 var observer = new MutationObserver(function(mutations) { 8328 mutations.forEach(function(mutation) { 8329 // needed for IE 8330 var nodesArray = [].slice.call(mutation.addedNodes); 8331 if (nodesArray.length > 0) { 8332 nodesArray.forEach(function(addedNode) { 8333 if (addedNode.querySelectorAll) { 8334 var elementsArray = [].slice.call(addedNode.querySelectorAll(selectors.self)); 8335 elementsArray.forEach(function(element) { 8336 new FormText({ element: element, options: readData(element) }); 8337 }); 8338 } 8339 }); 8340 } 8341 }); 8342 }); 8343 8344 observer.observe(body, { 8345 subtree: true, 8346 childList: true, 8347 characterData: true 8348 }); 8349 } 8350 8351 if (document.readyState !== "loading") { 8352 onDocumentReady(); 8353 } else { 8354 document.addEventListener("DOMContentLoaded", onDocumentReady); 8355 } 8356 8357})(); 8358 8359/******************************************************************************* 8360 * Copyright 2016 Adobe 8361 * 8362 * Licensed under the Apache License, Version 2.0 (the "License");
8363 * you may not use this file except in compliance with the License. 8364 * You may obtain a copy of the License at 8365 * 8366 * http://www.apache.org/licenses/LICENSE-2.0 8367 * 8368 * Unless required by applicable law or agreed to in writing, software 8369 * distributed under the License is distributed on an "AS IS" BASIS, 8370 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 8371 * See the License for the specific language governing permissions and 8372 * limitations under the License. 8373 ******************************************************************************/ 8374(function() { 8375 "use strict"; 8376 8377 var NS = "cmp"; 8378 var IS = "formText"; 8379 var IS_DASH = "form-text"; 8380 8381 var selectors = { 8382 self: "[data-" + NS + '-is="' + IS + '"]' 8383 }; 8384 8385 var properties = { 8386 /** 8387 * A validation message to display if there is a type mismatch between the user input and expected input. 8388 * 8389 * @type {String} 8390 */ 8391 constraintMessage: "", 8392 /** 8393 * A validation message to display if no input is supplied, but input is expected for the field. 8394 * 8395 * @type {String} 8396 */ 8397 requiredMessage: "" 8398 }; 8399 8400 function readData(element) { 8401 var data = element.dataset; 8402 var options = []; 8403 var capitalized = IS; 8404 capitalized = capitalized.charAt(0).toUpperCase() + capitalized.slice(1); 8405 var reserved = ["is", "hook" + capitalized]; 8406 8407 for (var key in data) { 8408 if (Object.prototype.hasOwnProperty.call(data, key)) { 8409 var value = data[key]; 8410 8411 if (key.indexOf(NS) === 0) { 8412 key = key.slice(NS.length); 8413 key = key.charAt(0).toLowerCase() + key.substring(1); 8414 8415 if (reserved.indexOf(key) === -1) { 8416 options[key] = value; 8417 } 8418 } 8419 } 8420 } 8421 8422 return options; 8423 } 8424 8425 function FormText(config) { 8426 if (config.element) { 8427 // prevents multiple initialization 8428 config.element.removeAttribute("data-" + NS + "-is"); 8429 } 8430 8431 this._cacheElements(config.element); 8432 this._setupProperties(config.options); 8433 8434 this._elements.input.addEventListener("invalid", this._onInvalid.bind(this)); 8435 this._elements.input.addEventListener("input", this._onInput.bind(this)); 8436 } 8437 8438 FormText.prototype._onInvalid = function(event) { 8439 event.target.setCustomValidity(""); 8440 if (event.target.validity.typeMismatch) { 8441 if (this._properties.constraintMessage) { 8442 event.target.setCustomValidity(this._properties.constraintMessage); 8443 } 8444 } else if (event.target.validity.valueMissing) { 8445 if (this._properties.requiredMessage) { 8446 event.target.setCustomValidity(this._properties.requiredMessage); 8447 } 8448 } 8449 }; 8450 8451 FormText.prototype._onInput = function(event) { 8452 event.target.setCustomValidity(""); 8453 }; 8454 8455 FormText.prototype._cacheElements = function(wrapper) { 8456 this._elements = {}; 8457 this._elements.self = wrapper; 8458 var hooks = this._elements.self.querySelectorAll("[data-" + NS + "-hook-" + IS_DASH + "]"); 8459 for (var i = 0; i < hooks.length; i++) { 8460 var hook = hooks[i]; 8461 var capitalized = IS; 8462 capitalized = capitalized.charAt(0).toUpperCase() + capitalized.slice(1); 8463 var key = hook.dataset[NS + "Hook" + capitalized]; 8464 this._elements[key] = hook; 8465 } 8466 }; 8467 8468 FormText.prototype._setupProperties = function(options) { 8469 this._properties = {}; 8470 8471 for (var key in properties) { 8472 if (Object.prototype.hasOwnProperty.call(properties, key)) { 8473 var property = properties[key]; 8474 if (options && options[key] != null) { 8475 if (property && typeof property.transform === "function") { 8476 this._properties[key] = property.transform(options[key]); 8477 } else { 8478 this._properties[key] = options[key]; 8479 } 8480 } else { 8481 this._properties[key] = properties[key]["default"]; 8482 } 8483 } 8484 } 8485 }; 8486 8487 function onDocumentReady() { 8488 var elements = document.querySelectorAll(selectors.self); 8489 for (var i = 0; i < elements.length; i++) { 8490 new FormText({ element: elements[i], options: readData(elements[i]) }); 8491 } 8492 8493 var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver; 8494 var body = document.querySelector("body"); 8495 var observer = new MutationObserver(function(mutations) { 8496 mutations.forEach(function(mutation) { 8497 // needed for IE 8498 var nodesArray = [].slice.call(mutation.addedNodes); 8499 if (nodesArray.length > 0) { 8500 nodesArray.forEach(function(addedNode) { 8501 if (addedNode.querySelectorAll) { 8502 var elementsArray = [].slice.call(addedNode.querySelectorAll(selectors.self)); 8503 elementsArray.forEach(function(element) { 8504 new FormText({ element: element, options: readData(element) }); 8505 }); 8506 } 8507 }); 8508 } 8509 }); 8510 }); 8511 8512 observer.observe(body, { 8513 subtree: true, 8514 childList: true, 8515 characterData: true 8516 }); 8517 } 8518 8519 if (document.readyState !== "loading") { 8520 onDocumentReady(); 8521 } else { 8522 document.addEventListener("DOMContentLoaded", onDocumentReady); 8523 } 8524 8525})(); 8526 8527/******************************************************************************* 8528 * Copyright 2020 Adobe 8529 * 8530 * Licensed under the Apache License, Version 2.0 (the "License");
8531 * you may not use this file except in compliance with the License. 8532 * You may obtain a copy of the License at 8533 * 8534 * http://www.apache.org/licenses/LICENSE-2.0 8535 * 8536 * Unless required by applicable law or agreed to in writing, software 8537 * distributed under the License is distributed on an "AS IS" BASIS, 8538 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 8539 * See the License for the specific language governing permissions and 8540 * limitations under the License. 8541 ******************************************************************************/ 8542(function() { 8543 "use strict"; 8544 8545 var NS = "cmp"; 8546 var IS = "pdfviewer"; 8547 var SDK_URL = "https://acrobatservices.adobe.com/view-sdk/viewer.js"; 8548 var SDK_READY_EVENT = "adobe_dc_view_sdk.ready"; 8549 8550 var selectors = { 8551 self: "[data-" + NS + '-is="' + IS + '"]', 8552 sdkScript: 'script[src="' + SDK_URL + '"]' 8553 }; 8554 8555 function initSDK() { 8556 var sdkIncluded = document.querySelectorAll(selectors.sdkScript).length > 0; 8557 if (!window.adobe_dc_view_sdk && !sdkIncluded) { 8558 var dcv = document.createElement("script"); 8559 dcv.type = "text/javascript"; 8560 dcv.src = SDK_URL; 8561 document.body.appendChild(dcv); 8562 } 8563 } 8564 8565 function previewPdf(component) { 8566 // prevents multiple initialization 8567 component.removeAttribute("data-" + NS + "-is"); 8568 8569 // add the view sdk to the page 8570 initSDK(); 8571 8572 // manage the preview 8573 if (component.dataset && component.id) { 8574 if (window.AdobeDC && window.AdobeDC.View) { 8575 dcView(component); 8576 } else { 8577 document.addEventListener(SDK_READY_EVENT, function() { 8578 dcView(component); 8579 }); 8580 } 8581 } 8582 } 8583 8584 function dcView(component) { 8585 var adobeDCView = new window.AdobeDC.View({ 8586 clientId: component.dataset.cmpClientId, 8587 divId: component.id + "-content", 8588 reportSuiteId: component.dataset.cmpReportSuiteId, 8589 locale: typeof Granite !== "undefined" && Granite && Granite.I18n ? Granite.I18n.getLocale() : navigator.language || navigator.userLanguage 8590 }); 8591 adobeDCView.previewFile({ 8592 content: { location: { url: component.dataset.cmpDocumentPath } }, 8593 metaData: { fileName: component.dataset.cmpDocumentFileName } 8594 }, JSON.parse(component.dataset.cmpViewerConfigJson)); 8595 } 8596 8597 /** 8598 * Document ready handler and DOM mutation observers. Initializes Accordion components as necessary. 8599 * 8600 * @private 8601 */ 8602 function onDocumentReady() { 8603 var elements = document.querySelectorAll(selectors.self); 8604 for (var i = 0; i < elements.length; i++) { 8605 previewPdf(elements[i]); 8606 } 8607 8608 var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver; 8609 var body = document.querySelector("body"); 8610 var observer = new MutationObserver(function(mutations) { 8611 mutations.forEach(function(mutation) { 8612 // needed for IE 8613 var nodesArray = [].slice.call(mutation.addedNodes); 8614 if (nodesArray.length > 0) { 8615 nodesArray.forEach(function(addedNode) { 8616 if (addedNode.querySelectorAll) { 8617 var elementsArray = [].slice.call(addedNode.querySelectorAll(selectors.self)); 8618 elementsArray.forEach(function(element) { 8619 previewPdf(element); 8620 }); 8621 } 8622 }); 8623 } 8624 }); 8625 }); 8626 8627 observer.observe(body, { 8628 subtree: true, 8629 childList: true, 8630 characterData: true 8631 }); 8632 8633 } 8634 8635 if (document.readyState !== "loading") { 8636 onDocumentReady(); 8637 } else { 8638 document.addEventListener("DOMContentLoaded", onDocumentReady); 8639 } 8640}()); 8641 8642/******************************************************************************* 8643 * Copyright 2022 Adobe 8644 * 8645 * Licensed under the Apache License, Version 2.0 (the "License");
8646 * you may not use this file except in compliance with the License. 8647 * You may obtain a copy of the License at 8648 * 8649 * http://www.apache.org/licenses/LICENSE-2.0 8650 * 8651 * Unless required by applicable law or agreed to in writing, software 8652 * distributed under the License is distributed on an "AS IS" BASIS, 8653 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 8654 * See the License for the specific language governing permissions and 8655 * limitations under the License. 8656 ******************************************************************************/ 8657(function() { 8658 "use strict"; 8659 8660 var dataLayerEnabled; 8661 var dataLayer; 8662 var dataLayerName; 8663 8664 /** 8665 * Adds Click Event Listener to the main <div> of the Text Components 8666 */ 8667 function addClickEventListenerToTextComponents() { 8668 var componentMainDivs = document.getElementsByClassName("cmp-text"); 8669 8670 for (var i = 0; i < componentMainDivs.length; i++) { 8671 componentMainDivs[i].addEventListener("click", addClickedLinkToDataLayer); 8672 } 8673 } 8674 8675 /** 8676 * Adds clicked link contained by the Text Component to Data Layer 8677 * 8678 * @private 8679 * @param {Object} event The Click event 8680 */ 8681 function addClickedLinkToDataLayer(event) { 8682 var element = event.currentTarget; 8683 var componentId = getDataLayerId(element); 8684 8685 if (event.target.tagName === "A") { 8686 dataLayer.push({ 8687 event: "cmp:click", 8688 eventInfo: { 8689 path: "component." + componentId, 8690 link: event.target.getAttribute("href") 8691 } 8692 }); 8693 } 8694 } 8695 8696 /** 8697 * Parses the dataLayer string and returns the ID 8698 * 8699 * @private 8700 * @param {HTMLElement} item, the Text item 8701 * @returns {String} dataLayerId or undefined 8702 */ 8703 function getDataLayerId(item) { 8704 if (item) { 8705 if (item.dataset.cmpDataLayer) { 8706 return Object.keys(JSON.parse(item.dataset.cmpDataLayer))[0]; 8707 } else { 8708 return item.id; 8709 } 8710 } 8711 return null; 8712 } 8713 8714 function onDocumentReady() { 8715 dataLayerEnabled = document.body.hasAttribute("data-cmp-data-layer-enabled"); 8716 if (dataLayerEnabled) { 8717 dataLayerName = document.body.getAttribute("data-cmp-data-layer-name") || "adobeDataLayer"; 8718 dataLayer = window[dataLayerName] = window[dataLayerName] || []; 8719 8720 addClickEventListenerToTextComponents(); 8721 } 8722 } 8723 8724 if (document.readyState !== "loading") { 8725 onDocumentReady(); 8726 } else { 8727 document.addEventListener("DOMContentLoaded", onDocumentReady); 8728 } 8729})(); 8730 8731/******************************************************************************* 8732 * Copyright 2022 Adobe 8733 * 8734 * Licensed under the Apache License, Version 2.0 (the "License"); 8735 * you may not use this file except in compliance with the License. 8736 * You may obtain a copy of the License at 8737 * 8738 * http://www.apache.org/licenses/LICENSE-2.0 8739 * 8740 * Unless required by applicable law or agreed to in writing, software 8741 * distributed under the License is distributed on an "AS IS" BASIS, 8742 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 8743 * See the License for the specific language governing permissions and 8744 * limitations under the License. 8745 ******************************************************************************/ 8746(function() { 8747 "use strict"; 8748 8749 var linkAccessibilityClass = "cmp-link__screen-reader-only"; 8750 var selectors = { 8751 linkAccessibility: "." + linkAccessibilityClass, 8752 linkAccessibilityEnabled: "[data-cmp-link-accessibility-enabled]", 8753 linkAccessibilityText: "[data-cmp-link-accessibility-text]" 8754 }; 8755 8756 function getLinkAccessibilityText() { 8757 var linkAccessibilityEnabled = document.querySelectorAll(selectors.linkAccessibilityEnabled); 8758 if (!linkAccessibilityEnabled[0]) { 8759 return; 8760 } 8761 var linkAccessibilityTextElements = document.querySelectorAll(selectors.linkAccessibilityText); 8762 if (!linkAccessibilityTextElements[0]) { 8763 return; 8764 } 8765 return linkAccessibilityTextElements[0].dataset.cmpLinkAccessibilityText; 8766 } 8767 8768 function onDocumentReady() { 8769 var linkAccessibilityText = getLinkAccessibilityText(); 8770 if (linkAccessibilityText) { 8771 document.querySelectorAll("a[target='_blank']").forEach(function(link) { 8772 if (!link.querySelector(selectors.linkAccessibility)) { 8773 var linkAccessibilityElement = document.createElement("span"); 8774 linkAccessibilityElement.classList.add(linkAccessibilityClass); 8775 linkAccessibilityElement.innerText = linkAccessibilityText; 8776 link.insertAdjacentElement("beforeend", linkAccessibilityElement); 8777 } 8778 }); 8779 } 8780 } 8781 8782 if (document.readyState !== "loading") { 8783 onDocumentReady(); 8784 } else { 8785 document.addEventListener("DOMContentLoaded", onDocumentReady); 8786 } 8787 8788}()); 8789 8790/******************************************************************************* 8791 * Copyright 2020 Adobe 8792 * 8793 * Licensed under the Apache License, Version 2.0 (the "License");
8794 * you may not use this file except in compliance with the License. 8795 * You may obtain a copy of the License at 8796 * 8797 * http://www.apache.org/licenses/LICENSE2.0 8798 * 8799 * Unless required by applicable law or agreed to in writing, software 8800 * distributed under the License is distributed on an "AS IS" BASIS, 8801 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 8802 * See the License for the specific language governing permissions and 8803 * limitations under the License. 8804 ******************************************************************************/ 8805 8806/** 8807 * Element.matches() 8808 * https://developer.mozilla.org/enUS/docs/Web/API/Element/matches#Polyfill 8809 */ 8810if (!Element.prototype.matches) { 8811 Element.prototype.matches = Element.prototype.msMatchesSelector || Element.prototype.webkitMatchesSelector; 8812} 8813 8814// eslint-disable-next-line valid-jsdoc 8815/** 8816 * Element.closest() 8817 * https://developer.mozilla.org/enUS/docs/Web/API/Element/closest#Polyfill 8818 */ 8819if (!Element.prototype.closest) { 8820 Element.prototype.closest = function(s) { 8821 "use strict"; 8822 var el = this; 8823 if (!document.documentElement.contains(el)) { 8824 return null; 8825 } 8826 do { 8827 if (el.matches(s)) { 8828 return el; 8829 } 8830 el = el.parentElement || el.parentNode; 8831 } while (el !== null && el.nodeType === 1); 8832 return null; 8833 }; 8834} 8835 8836// https://tc39.github.io/ecma262/#sec-array.prototype.find 8837if (!Array.prototype.find) { 8838 Object.defineProperty(Array.prototype, "find", { 8839 value: function(predicate) { 8840 "use strict"; 8841 // 1. Let O be ? ToObject(this value). 8842 if (this == null) { 8843 throw TypeError('"this" is null or not defined'); 8844 } 8845 8846 var o = Object(this); 8847 8848 // 2. Let len be ? ToLength(? Get(O, "length")). 8849 var len = o.length >>> 0; 8850 8851 // 3. If IsCallable(predicate) is false, throw a TypeError exception. 8852 if (typeof predicate !== "function") { 8853 throw TypeError("predicate must be a function"); 8854 } 8855 8856 // 4. If thisArg was supplied, let T be thisArg; else let T be undefined. 8857 var thisArg = arguments[1]; 8858 8859 // 5. Let k be 0. 8860 var k = 0; 8861 8862 // 6. Repeat, while k < len 8863 while (k < len) { 8864 // a. Let Pk be ! ToString(k). 8865 // b. Let kValue be ? Get(O, Pk). 8866 // c. Let testResult be ToBoolean(? Call(predicate, T, « kValue, k, O »)). 8867 // d. If testResult is true, return kValue. 8868 var kValue = o[k]; 8869 if (predicate.call(thisArg, kValue, k, o)) { 8870 return kValue; 8871 } 8872 // e. Increase k by 1. 8873 k++; 8874 } 8875 8876 // 7. Return undefined. 8877 return undefined; 8878 }, 8879 configurable: true, 8880 writable: true 8881 }); 8882} 8883 8884"use strict";function _slicedToArray(t,e){return _arrayWithHoles(t)||_iterableToArrayLimit(t,e)||_unsupportedIterableToArray(t,e)||_nonIterableRest()}function _nonIterableRest(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function _iterableToArrayLimit(t,e){if("undefined"!=typeof Symbol&&Symbol.iterator in Object(t)){var n=[],r=!0,o=!1,a=void 0;try{for(var i,u=t[Symbol.iterator]();!(r=(i=u.next()).done)&&(n.push(i.value),!e||n.length!==e);r=!0);}catch(t){o=!0,a=t}finally{try{r||null==u.return||u.return()}finally{if(o)throw a}}return n}}function _arrayWithHoles(t){if(Array.isArray(t))return t}function _createForOfIteratorHelper(t){if("undefined"==typeof Symbol||null==t[Symbol.iterator]){if(Array.isArray(t)||(t=_unsupportedIterableToArray(t))){var e=0,n=function(){};return{s:n,n:function(){return e>=t.length?{done:!0}:{done:!1,value:t[e++]}},e:function(t){throw t},f:n}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var r,o,a=!0,i=!1;return{s:function(){r=t[Symbol.iterator]()},n:function(){var t=r.next();return a=t.done,t},e:function(t){i=!0,o=t},f:function(){try{a||null==r.return||r.return()}finally{if(i)throw o}}}}function _unsupportedIterableToArray(t,e){if(t){if("string"==typeof t)return _arrayLikeToArray(t,e);var n=Object.prototype.toString.call(t).slice(8,-1);return"Object"===n&&t.constructor&&(n=t.constructor.name),"Map"===n||"Set"===n?Array.from(n):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?_arrayLikeToArray(t,e):void 0}}function _arrayLikeToArray(t,e){(null==e||e>t.length)&&(e=t.length);for(var n=0,r=new Array(e);n<e;n++)r[n]=t[n];return r}function _typeof(t){return(_typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}!function a(i,u,c){function f(e,t){if(!u[e]){if(!i[e]){var n="function"==typeof require&&require;if(!t&&n)return n(e,!0);if(s)return s(e,!0);var r=new Error("Cannot find module '"+e+"'");throw r.code="MODULE_NOT_FOUND",r}var o=u[e]={exports:{}};i[e][0].call(o.exports,function(t){return f(i[e][1][t]||t)},o,o.exports,a,i,u,c)}return u[e].exports}for(var s="function"==typeof require&&require,t=0;t<c.length;t++)f(c[t]);return f}({1:[function(t,wn,En){(function(On){(function(){function n(t,e){for(var n=-1,r=null==t?0:t.length,o=0,a=[];++n<r;){var i=t[n];e(i,n,t)&&(a[o++]=i)}return a}function a(t,e){for(var n=-1,r=null==t?0:t.length,o=Array(r);++n<r;)o[n]=e(t[n],n,t);return o}function f(t,e){for(var n=-1,r=e.length,o=t.length;++n<r;)t[o+n]=e[n];return t}function b(t,e){for(var n=-1,r=null==t?0:t.length;++n<r;)if(e(t[n],n,t))return!0;return!1}function o(t,e,n){var r=t.length;for(n+=-1;++n<r;)if(e(t[n],n,t))return n;return-1}function i(t){return t!=t}function t(e){return function(t){return e(t)}}function h(t){var n=-1,r=Array(t.size);return t.forEach(function(t,e){r[++n]=[e,t]}),r}function e(e){var n=Object;return function(t){return e(n(t))}}function v(t){var e=-1,n=Array(t.size);return t.forEach(function(t){n[++e]=t}),n}function r(){}function u(t){var e=-1,n=null==t?0:t.length;for(this.clear();++e<n;){var r=t[e];this.set(r[0],r[1])}}function c(t){var e=-1,n=null==t?0:t.length;for(this.clear();++e<n;){var r=t[e];this.set(r[0],r[1])}}function s(t){var e=-1,n=null==t?0:t.length;for(this.clear();++e<n;){var r=t[e];this.set(r[0],r[1])}}function d(t){var e=-1,n=null==t?0:t.length;for(this.__data__=new s;++e<n;)this.add(t[e])}function g(t){this.size=(this.__data__=new c(t)).size}function l(t,e){var n=hn(t),r=!n&&bn(t),o=!n&&!r&&vn(t),a=!n&&!r&&!o&&_n(t);if(n=n||r||o||a){r=t.length;for(var i=String,u=-1,c=Array(r);++u<r;)c[u]=i(u);r=c}else r=[];var f;i=r.length;for(f in t)!e&&!be.call(t,f)||n&&("length"==f||o&&("offset"==f||"parent"==f)||a&&("buffer"==f||"byteLength"==f||"byteOffset"==f)||Q(f,i))||r.push(f);return r}function _(t,e,n){(n===Mt||ft(t[e],n))&&(n!==Mt||e in t)||j(t,e,n)}function y(t,e,n){var r=t[e];be.call(t,e)&&ft(r,n)&&(n!==Mt||e in t)||j(t,e,n)}function p(t,e){for(var n=t.length;n--;)if(ft(t[n][0],e))return n;return-1}function j(t,e,n){"__proto__"==e&&xe?xe(t,e,{configurable:!0,enumerable:!0,value:n,writable:!0}):t[e]=n}function m(n,r,o,t,e,a){var i,u=1&r,c=2&r,f=4&r;
8884if(o&&(i=e?o(n,t,e,a):o(n)),i!==Mt)return i;if(!bt(n))return n;if(t=hn(n)){if(i=function(t){var e=t.length,n=new t.constructor(e);return e&&"string"==typeof t[0]&&be.call(t,"index")&&(n.index=t.index,n.input=t.input),n}(n),!u)return U(n,i)}else{var s=nn(n),l="[object Function]"==s||"[object GeneratorFunction]"==s;if(vn(n))return M(n,u);if("[object Object]"==s||"[object Arguments]"==s||l&&!e){if(i=c||l?{}:Y(n),!u)return c?function(t,e){return P(t,en(t),e)}(n,function(t,e){return t&&P(e,St(e),t)}(i,n)):function(t,e){return P(t,tn(t),e)}(n,function(t,e){return t&&P(e,Lt(e),t)}(i,n))}else{if(!Kt[s])return e?n:{};i=function(t,e,n){var r=t.constructor;switch(e){case"[object ArrayBuffer]":return z(t);case"[object Boolean]":case"[object Date]":return new r(+t);case"[object DataView]":return e=n?z(t.buffer):t.buffer,new t.constructor(e,t.byteOffset,t.byteLength);case"[object Float32Array]":case"[object Float64Array]":case"[object Int8Array]":case"[object Int16Array]":case"[object Int32Array]":case"[object Uint8Array]":case"[object Uint8ClampedArray]":case"[object Uint16Array]":case"[object Uint32Array]":return C(t,n);case"[object Map]":return new r;case"[object Number]":case"[object String]":return new r(t);case"[object RegExp]":return(e=new t.constructor(t.source,Ht.exec(t))).lastIndex=t.lastIndex,e;case"[object Set]":return new r;case"[object Symbol]":return qe?Object(qe.call(t)):{}}}(n,s,u)}}if(e=(a=a||new g).get(n))return e;if(a.set(n,i),gn(n))return n.forEach(function(t){i.add(m(t,r,o,t,n,a))}),i;if(dn(n))return n.forEach(function(t,e){i.set(e,m(t,r,o,e,n,a))}),i;c=f?c?B:H:c?St:Lt;var p=t?Mt:c(n);return function(t,e){for(var n=-1,r=null==t?0:t.length;++n<r&&!1!==e(t[n],n,t););}(p||n,function(t,e){p&&(t=n[e=t]),y(i,e,m(t,r,o,e,n,a))}),i}function A(t,e){for(var n=0,r=(e=F(e,t)).length;null!=t&&n<r;)t=t[nt(e[n++])];return n&&n==r?t:Mt}function O(t,e,n){return e=e(t),hn(t)?e:f(e,n(t))}function w(t){if(null==t)t=t===Mt?"[object Undefined]":"[object Null]";else if(Te&&Te in Object(t)){var e=be.call(t,Te),n=t[Te];try{t[Te]=Mt;var r=!0}catch(t){}var o=ve.call(t);r&&(e?t[Te]=n:delete t[Te]),t=o}else t=ve.call(t);return t}function E(t,e){return null!=t&&be.call(t,e)}function L(t,e){return null!=t&&e in Object(t)}function S(t){return ht(t)&&"[object Arguments]"==w(t)}function T(t,e,n,r,o){if(t===e)e=!0;else if(null==t||null==e||!ht(t)&&!ht(e))e=t!=t&&e!=e;else t:{var a,i,u=hn(t),c=hn(e),f="[object Object]"==(a="[object Arguments]"==(a=u?"[object Array]":nn(t))?"[object Object]":a);c="[object Object]"==(i="[object Arguments]"==(i=c?"[object Array]":nn(e))?"[object Object]":i);if((i=a==i)&&vn(t)){if(!vn(e)){e=!1;break t}f=!(u=!0)}if(i&&!f)o=o||new g,e=u||_n(t)?V(t,e,n,r,T,o):function(t,e,n,r,o,a,i){switch(n){case"[object DataView]":if(t.byteLength!=e.byteLength||t.byteOffset!=e.byteOffset)break;t=t.buffer,e=e.buffer;case"[object ArrayBuffer]":if(t.byteLength!=e.byteLength||!a(new me(t),new me(e)))break;return!0;case"[object Boolean]":case"[object Date]":case"[object Number]":return ft(+t,+e);case"[object Error]":return t.name==e.name&&t.message==e.message;case"[object RegExp]":case"[object String]":return t==e+"";case"[object Map]":var u=h;case"[object Set]":if(u=u||v,t.size!=e.size&&!(1&r))break;return(n=i.get(t))?n==e:(r|=2,i.set(t,e),e=V(u(t),u(e),r,o,a,i),i.delete(t),e);case"[object Symbol]":if(qe)return qe.call(t)==qe.call(e)}return!1}(t,e,a,n,r,T,o);else{if(!(1&n)&&(u=f&&be.call(t,"__wrapped__"),a=c&&be.call(e,"__wrapped__"),u||a)){e=T(t=u?t.value():t,e=a?e.value():e,n,r,o=o||new g);break t}if(i)e:if(o=o||new g,u=1&n,a=H(t),c=a.length,i=H(e).length,c==i||u){for(f=c;f--;){var s=a[f];if(!(u?s in e:be.call(e,s))){e=!1;break e}}if((i=o.get(t))&&o.get(e))e=i==e;else{i=!0,o.set(t,e),o.set(e,t);for(var l=u;++f<c;){var p=t[s=a[f]],y=e[s];if(r)var b=u?r(y,p,s,e,t,o):r(p,y,s,t,e,o);if(b===Mt?p!==y&&!T(p,y,n,r,o):!b){i=!1;break}l=l||"constructor"==s}i&&!l&&((n=t.constructor)!=(r=e.constructor)&&"constructor"in t&&"constructor"in e&&!("function"==typeof n&&n instanceof n&&"function"==typeof r&&r instanceof r)&&(i=!1)),o.delete(t),o.delete(e),e=i}}else e=!1;else e=!1}}return e}function x(t){return"function"==typeof t?t:null==t?It:"object"==_typeof(t)?hn(t)?function(n,r){return X(n)&&r==r&&!bt(r)?tt(nt(n),r):function(t){var e=wt(t,n);return e===Mt&&e===r?Et(t,n):T(r,e,3)}}(t[0],t[1]):function(e){var n=function(t){for(var e=Lt(t),n=e.length;n--;){var r=e[n],o=t[r];e[n]=[r,o,o==o&&!bt(o)]}return e}(e);return 1==n.length&&n[0][2]?tt(n[0][0],n[0][1]):function(t){return t===e||function(t,e){var n=e.length,r=n;if(null==t)return!r;for(t=Object(t);n--;){if((o=e[n])[2]?o[1]!==t[o[0]]:!(o[0]in t))return!1}for(;++n<r;
8884){var o,a=(o=e[n])[0],i=t[a],u=o[1];if(o[2]){if(i===Mt&&!(a in t))return!1}else if(o=new g,void 0!==Mt||!T(u,i,3,void 0,o))return!1}return!0}(t,n)}}(t):Nt(t)}function I(t){if(!Z(t))return Ne(t);var e,n=[];for(e in Object(t))be.call(t,e)&&"constructor"!=e&&n.push(e);return n}function k(s,l,p,y,b){s!==l&&Xe(l,function(t,e){if(bt(t)){var n=b=b||new g,r="__proto__"==e?Mt:s[e],o="__proto__"==e?Mt:l[e];if(f=n.get(o))_(s,e,f);else{var a=(f=y?y(r,o,e+"",s,l,n):Mt)===Mt;if(a){var i=hn(o),u=!i&&vn(o),c=!i&&!u&&_n(o),f=o;i||u||c?f=hn(r)?r:lt(r)?U(r):u?M(o,!(a=!1)):c?C(o,!(a=!1)):[]:vt(o)||bn(o)?bn(f=r)?f=At(r):(!bt(r)||p&&pt(r))&&(f=Y(o)):a=!1}a&&(n.set(o,f),k(f,o,p,y,n),n.delete(o)),_(s,e,f)}}else(n=y?y("__proto__"==e?Mt:s[e],t,e+"",s,l,b):Mt)===Mt&&(n=t),_(s,e,n)},St)}function N(t){if("string"==typeof t)return t;if(hn(t))return a(t,N)+"";if(gt(t))return Je?Je.call(t):"";var e=t+"";return"0"==e&&1/t==-zt?"-0":e}function D(t,e){var n;if((e=F(e,t)).length<2)n=t;else{var r=0,o=-1,a=-1,i=(n=e).length;for(r<0&&(r=i<-r?0:i+r),(o=i<o?i:o)<0&&(o+=i),i=o<r?0:o-r>>>0,r>>>=0,o=Array(i);++a<i;)o[a]=n[a+r];n=A(t,o)}null==(t=n)||delete t[nt(it(e))]}function F(t,e){return hn(t)?t:X(t,e)?[t]:ln(Ot(t))}function M(t,e){if(e)return t.slice();var n=t.length;n=Ae?Ae(n):new t.constructor(n);return t.copy(n),n}function z(t){var e=new t.constructor(t.byteLength);return new me(e).set(new me(t)),e}function C(t,e){return new t.constructor(e?z(t.buffer):t.buffer,t.byteOffset,t.length)}function U(t,e){var n=-1,r=t.length;for(e=e||Array(r);++n<r;)e[n]=t[n];return e}function P(t,e,n){var r=!n;n=n||{};for(var o=-1,a=e.length;++o<a;){var i=e[o],u=Mt;u===Mt&&(u=t[i]),r?j(n,i,u):y(n,i,u)}return n}function R(f){return function(t){return sn(et(t,void 0,It),t+"")}(function(t,e){var n,r=-1,o=e.length,a=1<o?e[o-1]:Mt,i=2<o?e[2]:Mt;a=3<f.length&&"function"==typeof a?(o--,a):Mt;if(n=i){n=e[0];var u=e[1];if(bt(i)){var c=_typeof(u);n=!!("number"==c?st(i)&&Q(u,i.length):"string"==c&&u in i)&&ft(i[u],n)}else n=!1}for(n&&(a=o<3?Mt:a,o=1),t=Object(t);++r<o;)(i=e[r])&&f(t,i,r,a);return t})}function $(t){return vt(t)?Mt:t}function V(t,e,n,r,o,a){var i=1&n,u=t.length;if(u!=(c=e.length)&&!(i&&u<c))return!1;if((c=a.get(t))&&a.get(e))return c==e;var c=-1,f=!0,s=2&n?new d:Mt;for(a.set(t,e),a.set(e,t);++c<u;){var l=t[c],p=e[c];if(r)var y=i?r(p,l,c,e,t,a):r(l,p,c,t,e,a);if(y!==Mt){if(y)continue;f=!1;break}if(s){if(!b(e,function(t,e){if(!s.has(e)&&(l===t||o(l,t,n,r,a)))return s.push(e)})){f=!1;break}}else if(l!==p&&!o(l,p,n,r,a)){f=!1;break}}return a.delete(t),a.delete(e),f}function H(t){return O(t,Lt,tn)}function B(t){return O(t,St,en)}function W(t,e){var n=(n=r.iteratee||kt)===kt?x:n;return arguments.length?n(t,e):n}function G(t,e){var n=t.__data__,r=_typeof(e);return("string"==r||"number"==r||"symbol"==r||"boolean"==r?"__proto__"!==e:null===e)?n["string"==typeof e?"string":"hash"]:n.map}function q(t,e){var n=null==t?Mt:t[e];return!bt(n)||he&&he in n||!(pt(n)?ge:Gt).test(rt(n))?Mt:n}function J(t,e,n){for(var r=-1,o=(e=F(e,t)).length,a=!1;++r<o;){var i=nt(e[r]);if(!(a=null!=t&&n(t,i)))break;t=t[i]}return a||++r!=o?a:!!(o=null==t?0:t.length)&&yt(o)&&Q(i,o)&&(hn(t)||bn(t))}function Y(t){return"function"!=typeof t.constructor||Z(t)?{}:Ye(Oe(t))}function K(t){return hn(t)||bn(t)||!!(Se&&t&&t[Se])}function Q(t,e){var n=_typeof(t);return!!(e=null==e?9007199254740991:e)&&("number"==n||"symbol"!=n&&Jt.test(t))&&-1<t&&0==t%1&&t<e}function X(t,e){if(hn(t))return!1;var n=_typeof(t);return!("number"!=n&&"symbol"!=n&&"boolean"!=n&&null!=t&&!gt(t))||Pt.test(t)||!Ut.test(t)||null!=e&&t in Object(e)}function Z(t){var e=t&&t.constructor;return t===("function"==typeof e&&e.prototype||le)}function tt(e,n){return function(t){return null!=t&&t[e]===n&&(n!==Mt||e in Object(t))}}function et(o,a,i){return a=De(a===Mt?o.length-1:a,0),function(){for(var t=arguments,e=-1,n=De(t.length-a,0),r=Array(n);++e<n;)r[e]=t[a+e];for(e=-1,n=Array(a+1);++e<a;)n[e]=t[e];return n[a]=i(r),function(t,e,n){switch(n.length){case 0:return t.call(e);case 1:return t.call(e,n[0]);case 2:return t.call(e,n[0],n[1]);case 3:return t.call(e,n[0],n[1],n[2])}return t.apply(e,n)}(o,this,n)}}function nt(t){if("string"==typeof t||gt(t))return t;var e=t+"";return"0"==e&&1/t==-zt?"-0":e}function rt(t){if(null==t)return"";try{return ye.call(t)}catch(t){}return t+""}function ot(t,e,n){var r=null==t?0:t.length;return r?((n=null==n?0:jt(n))<0&&(n=De(r+n,0)),o(t,W(e,3),n)):-1}function at(t){return null!=t&&t.length?function t(e,n,r,o,a){var i=-1,u=e.length;for(r=r||K,a=a||[];++i<u;){var c=e[i];0<n&&r(c)?1<n?t(c,n-1,r,o,a):f(a,c):o||(a[a.length]=c)}return a}(t,1):[]}function it(t){var e=null==t?0:t.length;return e?t[e-1]:Mt}function ut(r,o){function a(){var t=arguments,e=o?o.apply(this,t):t[0],n=a.cache;return n.has(e)?n.get(e):(t=r.apply(this,t),a.cache=n.set(e,t)||n,t)}if("function"!=typeof r||null!=o&&"function"!=typeof o)throw new TypeError("Expected a function");return a.cache=new(ut.Cache||s),a}function ct(e){if("function"!=typeof e)throw new TypeError("Expected a function");return function(){var t=arguments;switch(t.length){case 0:return!e.call(this);case 1:return!e.call(this,t[0]);case 2:return!e.call(this,t[0],t[1]);case 3:return!e.call(this,t[0],t[1],t[2])}return!e.apply(this,t)}}function ft(t,e){return t===e||t!=t&&e!=e}function st(t){return null!=t&&yt(t.length)&&!pt(t)}function lt(t){return ht(t)&&st(t)}function pt(t){return!!bt(t)&&("[object Function]"==(t=w(t))||"[object GeneratorFunction]"==t||"[object AsyncFunction]"==t||"[object Proxy]"==t)}function yt(t){return"number"==typeof t&&-1<t&&0==t%1&&t<=9007199254740991}function bt(t){var e=_typeof(t);return null!=t&&("object"==e||"function"==e)}function ht(t){return null!=t&&"object"==_typeof(t)}function vt(t){return!(!ht(t)||"[object Object]"!=w(t))&&(null===(t=Oe(t))||"function"==typeof(t=be.call(t,"constructor")&&t.constructor)&&t instanceof t&&ye.call(t)==de)}function dt(t){return"string"==typeof t||!hn(t)&&ht(t)&&"[object String]"==w(t)}function gt(t){return"symbol"==_typeof(t)||ht(t)&&"[object Symbol]"==w(t)}function _t(t){return t?(t=mt(t))===zt||t===-zt?17976931348623157e292*(t<0?-1:1):t==t?t:0:0===t?t:0}function jt(t){var e=(t=_t(t))%1;return t==t?e?t-e:t:0}function mt(t){if("number"==typeof t)return t;if(gt(t))return Ct;if(bt(t)&&(t=bt(t="function"==typeof t.valueOf?t.valueOf():t)?t+"":t),"string"!=typeof t)return 0===t?t:+t;t=t.replace($t,"");var e=Wt.test(t);return e||qt.test(t)?Xt(t.slice(2),e?2:8):Bt.test(t)?Ct:+t}function At(t){return P(t,St(t))}function Ot(t){return null==t?"":N(t)}function wt(t,e,n){return(t=null==t?Mt:A(t,e))===Mt?n:t}function Et(t,e){return null!=t&&J(t,e,L)}function Lt(t){return st(t)?l(t):I(t)}function St(t){if(st(t))t=l(t,!0);else if(bt(t)){var e,n=Z(t),r=[];for(e in t)("constructor"!=e||!n&&be.call(t,e))&&r.push(e);t=r}else{if(e=[],null!=t)for(n in Object(t))e.push(n);t=e}return t}function Tt(t){return null==t?[]:function(e,t){return a(t,function(t){return e[t]})}(t,Lt(t))}function xt(t){return function(){return t}}function It(t){return t}function kt(t){return x("function"==typeof t?t:m(t,1))}function Nt(t){return X(t)?function(e){return function(t){return null==t?Mt:t[e]}}(nt(t)):function(e){return function(t){return A(t,e)}}(t)}function Dt(){return[]}function Ft(){return!1}var Mt,zt=1/0,Ct=NaN,Ut=/\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,Pt=/^\w*$/,Rt=/[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g,$t=/^\s+|\s+$/g,Vt=/\\(\\)?/g,Ht=/\w*$/,Bt=/^[-+]0x[0-9a-f]+$/i,Wt=/^0b[01]+$/i,Gt=/^\[object .+?Constructor\]$/,qt=/^0o[0-7]+$/i,Jt=/^(?:0|[1-9]\d*)$/,Yt={};
8884Yt["[object Float32Array]"]=Yt["[object Float64Array]"]=Yt["[object Int8Array]"]=Yt["[object Int16Array]"]=Yt["[object Int32Array]"]=Yt["[object Uint8Array]"]=Yt["[object Uint8ClampedArray]"]=Yt["[object Uint16Array]"]=Yt["[object Uint32Array]"]=!0,Yt["[object Arguments]"]=Yt["[object Array]"]=Yt["[object ArrayBuffer]"]=Yt["[object Boolean]"]=Yt["[object DataView]"]=Yt["[object Date]"]=Yt["[object Error]"]=Yt["[object Function]"]=Yt["[object Map]"]=Yt["[object Number]"]=Yt["[object Object]"]=Yt["[object RegExp]"]=Yt["[object Set]"]=Yt["[object String]"]=Yt["[object WeakMap]"]=!1;var Kt={};Kt["[object Arguments]"]=Kt["[object Array]"]=Kt["[object ArrayBuffer]"]=Kt["[object DataView]"]=Kt["[object Boolean]"]=Kt["[object Date]"]=Kt["[object Float32Array]"]=Kt["[object Float64Array]"]=Kt["[object Int8Array]"]=Kt["[object Int16Array]"]=Kt["[object Int32Array]"]=Kt["[object Map]"]=Kt["[object Number]"]=Kt["[object Object]"]=Kt["[object RegExp]"]=Kt["[object Set]"]=Kt["[object String]"]=Kt["[object Symbol]"]=Kt["[object Uint8Array]"]=Kt["[object Uint8ClampedArray]"]=Kt["[object Uint16Array]"]=Kt["[object Uint32Array]"]=!0,Kt["[object Error]"]=Kt["[object Function]"]=Kt["[object WeakMap]"]=!1;var Qt,Xt=parseInt,Zt="object"==_typeof(On)&&On&&On.Object===Object&&On,te="object"==("undefined"==typeof self?"undefined":_typeof(self))&&self&&self.Object===Object&&self,ee=Zt||te||Function("return this")(),ne="object"==_typeof(En)&&En&&!En.nodeType&&En,re=ne&&"object"==_typeof(wn)&&wn&&!wn.nodeType&&wn,oe=re&&re.exports===ne,ae=oe&&Zt.process;t:{try{Qt=ae&&ae.binding&&ae.binding("util");break t}catch(t){}Qt=void 0}var ie,ue=Qt&&Qt.isMap,ce=Qt&&Qt.isSet,fe=Qt&&Qt.isTypedArray,se=Array.prototype,le=Object.prototype,pe=ee["__core-js_shared__"],ye=Function.prototype.toString,be=le.hasOwnProperty,he=(ie=/[^.]+$/.exec(pe&&pe.keys&&pe.keys.IE_PROTO||""))?"Symbol(src)_1."+ie:"",ve=le.toString,de=ye.call(Object),ge=RegExp("^"+ye.call(be).replace(/[\\^$.*+?()[\]{}|]/g,"\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$"),_e=oe?ee.Buffer:Mt,je=ee.Symbol,me=ee.Uint8Array,Ae=_e?_e.a:Mt,Oe=e(Object.getPrototypeOf),we=Object.create,Ee=le.propertyIsEnumerable,Le=se.splice,Se=je?je.isConcatSpreadable:Mt,Te=je?je.toStringTag:Mt,xe=function(){try{var t=q(Object,"defineProperty");return t({},"",{}),t}catch(t){}}(),Ie=Object.getOwnPropertySymbols,ke=_e?_e.isBuffer:Mt,Ne=e(Object.keys),De=Math.max,Fe=Date.now,Me=q(ee,"DataView"),ze=q(ee,"Map"),Ce=q(ee,"Promise"),Ue=q(ee,"Set"),Pe=q(ee,"WeakMap"),Re=q(Object,"create"),$e=rt(Me),Ve=rt(ze),He=rt(Ce),Be=rt(Ue),We=rt(Pe),Ge=je?je.prototype:Mt,qe=Ge?Ge.valueOf:Mt,Je=Ge?Ge.toString:Mt,Ye=function(t){return bt(t)?we?we(t):(Ke.prototype=t,t=new Ke,Ke.prototype=Mt,t):{}};function Ke(){}u.prototype.clear=function(){this.__data__=Re?Re(null):{},this.size=0},u.prototype.delete=function(t){return t=this.has(t)&&delete this.__data__[t],this.size-=t?1:0,t},u.prototype.get=function(t){var e=this.__data__;return Re?"__lodash_hash_undefined__"===(t=e[t])?Mt:t:be.call(e,t)?e[t]:Mt},u.prototype.has=function(t){var e=this.__data__;return Re?e[t]!==Mt:be.call(e,t)},u.prototype.set=function(t,e){var n=this.__data__;return this.size+=this.has(t)?0:1,n[t]=Re&&e===Mt?"__lodash_hash_undefined__":e,this},c.prototype.clear=function(){this.__data__=[],this.size=0},c.prototype.delete=function(t){var e=this.__data__;return!((t=p(e,t))<0||(t==e.length-1?e.pop():Le.call(e,t,1),--this.size,0))},c.prototype.get=function(t){var e=this.__data__;return(t=p(e,t))<0?Mt:e[t][1]},c.prototype.has=function(t){return-1<p(this.__data__,t)},c.prototype.set=function(t,e){var n=this.__data__,r=p(n,t);return r<0?(++this.size,n.push([t,e])):n[r][1]=e,this},s.prototype.clear=function(){this.size=0,this.__data__={hash:new u,map:new(ze||c),string:new u}},s.prototype.delete=function(t){return t=G(this,t).delete(t),this.size-=t?1:0,t},s.prototype.get=function(t){return G(this,t).get(t)},s.prototype.has=function(t){return G(this,t).has(t)},s.prototype.set=function(t,e){var n=G(this,t),r=n.size;return n.set(t,e),this.size+=n.size==r?0:1,this},d.prototype.add=d.prototype.push=function(t){return this.__data__.set(t,"__lodash_hash_undefined__"),this},d.prototype.has=function(t){return this.__data__.has(t)},g.prototype.clear=function(){this.__data__=new c,this.size=0},g.prototype.delete=function(t){var e=this.__data__;return t=e.delete(t),this.size=e.size,t},g.prototype.get=function(t){return this.__data__.get(t)},g.prototype.has=function(t){return this.__data__.has(t)},g.prototype.set=function(t,e){var n=this.__data__;if(n instanceof c){var r=n.__data__;if(!ze||r.length<199)return r.push([t,e]),this.size=++n.size,this;n=this.__data__=new s(r)}return n.set(t,e),this.size=n.size,this};var Qe=function(t,e){if(null==t)return t;if(!st(t))return function(t,e){return t&&Xe(t,e,Lt)}(t,e);for(var n=t.length,r=-1,o=Object(t);++r<n&&!1!==e(o[r],r,o););return t},Xe=function(t,e,n){for(var r=-1,o=Object(t),a=(n=n(t)).length;a--;){var i=n[++r];if(!1===e(o[i],i,o))break}return t},Ze=xe?function(t,e){return xe(t,"toString",{configurable:!0,enumerable:!1,value:xt(e),writable:!0})}:It,tn=Ie?function(e){return null==e?[]:(e=Object(e),n(Ie(e),function(t){return Ee.call(e,t)}))}:Dt,en=Ie?function(t){for(var e=[];t;)f(e,tn(t)),t=Oe(t);return e}:Dt,nn=w;(Me&&"[object DataView]"!=nn(new Me(new ArrayBuffer(1)))||ze&&"[object Map]"!=nn(new ze)||Ce&&"[object Promise]"!=nn(Ce.resolve())||Ue&&"[object Set]"!=nn(new Ue)||Pe&&"[object WeakMap]"!=nn(new Pe))&&(nn=function(t){var e=w(t);if(t=(t="[object Object]"==e?t.constructor:Mt)?rt(t):"")switch(t){case $e:return"[object DataView]";case Ve:return"[object Map]";case He:return"[object Promise]";case Be:return"[object Set]";case We:return"[object WeakMap]"}return e});var rn,on,an,un,cn,fn,sn=(un=Ze,fn=cn=0,function(){var t=Fe(),e=16-(t-fn);if(fn=t,0<e){if(800<=++cn)return arguments[0]}else cn=0;return un.apply(Mt,arguments)}),ln=(an=(on=ut(on=function(t){var o=[];return 46===t.charCodeAt(0)&&o.push(""),t.replace(Rt,function(t,e,n,r){o.push(n?r.replace(Vt,"$1"):e||t)}),o},function(t){return 500===an.size&&an.clear(),t})).cache,on),pn=(rn=ot,function(t,e,n){var r=Object(t);if(!st(t)){var o=W(e,3);t=Lt(t),e=function(t){return o(r[t],t,r)}}return-1<(e=rn(t,e,n))?r[o?t[e]:e]:Mt});ut.Cache=s;var yn,bn=S(function(){return arguments}())?S:function(t){return ht(t)&&be.call(t,"callee")&&!Ee.call(t,"callee")},hn=Array.isArray,vn=ke||Ft,dn=ue?t(ue):function(t){return ht(t)&&"[object Map]"==nn(t)},gn=ce?t(ce):function(t){return ht(t)&&"[object Set]"==nn(t)}
8884,_n=fe?t(fe):function(t){return ht(t)&&yt(t.length)&&!!Yt[w(t)]},jn=R(function(t,e,n){k(t,e,n)}),mn=R(function(t,e,n,r){k(t,e,n,r)}),An=sn(et(yn=function(e,t){var n={};if(null==e)return n;var r=!1;t=a(t,function(t){return t=F(t,e),r=r||1<t.length,t}),P(e,B(e),n),r&&(n=m(n,7,$));for(var o=t.length;o--;)D(n,t[o]);return n},Mt,at),yn+"");r.constant=xt,r.flatten=at,r.iteratee=kt,r.keys=Lt,r.keysIn=St,r.memoize=ut,r.merge=jn,r.mergeWith=mn,r.negate=ct,r.omit=An,r.property=Nt,r.reject=function(t,e){return(hn(t)?n:function(t,r){var o=[];return Qe(t,function(t,e,n){r(t,e,n)&&o.push(t)}),o})(t,ct(W(e,3)))},r.toPlainObject=At,r.values=Tt,r.cloneDeep=function(t){return m(t,5)},r.cloneDeepWith=function(t,e){return m(t,5,e="function"==typeof e?e:Mt)},r.eq=ft,r.find=pn,r.findIndex=ot,r.get=wt,r.has=function(t,e){return null!=t&&J(t,e,E)},r.hasIn=Et,r.identity=It,r.includes=function(t,e,n,r){if(t=st(t)?t:Tt(t),n=n&&!r?jt(n):0,r=t.length,n<0&&(n=De(r+n,0)),dt(t))t=n<=r&&-1<t.indexOf(e,n);else{if(r=!!r){if(e==e)t:{for(n-=1,r=t.length;++n<r;)if(t[n]===e){t=n;break t}t=-1}else t=o(t,i,n);r=-1<t}t=r}return t},r.isArguments=bn,r.isArray=hn,r.isArrayLike=st,r.isArrayLikeObject=lt,r.isBuffer=vn,r.isEmpty=function(t){if(null==t)return!0;if(st(t)&&(hn(t)||"string"==typeof t||"function"==typeof t.splice||vn(t)||_n(t)||bn(t)))return!t.length;var e=nn(t);if("[object Map]"==e||"[object Set]"==e)return!t.size;if(Z(t))return!I(t).length;for(var n in t)if(be.call(t,n))return!1;return!0},r.isEqual=function(t,e){return T(t,e)},r.isFunction=pt,r.isLength=yt,r.isMap=dn,r.isNull=function(t){return null===t},r.isObject=bt,r.isObjectLike=ht,r.isPlainObject=vt,r.isSet=gn,r.isString=dt,r.isSymbol=gt,r.isTypedArray=_n,r.last=it,r.stubArray=Dt,r.stubFalse=Ft,r.toFinite=_t,r.toInteger=jt,r.toNumber=mt,r.toString=Ot,r.VERSION="4.17.5",re&&((re.exports=r)._=r,ne._=r)}).call(this)}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{}],2:[function(t,e,n){e.exports={itemType:{DATA:"data",FCTN:"fctn",EVENT:"event",LISTENER_ON:"listenerOn",LISTENER_OFF:"listenerOff"},dataLayerEvent:{CHANGE:"adobeDataLayer:change",EVENT:"adobeDataLayer:event"},listenerScope:{PAST:"past",FUTURE:"future",ALL:"all"}}},{}],3:[function(t,e,n){var r=t("../custom-lodash"),c=t("../version.json").version,l=r.cloneDeep,p=r.get,y=t("./item"),b=t("./listener"),h=t("./listenerManager"),v=t("./constants"),d=t("./utils/customMerge");e.exports=function(t){var f,e=t||{},n=[],r=[],o={},a={getState:function(){return o},getDataLayer:function(){return n}};function i(t){o=d(o,t.data)}function u(t){t.valid?{data:function(t){i(t),f.triggerListeners(t)},fctn:function(t){t.config.call(n,n)},event:function(t){t.data&&i(t),f.triggerListeners(t)},listenerOn:function(t){var e=b(t);switch(e.scope){case v.listenerScope.PAST:var n,r=_createForOfIteratorHelper(c(t));try{for(r.s();!(n=r.n()).done;){var o=n.value;f.triggerListener(e,o)}}catch(t){r.e(t)}finally{r.f()}break;case v.listenerScope.FUTURE:f.register(e);break;case v.listenerScope.ALL:if(f.register(e)){var a,i=_createForOfIteratorHelper(c(t));try{for(i.s();!(a=i.n()).done;){var u=a.value;f.triggerListener(e,u)}}catch(t){i.e(t)}finally{i.f()}}}},listenerOff:function(t){f.unregister(b(t))}}[t.type](t):s(t);function c(t){return 0===n.length||t.index>n.length-1?[]:n.slice(0,t.index).map(function(t){return y(t)})}}function s(t){var e="The following item cannot be handled by the data layer because it does not have a valid format: "+JSON.stringify(t.config);console.error(e)}return function(){Array.isArray(e.dataLayer)||(e.dataLayer=[]);r=e.dataLayer.splice(0,e.dataLayer.length),(n=e.dataLayer).version=c,o={},f=h(a)}(),n.push=function(t){var n=arguments,r=arguments;if(Object.keys(n).forEach(function(t){var e=y(n[t]);switch(e.valid||(s(e),delete r[t]),e.type){case v.itemType.DATA:case v.itemType.EVENT:u(e);break;case v.itemType.FCTN:delete r[t],u(e);break;case v.itemType.LISTENER_ON:case v.itemType.LISTENER_OFF:delete r[t]}}),r[0])return Array.prototype.push.apply(this,r)},n.getState=function(t){return t?p(l(o),t):l(o)},n.addEventListener=function(t,e,n){u(y({on:t,handler:e,scope:n&&n.scope,path:n&&n.path}))},n.removeEventListener=function(t,e){u(y({off:t,handler:e}))},function(){for(var t=0;t<r.length;t++)n.push(r[t])}(),a}},{"../custom-lodash":1,"../version.json":14,"./constants":2,"./item":5,"./listener":7,"./listenerManager":8,"./utils/customMerge":10}],4:[function(t,e,n){var r={Manager:t("./dataLayerManager")};window.adobeDataLayer=window.adobeDataLayer||[],window.adobeDataLayer.version?console.warn("Adobe Client Data Layer v".concat(window.adobeDataLayer.version," has already been imported/initialized on this page. You may be erroneously loading it a second time.")):r.Manager({dataLayer:window.adobeDataLayer}),e.exports=r},{"./dataLayerManager":3}],5:[function(t,e,n){var r=t("../custom-lodash"),i=r.isPlainObject,u=r.isEmpty,c=r.omit,f=r.find,s=t("./utils/dataMatchesContraints"),l=t("./itemConstraints"),p=t("./constants");e.exports=function(t,e){var n=t,r=e,o=f(Object.keys(l),function(t){return s(n,l[t])})||"function"==typeof n&&p.itemType.FCTN||i(n)&&p.itemType.DATA,a=function(){var t=c(n,Object.keys(l.event));if(!u(t))return t}();return{config:n,type:o,data:a,valid:!!o,index:r}}},{"../custom-lodash":1,"./constants":2,"./itemConstraints":6,"./utils/dataMatchesContraints":11}],6:[function(t,e,n){e.exports={event:{event:{type:"string"},eventInfo:{optional:!0}},listenerOn:{on:{type:"string"},handler:{type:"function"},scope:{type:"string",values:["past","future","all"],optional:!0},path:{type:"string",optional:!0}},listenerOff:{off:{type:"string"},handler:{type:"function",optional:!0},scope:{type:"string",values:["past","future","all"],optional:!0},path:{type:"string",optional:!0}}}},{}],7:[function(t,e,n){var r=t("./constants");e.exports=function(t){return{event:t.config.on||t.config.off,handler:t.config.handler||null,scope:t.config.scope||t.config.on&&r.listenerScope.ALL||null,path:t.config.path||null}}},{"./constants":2}],8:[function(t,e,n){var u=t("../custom-lodash").cloneDeep,c=t("./constants"),f=t("./utils/listenerMatch"),s=t("./utils/indexOfListener");e.exports=function(t){var o={},r=t,a=s.bind(null,o);function i(t,e){if(f(t,e)){var n=[u(e.config)];t.handler.apply(r.getDataLayer(),n)}}return{register:function(t){var e=t.event;return Object.prototype.hasOwnProperty.call(o,e)?-1===a(t)&&(o[t.event].push(t),!0):(o[t.event]=[t],!0)},unregister:function(t){var e=t.event;if(Object.prototype.hasOwnProperty.call(o,e))if(t.handler||t.scope||t.path){var n=a(t);-1<n&&o[e].splice(n,1)}else o[e]=[]},triggerListeners:function(r){(function(t){var e=[];switch(t.type){case c.itemType.DATA:e.push(c.dataLayerEvent.CHANGE);break;case c.itemType.EVENT:e.push(c.dataLayerEvent.EVENT),t.data&&e.push(c.dataLayerEvent.CHANGE),t.config.event!==c.dataLayerEvent.CHANGE&&e.push(t.config.event)}return e})(r).forEach(function(t){if(Object.prototype.hasOwnProperty.call(o,t)){var e,n=_createForOfIteratorHelper(o[t]);try{for(n.s();!(e=n.n()).done;){i(e.value,r)}}catch(t){n.e(t)}finally{n.f()}}})},triggerListener:function(t,e){i(t,e)}}}},{"../custom-lodash":1,"./constants":2,"./utils/indexOfListener":12,"./utils/listenerMatch":13}],9:[function(t,e,n){var r=t("../../custom-lodash"),o=r.has,a=r.get;e.exports=function(t,e){for(var n=e.substring(0,e.lastIndexOf("."));n;){if(o(t,n)){var r=a(t,n);if(null==r)return!0}n=n.substring(0,n.lastIndexOf("."))}return!1}},{"../../custom-lodash":1}],10:[function(t,e,n){var r=t("../../custom-lodash"),s=r.cloneDeepWith,l=r.isObject,p=r.isArray,y=r.reject,o=r.mergeWith,a=r.isNull;e.exports=function(t,e){return o(t,e,function(t,e,n,r){if(null==e)return null}),t=function(t,e){return s(t,function(f){return function e(t,n,r,o){if(l(t)){if(p(t))return y(t,f).map(function(t){return s(t,e)});for(var a={},i=0,u=Object.keys(t);i<u.length;i++){var c=u[i];f(t[c])||(a[c]=s(t[c],e))}return a}}}(1<arguments.length&&void 0!==e?e:function(t){return!t}))}(t,a)}},{"../../custom-lodash":1}],11:[function(t,e,n){var r=t("../../custom-lodash"),o=r.find,s=r.includes;e.exports=function(c,f){return void 0===o(Object.keys(f),function(t){var e=f[t].type,n=t&&f[t].values,r=!f[t].optional,o=c[t],a=_typeof(o),i=e&&a!==e,u=n&&!s(n,o);return r?!o||i||u:o&&(i||u)})}},{"../../custom-lodash":1}],12:[function(t,e,n){var c=t("../../custom-lodash").isEqual;e.exports=function(t,e){var n=e.event;if(Object.prototype.hasOwnProperty.call(t,n)){var r,o=_createForOfIteratorHelper(t[n].entries());try{for(o.s();!(r=o.n()).done;){var a=_slicedToArray(r.value,2),i=a[0],u=a[1];if(c(u.handler,e.handler))return i}}catch(t){o.e(t)}finally{o.f()}}return-1}},{"../../custom-lodash":1}],13:[function(t,e,n){var r=t("../../custom-lodash").has,a=t("../constants"),o=t("./ancestorRemoved");function i(t,e){return!e.data||!t.path||(r(e.data,t.path)||o(e.data,t.path))}
8884e.exports=function(t,e){var n=t.event,r=e.config,o=!1;return e.type===a.itemType.DATA?n===a.dataLayerEvent.CHANGE&&(o=i(t,e)):e.type===a.itemType.EVENT&&(n!==a.dataLayerEvent.EVENT&&n!==r.event||(o=i(t,e)),e.data&&n===a.dataLayerEvent.CHANGE&&(o=i(t,e))),o}},{"../../custom-lodash":1,"../constants":2,"./ancestorRemoved":9}],14:[function(t,e,n){e.exports={version:"2.0.2"}},{}]},{},[4]); 8885//# sourceMappingURL=adobe-client-data-layer.min.js.map 8886 8887/******************************************************************************* 8888 * Copyright 2020 Adobe 8889 * 8890 * Licensed under the Apache License, Version 2.0 (the "License"); 8891 * you may not use this file except in compliance with the License. 8892 * You may obtain a copy of the License at 8893 * 8894 * http://www.apache.org/licenses/LICENSE-2.0 8895 * 8896 * Unless required by applicable law or agreed to in writing, software 8897 * distributed under the License is distributed on an "AS IS" BASIS, 8898 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 8899 * See the License for the specific language governing permissions and 8900 * limitations under the License. 8901 ******************************************************************************/ 8902(function() { 8903 "use strict"; 8904 8905 var dataLayerEnabled; 8906 var dataLayerName; 8907 var dataLayer; 8908 8909 function addComponentToDataLayer(component) { 8910 dataLayer.push({ 8911 component: getComponentObject(component) 8912 }); 8913 } 8914 8915 function attachClickEventListener(element) { 8916 element.addEventListener("click", addClickToDataLayer); 8917 } 8918 8919 function getComponentObject(element) { 8920 var component = getComponentData(element); 8921 var componentID = Object.keys(component)[0]; 8922 // if the component does not have a parent ID property, use the ID of the parent element 8923 if (component && component[componentID] && !component[componentID].parentId) { 8924 var parentElement = element.parentNode.closest("[data-cmp-data-layer], body"); 8925 if (parentElement) { 8926 component[componentID].parentId = parentElement.id; 8927 } 8928 } 8929 8930 return component; 8931 } 8932 8933 function addClickToDataLayer(event) { 8934 var element = event.currentTarget; 8935 var componentId = getClickId(element); 8936 8937 dataLayer.push({ 8938 event: "cmp:click", 8939 eventInfo: { 8940 path: "component." + componentId 8941 } 8942 }); 8943 } 8944 8945 function getComponentData(element) { 8946 var dataLayerJson = element.dataset.cmpDataLayer; 8947 if (dataLayerJson) { 8948 return JSON.parse(dataLayerJson); 8949 } else { 8950 return undefined; 8951 } 8952 } 8953 8954 function getClickId(element) { 8955 if (element.dataset.cmpDataLayer) { 8956 return Object.keys(JSON.parse(element.dataset.cmpDataLayer))[0]; 8957 } 8958 8959 var componentElement = element.closest("[data-cmp-data-layer]"); 8960 8961 return Object.keys(JSON.parse(componentElement.dataset.cmpDataLayer))[0]; 8962 } 8963 8964 function onDocumentReady() { 8965 dataLayerEnabled = document.body.hasAttribute("data-cmp-data-layer-enabled"); 8966 if (dataLayerEnabled) { 8967 dataLayerName = document.body.getAttribute("data-cmp-data-layer-name") || "adobeDataLayer"; 8968 dataLayer = window[dataLayerName] = window[dataLayerName] || []; 8969 8970 var components = document.querySelectorAll("[data-cmp-data-layer]"); 8971 var clickableElements = document.querySelectorAll("[data-cmp-clickable]"); 8972 8973 components.forEach(function(component) { 8974 addComponentToDataLayer(component); 8975 }); 8976 8977 clickableElements.forEach(function(element) { 8978 attachClickEventListener(element); 8979 }); 8980 8981 dataLayer.push({ 8982 event: "cmp:loaded" 8983 }); 8984 } 8985 } 8986 8987 if (document.readyState !== "loading") { 8988 onDocumentReady(); 8989 } else { 8990 document.addEventListener("DOMContentLoaded", onDocumentReady); 8991 } 8992 8993}()); 8994 8995//Script for Adobe Analytics 8996{ 8997 var cjaScript = document.createElement("script"); 8998 cjaScript.type = "text/javascript"; 8999 cjaScript.async = true; 9000 var windowLocation = location.host; 9001 function callAdobedtm() { 9002 if (windowLocation === "www.blueshieldca.com") { 9003 cjaScript.src = "https://assets.adobedtm.com/4292fae30116/2025583062c9/launch-bc4d4ddee690.min.js"; 9004 }
9004 else if (windowLocation === "webh72.bsc.bscal.com") { 9005 cjaScript.src = 9006 "https://assets.adobedtm.com/4292fae30116/2025583062c9/launch-4752dd9a4f78-staging.min.js"; 9007 }else { 9008 cjaScript.src = 9009 "https://assets.adobedtm.com/4292fae30116/2025583062c9/launch-73f269d5a602-development.min.js"; 9010 } 9011 } 9012 callAdobedtm(); 9013 9014 let s = document.getElementsByTagName('script')[0]; 9015 9016 if (!document.querySelector('script[src*="assets.adobedtm.com"]')) { 9017 s.parentNode.insertBefore(cjaScript, s); 9018 } 9019 else { 9020 //do nothing 9021 } 9022 9023}
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.