Brian Silverman | 1a67511 | 2016-02-20 20:42:49 -0500 | [diff] [blame^] | 1 | TocTypeEnum = { |
| 2 | VERTICAL: 1, |
| 3 | HORIZONTAL: 2 |
| 4 | }; |
| 5 | |
| 6 | function CreateTOC(tocElement) { |
| 7 | |
| 8 | // Find the toc element DIV. We'll place our TOC there. |
| 9 | var toc = document.getElementById(tocElement); |
| 10 | |
| 11 | var tocTypeClass = toc.className; |
| 12 | var tocType; |
| 13 | |
| 14 | switch (tocTypeClass) { |
| 15 | case 'horizontal_toc': |
| 16 | tocType = TocTypeEnum.HORIZONTAL; |
| 17 | break; |
| 18 | case 'vertical_toc': |
| 19 | tocType = TocTypeEnum.VERTICAL; |
| 20 | break; |
| 21 | default: |
| 22 | tocType = TocTypeEnum.VERTICAL; |
| 23 | break; |
| 24 | } |
| 25 | |
| 26 | // If toc_levels is defined, set headingLevels to it. |
| 27 | // Otherwise, use default value of "h2,h3" |
| 28 | var headingLevels; |
| 29 | if (typeof toc_levels === 'undefined') { |
| 30 | headingLevels = 'h2,h3'; |
| 31 | } else { |
| 32 | |
| 33 | } |
| 34 | |
| 35 | // Collect all section heading elements in an array |
| 36 | var headings = document.querySelectorAll(headingLevels); |
| 37 | |
| 38 | // Add TOC title elements |
| 39 | var tocHeadingDiv = document.createElement('div'); |
| 40 | toc.appendChild(tocHeadingDiv); |
| 41 | tocHeadingDiv.className = 'toc_title'; |
| 42 | var tocHeading = document.createElement('h3'); |
| 43 | toc.appendChild(tocHeading); |
| 44 | tocHeading.className = 'ignoreLink'; |
| 45 | tocHeading.id = 'toc'; |
| 46 | var tocText = document.createTextNode('Table of Contents'); |
| 47 | tocHeading.appendChild(tocText); |
| 48 | |
| 49 | // Add table and tbody |
| 50 | var tocTable = document.createElement('table'); |
| 51 | if (tocType == TocTypeEnum.VERTICAL) { |
| 52 | tocTable.className = 'columns'; |
| 53 | } |
| 54 | toc.appendChild(tocTable); |
| 55 | |
| 56 | var tbody_element = document.createElement('tbody'); |
| 57 | tbody_element.setAttribute('valign', 'top'); |
| 58 | tbody_element.className = 'toc'; |
| 59 | tocTable.appendChild(tbody_element); |
| 60 | |
| 61 | // Get the highest level heading |
| 62 | var firstHeading = headings[0]; |
| 63 | var masterLevel = parseInt(headingLevels.charAt(1)); |
| 64 | |
| 65 | // Get the lowest heading level |
| 66 | var lowestLevel = parseInt(headingLevels.charAt(headingLevels - 1)); |
| 67 | |
| 68 | switch (tocType) { |
| 69 | case TocTypeEnum.HORIZONTAL: |
| 70 | CreateHorizontalTOC(headings, masterLevel, lowestLevel, tbody_element); |
| 71 | break; |
| 72 | case TocTypeEnum.VERTICAL: |
| 73 | CreateVerticalTOC(headings, masterLevel, lowestLevel, tbody_element); |
| 74 | break; |
| 75 | default: |
| 76 | } |
| 77 | } |
| 78 | |
| 79 | function CreateHorizontalTOC( |
| 80 | headings, masterLevel, lowestLevel, tbody_element) { |
| 81 | |
| 82 | // Initialize the header counter |
| 83 | var h = 0; |
| 84 | var ignoreChildren = false; |
| 85 | |
| 86 | while (h < headings.length) { |
| 87 | // Get current heading |
| 88 | var heading = headings[h]; |
| 89 | |
| 90 | // Get the current heading level |
| 91 | var level = parseInt(heading.tagName.charAt(1)); |
| 92 | |
| 93 | if (isNaN(level) || level < 1 || level > lowestLevel) continue; |
| 94 | |
| 95 | // If level is a masterLevel, make it a TOC parent category |
| 96 | if ((level == masterLevel) && (!hasClass(heading, 'ignoreLink'))) { |
| 97 | toc_current_row = AddTOCMaster(tbody_element, heading); |
| 98 | ignoreChildren = false; |
| 99 | } |
| 100 | |
| 101 | if ((level == masterLevel) && (hasClass(heading, 'ignoreLink'))) { |
| 102 | ignoreChildren = true; |
| 103 | } |
| 104 | |
| 105 | if ((level != masterLevel) && (!ignoreChildren)) { |
| 106 | AddTOCElements(toc_current_row, heading); |
| 107 | } |
| 108 | |
| 109 | // Advance the header counter |
| 110 | h++; |
| 111 | } |
| 112 | } |
| 113 | |
| 114 | // Adds a master Table of Content heading |
| 115 | function AddTOCMaster(tocTable, heading) { |
| 116 | |
| 117 | // Add the table row scaffolding |
| 118 | var toc_tr = document.createElement('tr'); |
| 119 | tocTable.appendChild(toc_tr); |
| 120 | toc_tr.setAttribute('valign', 'top'); |
| 121 | var toc_tr_td = document.createElement('td'); |
| 122 | toc_tr.appendChild(toc_tr_td); |
| 123 | var toc_category = document.createElement('div'); |
| 124 | toc_tr_td.appendChild(toc_category); |
| 125 | toc_category.className = 'toc_category'; |
| 126 | |
| 127 | // Create the link to this header |
| 128 | var link = document.createElement('a'); |
| 129 | link.href = '#' + heading.id; // Create the anchor link |
| 130 | link.textContent = heading.textContent; // Link text is same as heading |
| 131 | toc_category.appendChild(link); |
| 132 | |
| 133 | // Add the container table cell for its children |
| 134 | var toc_td = document.createElement('td'); |
| 135 | toc_tr.appendChild(toc_td); |
| 136 | var toc_td_div = document.createElement('div'); |
| 137 | toc_td_div.className = 'toc_stylepoint'; |
| 138 | toc_td.appendChild(toc_td_div); |
| 139 | |
| 140 | return (toc_td_div); |
| 141 | } |
| 142 | |
| 143 | // Adds Table of Contents element to a master heading as children |
| 144 | function AddTOCElements(toc_div, heading) { |
| 145 | |
| 146 | if (heading.offsetParent === null) { |
| 147 | // The element is currently hidden, so don't create a TOC entry |
| 148 | } else { |
| 149 | // Create the list item element |
| 150 | var toc_list_element = document.createElement('li'); |
| 151 | toc_list_element.className = 'toc_entry'; |
| 152 | toc_div.appendChild(toc_list_element); |
| 153 | |
| 154 | // Create the link to this header |
| 155 | var link = document.createElement('a'); |
| 156 | link.href = '#' + heading.id; // Create the anchor link |
| 157 | link.textContent = heading.textContent; // Link text is same as heading |
| 158 | toc_list_element.appendChild(link); |
| 159 | } |
| 160 | } |
| 161 | |
| 162 | function CreateVerticalTOC(headings, masterLevel, lowestLevel, tbody_element) { |
| 163 | |
| 164 | // Create the Column scaffolding |
| 165 | var toc_tr = document.createElement('tr'); |
| 166 | tbody_element.appendChild(toc_tr); |
| 167 | var toc_tr_td = document.createElement('td'); |
| 168 | toc_tr_td.className = 'two_columns'; |
| 169 | toc_tr.appendChild(toc_tr_td); |
| 170 | |
| 171 | |
| 172 | // Initialize the header counter and the current row |
| 173 | var h = 0; |
| 174 | var toc_current_col = null; |
| 175 | var ignoreChildren = false; |
| 176 | |
| 177 | while (h < headings.length) { |
| 178 | // Get current heading |
| 179 | var heading = headings[h]; |
| 180 | |
| 181 | // Get the current heading level |
| 182 | var level = parseInt(heading.tagName.charAt(1)); |
| 183 | |
| 184 | if (isNaN(level) || level < 1 || level > lowestLevel) continue; |
| 185 | |
| 186 | // If level is a masterLevel, make it a TOC parent category |
| 187 | if ((level == masterLevel) && (!hasClass(heading, 'ignoreLink'))) { |
| 188 | if (heading.offsetParent === null) { |
| 189 | // The element is currently hidden, so don't create a TOC entry |
| 190 | } else { |
| 191 | var td_dl = document.createElement('dl'); |
| 192 | toc_tr_td.appendChild(td_dl); |
| 193 | var td_dt = document.createElement('dt'); |
| 194 | td_dl.appendChild(td_dt); |
| 195 | toc_current_col = td_dl; |
| 196 | |
| 197 | // Create the link to this header |
| 198 | var link = document.createElement('a'); |
| 199 | link.href = '#' + heading.id; // Create the anchor link |
| 200 | link.textContent = heading.textContent; // Link text is same as heading |
| 201 | td_dt.appendChild(link); |
| 202 | ignoreChildren = false; |
| 203 | } |
| 204 | } |
| 205 | |
| 206 | // If level is a masterLevel but it's specified to ignore links, skip it |
| 207 | // and its children. |
| 208 | if ((level == masterLevel) && (hasClass(heading, 'ignoreLink'))) { |
| 209 | ignoreChildren = true; |
| 210 | } |
| 211 | |
| 212 | if ((level != masterLevel) && (!ignoreChildren)) { |
| 213 | if (heading.offsetParent === null) { |
| 214 | // The element is currently hidden, so don't create a TOC entry |
| 215 | } else { |
| 216 | var td_dd = document.createElement('dd'); |
| 217 | toc_current_col.appendChild(td_dd); |
| 218 | // Create the link to this header |
| 219 | var link = document.createElement('a'); |
| 220 | link.href = '#' + heading.id; // Create the anchor link |
| 221 | link.textContent = heading.textContent; // Link text is same as heading |
| 222 | td_dd.appendChild(link); |
| 223 | } |
| 224 | } |
| 225 | |
| 226 | // Advance the header counter |
| 227 | h++; |
| 228 | } |
| 229 | } |
| 230 | |
| 231 | /* |
| 232 | * Utility function for finding elements with a given |
| 233 | * class. |
| 234 | */ |
| 235 | function hasClass(element, cls) { |
| 236 | return (' ' + element.className + ' ').indexOf(' ' + cls + ' ') > -1; |
| 237 | } |
| 238 | |
| 239 | /* |
| 240 | * Linkify all h2 through h4 headers, except for those marked |
| 241 | * "ignoreLink" |
| 242 | */ |
| 243 | |
| 244 | // Add the link image to the element. |
| 245 | function LinkifyHeader(header, fileName, sizePixels) { |
| 246 | var link = document.createElement('a'); |
| 247 | link.href = '#' + header.id; |
| 248 | link.alt = 'link to ' + header.id; |
| 249 | link.innerHTML = |
| 250 | '<img src="include/' + fileName + '"' + |
| 251 | ' width=' + sizePixels + |
| 252 | ' height=' + sizePixels + |
| 253 | ' style="float:left;position:relative;bottom:5px;">'; |
| 254 | header.appendChild(link); |
| 255 | } |
| 256 | |
| 257 | // Find all elements of the given tag and linkify if |
| 258 | // they don't have 'ignoreLink' in their class. |
| 259 | function LinkifyHeadersForTag(tagName) { |
| 260 | var headers = document.getElementsByTagName(tagName); |
| 261 | var header; |
| 262 | for (var j = 0; j != headers.length; j++) { |
| 263 | header = headers[j]; |
| 264 | if (!hasClass(header, 'ignoreLink') && ('id' in header)) { |
| 265 | if (header.id != '') { |
| 266 | LinkifyHeader(header, 'link.png', 21); |
| 267 | header.style.left = '-46px'; |
| 268 | header.style.position = 'relative'; |
| 269 | } |
| 270 | } |
| 271 | } |
| 272 | } |
| 273 | |
| 274 | // Linkify all h2, h3, and h4s. h1s are titles. |
| 275 | function LinkifyHeaders() { |
| 276 | LinkifyHeadersForTag('h2'); |
| 277 | LinkifyHeadersForTag('h3'); |
| 278 | LinkifyHeadersForTag('h4'); |
| 279 | } |
| 280 | |
| 281 | /* |
| 282 | * Initialize the style guide by showing all internal |
| 283 | * elements and then linkifying the headers. |
| 284 | */ |
| 285 | |
| 286 | function initStyleGuide() { |
| 287 | LinkifyHeaders(); |
| 288 | CreateTOC('tocDiv'); |
| 289 | } |