1class SummaryItem { 2 text = null; 3 active = false; 4 5 element = null; 6 elementLi = null; 7 elementA = null; 8 9 anchorElement = null; 10 anchorId = null; 11 level = null; 12 13 summary = null; 14 15 constructor(element, summary) { 16 // Set variables 17 this.element = element; 18 this.summary = summary; 19 this.text = (element.innerText || element.textContent).trim(); 20 21 // Get anchor element 22 this.anchorId = this.element?.dataset?.anchor; 23 if (this.anchorId) { 24 this.anchorElement = document.getElementById(this.anchorId); 25 this.anchorElement.addEventListener("click", this.onClickAnchorEvent.bind(this)); 26 } 27 28 this.level = this.element?.dataset?.summarylevel; 29 30 // Create 'a' element 31 const a = document.createElement('a'); 32 const aText = document.createTextNode(this.text); 33 a.setAttribute('href', "#" + this.anchorId); 34 a.appendChild(aText); 35 a.tabIndex = -1; 36 37 // Create icon span 38 const iconSpan = document.createElement('span'); 39 iconSpan.classList.add('summary-item-icon'); 40 41 // Create 'li' element 42 const li = document.createElement("li"); 43 li.appendChild(iconSpan); 44 li.appendChild(a); 45 li.classList.add('summary-level-' + this.level); 46 47 // Add click event 48 li.addEventListener("click", this.onClickEvent.bind(this)); 49 50 // Persist objects 51 this.elementA = a; 52 this.elementLi = li; 53 } 54 55 /** 56 * Set whether the element is active 57 * @param {Boolean} active 58 */ 59 setActive(active) { 60 if (this.active == active) return; 61 62 // Persist value 63 this.active = active; 64 65 // Set active class 66 if (this.active) this.elementLi.classList.add('active'); 67 else this.elementLi.classList.remove('active'); 68 } 69 70 /** 71 * Focus and smooth scroll to the title element 72 * @param {Event} event 73 */ 74 scrollToAnchor(event) { 75 this.anchorElement.focus({ preventScroll: true }); 76 const offsetTop = this.getOffset(this.element).top; 77 const target = offsetTop + this.summary.scrollToOffset(); 78 window.scrollTo({ top: target, behavior: 'smooth' }); 79 } 80 81 /** 82 * Event on click of a summary element 83 * @param {Event} event 84 */ 85 onClickEvent(event) { 86 event.preventDefault(); 87 88 if (this.summary.state === Summary.STATE_OPEN) { 89 // Set the URL hash 90 history.pushState({}, "", `#${this.anchorId}`); 91 92 // Scroll to title 93 this.scrollToAnchor(this); 94 } 95 } 96 97 /** 98 * Event on click of a title's anchor 99 * @param {Event} event 100 */ 101 onClickAnchorEvent(event) { 102 event.preventDefault(); 103 // this.scrollToAnchor(this); 104 } 105 106 /** 107 * Returns an element's position relative to the whole document 108 * @param {Element} el 109 * @returns {object} 110 */ 111 getOffset(el) { 112 const rect = el.getBoundingClientRect(); 113 return { 114 left: rect.left + window.scrollX, 115 top: rect.top + window.scrollY 116 }; 117 } 118}
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.