1// Animate native HTML5 accordions (Adapted From: https://css-tricks.com/how-to-animate-the-details-element-using-waapi/) 2class Accordion { 3 constructor(el) { 4 // Store the <details> element 5 this.el = el; 6 // Store the <summary> element 7 this.summary = el.querySelector('.howToHeading, .tocHeading'); 8 // Store the <div class="content"> element 9 this.content = el.querySelector('.howToDescription, .tocContent'); 10 11 // Store the animation object (so we can cancel it if needed) 12 this.animation = null; 13 // Store if the element is closing 14 this.isClosing = false; 15 // Store if the element is expanding 16 this.isExpanding = false; 17 // Detect user clicks on the summary element 18 this.summary.addEventListener('click', (e) => this.onClick(e)); 19 } 20 21 onClick(e) { 22 // Stop default behaviour from the browser 23 e.preventDefault(); 24 // Add an overflow on the <details> to avoid content overflowing 25 this.el.style.overflow = 'hidden'; 26 // Check if the element is being closed or is already closed 27 if (this.isClosing || !this.el.open) { 28 this.open(); 29 // Check if the element is being openned or is already open 30 } else if (this.isExpanding || this.el.open) { 31 this.shrink(); 32 } 33 } 34 35 shrink() { 36 // Set the element as "being closed" 37 this.isClosing = true; 38 39 // Store the current height of the element 40 const startHeight = `${this.el.offsetHeight}px`; 41 // Calculate the height of the summary 42 const endHeight = `${this.summary.offsetHeight}px`; 43 44 // If there is already an animation running 45 if (this.animation) { 46 // Cancel the current animation 47 this.animation.cancel(); 48 } 49 50 // Start a WAAPI animation 51 this.animation = this.el.animate({ 52 // Set the keyframes from the startHeight to endHeight 53 height: [startHeight, endHeight] 54 }, { 55 duration: 150, 56 easing: 'ease-out' 57 }); 58 59 // When the animation is complete, call onAnimationFinish() 60 this.animation.onfinish = () => this.onAnimationFinish(false); 61 // If the animation is cancelled, isClosing variable is set to false 62 this.animation.oncancel = () => this.isClosing = false; 63 } 64 65 open() { 66 // Apply a fixed height on the element 67 this.el.style.height = `${this.el.offsetHeight}px`; 68 // Force the [open] attribute on the details element 69 this.el.open = true; 70 // Wait for the next frame to call the expand function 71 window.requestAnimationFrame(() => this.expand()); 72 } 73 74 expand() { 75 // Set the element as "being expanding" 76 this.isExpanding = true; 77 // Get the current fixed height of the element 78 const startHeight = `${this.el.offsetHeight}px`; 79 // Calculate the open height of the element (summary height + content height) 80 const endHeight = `${this.summary.offsetHeight + this.content.offsetHeight}px`; 81 82 // If there is already an animation running 83 if (this.animation) { 84 // Cancel the current animation 85 this.animation.cancel(); 86 } 87 88 // Start a WAAPI animation 89 this.animation = this.el.animate({ 90 // Set the keyframes from the startHeight to endHeight 91 height: [startHeight, endHeight] 92 }, { 93 duration: 150, 94 easing: 'ease-out' 95 }); 96 // When the animation is complete, call onAnimationFinish() 97 this.animation.onfinish = () => this.onAnimationFinish(true); 98 // If the animation is cancelled, isExpanding variable is set to false 99 this.animation.oncancel = () => this.isExpanding = false; 100 } 101 102 onAnimationFinish(open) { 103 // Set the open attribute based on the parameter 104 this.el.open = open; 105 // Clear the stored animation 106 this.animation = null; 107 // Reset isClosing & isExpanding 108 this.isClosing = false; 109 this.isExpanding = false; 110 // Remove the overflow hidden and the fixed height 111 this.el.style.height = this.el.style.overflow = ''; 112 } 113} 114 115document.querySelectorAll('.howToAccordion, .tocAccordion').forEach((el) => { 116 new Accordion(el); 117});
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.