1/******************************************************************************* 2 * Copyright 2024 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/LICENSE-2.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(function () { 19 20 function AccordionMixin(Base) { 21 return class extends Base { 22 static NS = "cmp"; 23 static IS = "adaptiveFormAccordion"; 24 static bemBlock = 'cmp-accordion'; 25 static selectors = { 26 self: "[data-" + this.NS + '-is="' + this.IS + '"]' 27 }; 28 29 30 static idSuffixes = { 31 item: "-item", 32 button: "-button", 33 panel: "-panel" 34 } 35 36 static cacheKeys = { 37 buttonKey: "button", 38 panelKey: "panel", 39 itemKey: "item" 40 } 41 42 static cssClasses = { 43 button: { 44 disabled: "cmp-accordion__button--disabled", 45 expanded: "cmp-accordion__button--expanded", 46 stepped: "cmp-accordion__button--stepped" 47 }, 48 panel: { 49 hidden: "cmp-accordion__panel--hidden", 50 expanded: "cmp-accordion__panel--expanded", 51 stepped: "cmp-accordion__panel--stepped" 52 } 53 }; 54 55 static delay = 100; 56 57 static dataAttributes = { 58 item: { 59 expanded: "data-cmp-expanded" 60 } 61 }; 62 63 constructor(params) { 64 super(params); 65 } 66 67 getCachedItems() { 68 return (this._elements[this.constructor.cacheKeys.itemKey] != null) ? this._elements[this.constructor.cacheKeys.itemKey] : []; 69 } 70 71 getCachedPanels() { 72 return this._elements[this.constructor.cacheKeys.panelKey]; 73 } 74 75 getCachedButtons() { 76 return this._elements[this.constructor.cacheKeys.buttonKey] 77 } 78 79 getItemById(itemId) { 80 var items = this.getCachedItems(); 81 if (items) { 82 for (var i = 0; i < items.length; i++) { 83 if (items[i].id === itemId) { 84 return items[i]; 85 } 86 } 87 } 88 } 89 90 91 /** 92 * Returns all expanded items. 93 * 94 * @private 95 * @returns {HTMLElement[]} The expanded items 96 */ 97 getExpandedItems() { 98 var expandedItems = []; 99 100 for (var i = 0; i < this.getCachedItems().length; i++) { 101 var item = this.getCachedItems()[i]; 102 var expanded = this.isItemExpanded(item); 103 if (expanded) { 104 expandedItems.push(item); 105 } 106 } 107 108 return expandedItems; 109 } 110 111 /** 112 * Gets an item's expanded state. 113 * 114 * @private 115 * @param {HTMLElement} item The item for checking its expanded state 116 * @returns {Boolean} true if the item is expanded, false otherwise 117 */ 118 isItemExpanded(item) { 119 return item && item.dataset && item.dataset["cmpExpanded"] !== undefined; 120 } 121 122 /** 123 * Caches the Accordion elements as defined via the {@code data-accordion-hook="ELEMENT_NAME"} markup API. 124 * 125 * @private 126 * @param {HTMLElement} wrapper The Accordion wrapper element 127 */ 128 cacheElements(wrapper) { 129 this._elements = {}; 130 this._elements.self = wrapper; 131 var hooks = this._elements.self.querySelectorAll("[data-" + this.constructor.NS + "-hook-" + this.constructor.IS + "]"); 132 133 for (var i = 0; i < hooks.length; i++) { 134 var hook = hooks[i]; 135 if (hook.closest("[data-cmp-is=" + this.constructor.IS + "]") === this._elements.self) { // only process own accordion elements 136 var lowerCased = this.constructor.IS.toLowerCase(); 137 var capitalized = lowerCased.charAt(0).toUpperCase() + lowerCased.slice(1); 138 var key = hook.dataset[this.constructor.NS + "Hook" + capitalized]; 139 if (this._elements[key]) { 140 if (!Array.isArray(this._elements[key])) { 141 var tmp = this._elements[key]; 142 this._elements[key] = [tmp]; 143 } 144 this._elements[key].push(hook); 145 } else { 146 this._elements[key] = [hook]; 147 } 148 } 149 } 150 } 151 152 collapseAllOtherItems(itemId) { 153 var itemToToggle = this.getItemById(itemId); 154 var itemList = this.getCachedItems(); 155 for (var i = 0; i < itemList.length; i++) { 156 if (itemList[i] !== itemToToggle) { 157 var expanded = this.isItemExpanded(itemList[i]); 158 if (expanded) { 159 this.collapseItem(this.getCachedItems()[i]); 160 } 161 } 162 } 163 } 164 165 /** 166 * General handler for toggle of an item. 167 * 168 * @private 169 * @param {Number} id The id of the item to toggle 170 */ 171 toggle(id) { 172 var itemToToggle = this.getItemById(id); 173 if (itemToToggle) { 174 (this.isItemExpanded(itemToToggle) === false) ? this.expandItem(itemToToggle) : this.collapseItem(itemToToggle); 175 } 176 } 177 178 179 /** 180 * Refreshes an item based on its expanded state. 181 * 182 * @private 183 * @param {HTMLElement} item The item to refresh 184 */ 185 refreshItem(item) { 186 var expanded = this.isItemExpanded(item); 187 if (expanded) { 188 this.expandItem(item); 189 } else { 190 this.collapseItem(item); 191 } 192 } 193 194 /** 195 * Refreshes all items based on their expanded state. 196 * 197 * @private 198 */ 199 refreshItems() { 200 for (var i = 0; i < this.getCachedItems().length; i++) { 201 this.refreshItem(this.getCachedItems()[i]); 202 } 203 } 204 205 206 /** 207 * Annotates the item and its internals with 208 * the necessary style and accessibility attributes to indicate it is expanded. 209 * 210 * @private 211 * @param {HTMLElement} item The item to annotate as expanded 212 */ 213 expandItem(item) { 214 var index = this.getCachedItems().indexOf(item); 215 if (index > -1) { 216 item.setAttribute(this.constructor.dataAttributes.item.expanded, ""); 217 var button = this.getCachedButtons()[index]; 218 var panel = this.getCachedPanels()[index]; 219 button.classList.add(this.constructor.cssClasse
219s.button.expanded); 220 // used to fix some known screen readers issues in reading the correct state of the 'aria-expanded' attribute 221 // e.g. https://bugs.webkit.org/show_bug.cgi?id=210934 222 setTimeout(function () { 223 button.setAttribute("aria-expanded", true); 224 }, this.constructor.delay); 225 panel.classList.add(this.constructor.cssClasses.panel.expanded); 226 panel.classList.remove(this.constructor.cssClasses.panel.hidden); 227 panel.setAttribute("aria-hidden", false); 228 229 // To set the focus on the field when tab expands 230 if (document.activeElement === button) { 231 const focusPanelId = panel.id.replace(this.constructor.idSuffixes.panel, ""); 232 this.focusToFirstVisibleField(focusPanelId); 233 } 234 } 235 } 236 237 /** 238 * Annotates the item and its internals with 239 * the necessary style and accessibility attributes to indicate it is not expanded. 240 * 241 * @private 242 * @param {HTMLElement} item The item to annotate as not expanded 243 */ 244 collapseItem(item) { 245 var index = this.getCachedItems().indexOf(item); 246 if (index > -1) { 247 item.removeAttribute(this.constructor.dataAttributes.item.expanded); 248 var button = this.getCachedButtons()[index]; 249 var panel = this.getCachedPanels()[index]; 250 if (button.classList.contains(this.constructor.cssClasses.button.expanded)) { 251 // Only apply `stepped` class if the tab was previously expanded 252 button.classList.add(this.constructor.cssClasses.button.stepped); 253 panel.classList.add(this.constructor.cssClasses.panel.stepped); 254 } 255 button.classList.remove(this.constructor.cssClasses.button.expanded); 256 // used to fix some known screen readers issues in reading the correct state of the 'aria-expanded' attribute 257 // e.g. https://bugs.webkit.org/show_bug.cgi?id=210934 258 setTimeout(function () { 259 button.setAttribute("aria-expanded", false); 260 }, this.constructor.delay); 261 panel.classList.add(this.constructor.cssClasses.panel.hidden); 262 panel.classList.remove(this.constructor.cssClasses.panel.expanded); 263 panel.setAttribute("aria-hidden", true); 264 } 265 } 266 }; 267 } 268 269 270 window.Forms = window.Forms || {}; 271 window.Forms.CoreComponentsCommons = window.Forms.CoreComponentsCommons || {}; 272 window.Forms.CoreComponentsCommons.AccordionMixin = AccordionMixin; 273 274 const event = new CustomEvent('AccordionMixinLoaded', { 275 detail: { 276 AccordionMixin: AccordionMixin 277 } 278 }); 279 window.dispatchEvent(event); 280 281}());
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.