1var tableOfContents = function (content, target, options) { 2 3 // 4 // Variables 5 // 6 7 // Get content 8 var contentWrap = document.querySelector(content); 9 var toc = document.querySelector(target); 10 if (!contentWrap || !toc) { 11 return; 12 } 13 14 // Settings & Defaults 15 var defaults = { 16 levels: 'h2, h3, h4, h5, h6', 17 heading: '', 18 headingLevel: 'h2', 19 listType: 'ul' 20 }; 21 var settings = {}; 22 23 // Placeholder for headings 24 var headings; 25 26 27 // 28 // Methods 29 // 30 31 /** 32 * Merge user options into defaults 33 * @param {Object} obj The user options 34 */ 35 var merge = function (obj) { 36 for (var key in defaults) { 37 if (Object.prototype.hasOwnProperty.call(defaults, key)) { 38 settings[key] = Object.prototype.hasOwnProperty.call(obj, key) ? obj[key] : defaults[key]; 39 } 40 } 41 }; 42 43 /** 44 * Create an ID for a heading if one does not exist 45 * @param {Node} heading The heading element 46 */ 47 var createID = function (heading) { 48 if (heading.id.length) { 49 return; 50 } 51 heading.id = 'toc_' + heading.textContent.replace(/[^A-Za-z0-9]/g, '-'); 52 }; 53 54 /** 55 * Get the HTML to indent a list a specific number of levels 56 * @param {Integer} count The number of times to indent the list 57 * @return {String} The HTML 58 */ 59 var getIndent = function (count) { 60 var html = ''; 61 for (var i = 0; i < count; i++) { 62 html += '<' + settings.listType + '>'; 63 } 64 return html; 65 }; 66 67 /** 68 * Get the HTML to close an indented list a specific number of levels 69 * @param {Integer} count The number of times to "outdent" the list 70 * @return {String} The HTML 71 */ 72 var getOutdent = function (count) { 73 var html = ''; 74 for (var i = 0; i < count; i++) { 75 html += '</' + settings.listType + '></li>'; 76 } 77 return html; 78 }; 79 80 /** 81 * Get the HTML string to start a new list of headings 82 * @param {Integer} diff The number of levels in or out from the current level the list is 83 * @param {Integer} index The index of the heading in the "headings" NodeList 84 * @return {String} The HTML 85 */ 86 var getStartingHTML = function (diff, index) { 87 88 // If indenting 89 if (diff > 0) { 90 return getIndent(diff); 91 } 92 93 // If outdenting 94 if (diff < 0) { 95 return getOutdent(Math.abs(diff)); 96 } 97 98 // If it's not the first item and there's no difference 99 if (index && !diff) { 100 return '</li>'; 101 } 102 103 return ''; 104 105 }; 106 107 /** 108 * Inject the table of contents into the DOM 109 */ 110 var injectTOC = function () { 111 112 // Track the current heading level 113 var level = headings[0].tagName.slice(1); 114 var startingLevel = level; 115 116 // Cache the number of headings 117 var len = headings.length - 1; 118 119 // Inject the HTML into the DOM 120 toc.innerHTML = 121 '<div class="tocheading"><span>' + settings.heading + '</span></div>' + 122 '<' + settings.listType + ' class="toclist">' + 123 Array.prototype.map.call(headings, function (heading, index) { 124 125 // Add an ID if one is missing 126 createID(heading); 127 128 // Check the heading level vs. the current list 129 var currentLevel = heading.tagName.slice(1); 130 var levelDifference = currentLevel - level; 131 level = currentLevel; 132 var html = getStartingHTML(levelDifference, index); 133 134 // Generate the HTML 135 html += 136 '<li>' + 137 '<a href="#' + heading.id + '">' + 138 heading.innerHTML.trim() + 139 '</a>'; 140 141 // If the last item, close it all out 142 if (index === len) { 143 html += getOutdent(Math.abs(startingLevel - currentLevel)); 144 } 145 146 return html; 147 148 }).join('') + 149 '</' + settings.listType + '>'; 150 }; 151 152 /** 153 * Initialize the script 154 */ 155 var init = function () { 156 157 // Merge any user settings into the defaults 158 merge(options || {}); 159 160 // Get the headings 161 // If none are found, don't render a list
162 headings = contentWrap.querySelectorAll(settings.levels); 163 if (!headings.length) { 164 return; 165 } 166 167 // Inject the table of contents 168 injectTOC(); 169 170 }; 171 172 173 // 174 // Initialize the script 175 // 176 177 init(); 178 179}; 180 181var elements = document.querySelectorAll('[id^="datatoc"]'); 182 183elements.forEach(function (element, index) { 184 element.setAttribute('data-toc-' + (index + 1), ''); 185 186 var titleAttribute = element.getAttribute('title') || ''; 187 var headingAttribute = element.getAttribute('heading') || 'h2,h3'; 188 189 tableOfContents('[data-content]', '[data-toc-' + (index + 1) + ']', { 190 heading: titleAttribute, 191 listType: 'ul', 192 levels: headingAttribute 193 }); 194 195 document.addEventListener('DOMContentLoaded', function () { 196 197 var toggleListValue = element.getAttribute('toggle_list'); 198 if (toggleListValue === 'true') { 199 200 var tocheading = element.querySelector('.tocheading'); 201 if (tocheading) { 202 tocheading.classList.add('active'); 203 } 204 205 } 206 }); 207 208 document.addEventListener('DOMContentLoaded', function () { 209 var tocheading = element.querySelector('.tocheading'); 210 211 tocheading.addEventListener('click', function () { 212 this.classList.toggle('active'); 213 var toclist = this.nextElementSibling; 214 215 if (this.classList.contains('active')) { 216 toclist.style.display = 'block'; 217 } else { 218 toclist.style.display = 'none'; 219 } 220 }); 221 }); 222}); 223 224 225function loadDemo(button) { 226 var parentElement = button.parentElement; 227 var nextElement = parentElement.nextElementSibling; 228 229 const demoLink = button.getAttribute('link'); 230 231 if (demoLink && nextElement) { 232 nextElement.src = demoLink; 233 button.parentElement.style.display = 'none'; 234 } 235}
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.