github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/tools/godoc/static/godocs.js (about) 1 // Copyright 2012 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 /* A little code to ease navigation of these documents. 6 * 7 * On window load we: 8 * + Bind search box hint placeholder show/hide events (bindSearchEvents) 9 * + Generate a table of contents (generateTOC) 10 * + Bind foldable sections (bindToggles) 11 * + Bind links to foldable sections (bindToggleLinks) 12 */ 13 14 (function() { 15 'use strict'; 16 17 // Mobile-friendly topbar menu 18 $(function() { 19 var menu = $('#menu'); 20 var menuButton = $('#menu-button'); 21 var menuButtonArrow = $('#menu-button-arrow'); 22 menuButton.click(function(event) { 23 menu.toggleClass('menu-visible'); 24 menuButtonArrow.toggleClass('vertical-flip'); 25 event.preventDefault(); 26 return false; 27 }); 28 }); 29 30 function bindSearchEvents() { 31 32 var search = $('#search'); 33 if (search.length === 0) { 34 return; // no search box 35 } 36 37 function clearInactive() { 38 if (search.is('.inactive')) { 39 search.val(''); 40 search.removeClass('inactive'); 41 } 42 } 43 44 function restoreInactive() { 45 if (search.val() !== '') { 46 return; 47 } 48 search.val(search.attr('placeholder')); 49 search.addClass('inactive'); 50 } 51 52 search.on('focus', clearInactive); 53 search.on('blur', restoreInactive); 54 55 restoreInactive(); 56 } 57 58 /* Generates a table of contents: looks for h2 and h3 elements and generates 59 * links. "Decorates" the element with id=="nav" with this table of contents. 60 */ 61 function generateTOC() { 62 if ($('#manual-nav').length > 0) { 63 return; 64 } 65 66 var nav = $('#nav'); 67 if (nav.length === 0) { 68 return; 69 } 70 71 var toc_items = []; 72 $(nav).nextAll('h2, h3').each(function() { 73 var node = this; 74 if (node.id == '') 75 node.id = 'tmp_' + toc_items.length; 76 var link = $('<a/>').attr('href', '#' + node.id).text($(node).text()); 77 var item; 78 if ($(node).is('h2')) { 79 item = $('<dt/>'); 80 } else { // h3 81 item = $('<dd class="indent"/>'); 82 } 83 item.append(link); 84 toc_items.push(item); 85 }); 86 if (toc_items.length <= 1) { 87 return; 88 } 89 90 var dl1 = $('<dl/>'); 91 var dl2 = $('<dl/>'); 92 93 var split_index = (toc_items.length / 2) + 1; 94 if (split_index < 8) { 95 split_index = toc_items.length; 96 } 97 for (var i = 0; i < split_index; i++) { 98 dl1.append(toc_items[i]); 99 } 100 for (/* keep using i */; i < toc_items.length; i++) { 101 dl2.append(toc_items[i]); 102 } 103 104 var tocTable = $('<table class="unruled"/>').appendTo(nav); 105 var tocBody = $('<tbody/>').appendTo(tocTable); 106 var tocRow = $('<tr/>').appendTo(tocBody); 107 108 // 1st column 109 $('<td class="first"/>').appendTo(tocRow).append(dl1); 110 // 2nd column 111 $('<td/>').appendTo(tocRow).append(dl2); 112 } 113 114 function bindToggle(el) { 115 $('.toggleButton', el).click(function() { 116 if ($(el).is('.toggle')) { 117 $(el).addClass('toggleVisible').removeClass('toggle'); 118 } else { 119 $(el).addClass('toggle').removeClass('toggleVisible'); 120 } 121 }); 122 } 123 function bindToggles(selector) { 124 $(selector).each(function(i, el) { 125 bindToggle(el); 126 }); 127 } 128 129 function bindToggleLink(el, prefix) { 130 $(el).click(function() { 131 var href = $(el).attr('href'); 132 var i = href.indexOf('#'+prefix); 133 if (i < 0) { 134 return; 135 } 136 var id = '#' + prefix + href.slice(i+1+prefix.length); 137 if ($(id).is('.toggle')) { 138 $(id).find('.toggleButton').first().click(); 139 } 140 }); 141 } 142 function bindToggleLinks(selector, prefix) { 143 $(selector).each(function(i, el) { 144 bindToggleLink(el, prefix); 145 }); 146 } 147 148 function setupDropdownPlayground() { 149 if (!$('#page').is('.wide')) { 150 return; // don't show on front page 151 } 152 var button = $('#playgroundButton'); 153 var div = $('#playground'); 154 var setup = false; 155 button.toggle(function() { 156 button.addClass('active'); 157 div.show(); 158 if (setup) { 159 return; 160 } 161 setup = true; 162 playground({ 163 'codeEl': $('.code', div), 164 'outputEl': $('.output', div), 165 'runEl': $('.run', div), 166 'fmtEl': $('.fmt', div), 167 'shareEl': $('.share', div), 168 'shareRedirect': '//play.golang.org/p/' 169 }); 170 }, 171 function() { 172 button.removeClass('active'); 173 div.hide(); 174 }); 175 button.show(); 176 $('#menu').css('min-width', '+=60'); 177 } 178 179 function setupInlinePlayground() { 180 'use strict'; 181 // Set up playground when each element is toggled. 182 $('div.play').each(function (i, el) { 183 // Set up playground for this example. 184 var setup = function() { 185 var code = $('.code', el); 186 playground({ 187 'codeEl': code, 188 'outputEl': $('.output', el), 189 'runEl': $('.run', el), 190 'fmtEl': $('.fmt', el), 191 'shareEl': $('.share', el), 192 'shareRedirect': '//play.golang.org/p/' 193 }); 194 195 // Make the code textarea resize to fit content. 196 var resize = function() { 197 code.height(0); 198 var h = code[0].scrollHeight; 199 code.height(h+20); // minimize bouncing. 200 code.closest('.input').height(h); 201 }; 202 code.on('keydown', resize); 203 code.on('keyup', resize); 204 code.keyup(); // resize now. 205 }; 206 207 // If example already visible, set up playground now. 208 if ($(el).is(':visible')) { 209 setup(); 210 return; 211 } 212 213 // Otherwise, set up playground when example is expanded. 214 var built = false; 215 $(el).closest('.toggle').click(function() { 216 // Only set up once. 217 if (!built) { 218 setup(); 219 built = true; 220 } 221 }); 222 }); 223 } 224 225 // fixFocus tries to put focus to div#page so that keyboard navigation works. 226 function fixFocus() { 227 var page = $('div#page'); 228 var topbar = $('div#topbar'); 229 page.css('outline', 0); // disable outline when focused 230 page.attr('tabindex', -1); // and set tabindex so that it is focusable 231 $(window).resize(function (evt) { 232 // only focus page when the topbar is at fixed position (that is, it's in 233 // front of page, and keyboard event will go to the former by default.) 234 // by focusing page, keyboard event will go to page so that up/down arrow, 235 // space, etc. will work as expected. 236 if (topbar.css('position') == "fixed") 237 page.focus(); 238 }).resize(); 239 } 240 241 function toggleHash() { 242 var hash = $(window.location.hash); 243 if (hash.is('.toggle')) { 244 hash.find('.toggleButton').first().click(); 245 } 246 } 247 248 function personalizeInstallInstructions() { 249 var prefix = '?download='; 250 var s = window.location.search; 251 if (s.indexOf(prefix) != 0) { 252 // No 'download' query string; bail. 253 return; 254 } 255 256 var filename = s.substr(prefix.length); 257 var filenameRE = /^go1\.\d+(\.\d+)?([a-z0-9]+)?\.([a-z0-9]+)(-[a-z0-9]+)?(-osx10\.[68])?\.([a-z.]+)$/; 258 $('.downloadFilename').text(filename); 259 $('.hideFromDownload').hide(); 260 var m = filenameRE.exec(filename); 261 if (!m) { 262 // Can't interpret file name; bail. 263 return; 264 } 265 266 var os = m[3]; 267 var ext = m[6]; 268 if (ext != 'tar.gz') { 269 $('#tarballInstructions').hide(); 270 } 271 if (os != 'darwin' || ext != 'pkg') { 272 $('#darwinPackageInstructions').hide(); 273 } 274 if (os != 'windows') { 275 $('#windowsInstructions').hide(); 276 $('.testUnix').show(); 277 $('.testWindows').hide(); 278 } else { 279 if (ext != 'msi') { 280 $('#windowsInstallerInstructions').hide(); 281 } 282 if (ext != 'zip') { 283 $('#windowsZipInstructions').hide(); 284 } 285 $('.testUnix').hide(); 286 $('.testWindows').show(); 287 } 288 289 var download = "https://storage.googleapis.com/golang/" + filename; 290 291 var message = $('<p class="downloading">'+ 292 'Your download should begin shortly. '+ 293 'If it does not, click <a>this link</a>.</p>'); 294 message.find('a').attr('href', download); 295 message.insertAfter('#nav'); 296 297 window.location = download; 298 } 299 300 $(document).ready(function() { 301 bindSearchEvents(); 302 generateTOC(); 303 bindToggles(".toggle"); 304 bindToggles(".toggleVisible"); 305 bindToggleLinks(".exampleLink", "example_"); 306 bindToggleLinks(".overviewLink", ""); 307 bindToggleLinks(".examplesLink", ""); 308 bindToggleLinks(".indexLink", ""); 309 setupDropdownPlayground(); 310 setupInlinePlayground(); 311 fixFocus(); 312 setupTypeInfo(); 313 setupCallgraphs(); 314 toggleHash(); 315 personalizeInstallInstructions(); 316 317 // godoc.html defines window.initFuncs in the <head> tag, and root.html and 318 // codewalk.js push their on-page-ready functions to the list. 319 // We execute those functions here, to avoid loading jQuery until the page 320 // content is loaded. 321 for (var i = 0; i < window.initFuncs.length; i++) window.initFuncs[i](); 322 }); 323 324 // -- analysis --------------------------------------------------------- 325 326 // escapeHTML returns HTML for s, with metacharacters quoted. 327 // It is safe for use in both elements and attributes 328 // (unlike the "set innerText, read innerHTML" trick). 329 function escapeHTML(s) { 330 return s.replace(/&/g, '&'). 331 replace(/\"/g, '"'). 332 replace(/\'/g, '''). 333 replace(/</g, '<'). 334 replace(/>/g, '>'); 335 } 336 337 // makeAnchor returns HTML for an <a> element, given an anchorJSON object. 338 function makeAnchor(json) { 339 var html = escapeHTML(json.Text); 340 if (json.Href != "") { 341 html = "<a href='" + escapeHTML(json.Href) + "'>" + html + "</a>"; 342 } 343 return html; 344 } 345 346 function showLowFrame(html) { 347 var lowframe = document.getElementById('lowframe'); 348 lowframe.style.height = "200px"; 349 lowframe.innerHTML = "<p style='text-align: left;'>" + html + "</p>\n" + 350 "<div onclick='hideLowFrame()' style='position: absolute; top: 0; right: 0; cursor: pointer;'>✘</div>" 351 }; 352 353 document.hideLowFrame = function() { 354 var lowframe = document.getElementById('lowframe'); 355 lowframe.style.height = "0px"; 356 } 357 358 // onClickCallers is the onclick action for the 'func' tokens of a 359 // function declaration. 360 document.onClickCallers = function(index) { 361 var data = document.ANALYSIS_DATA[index] 362 if (data.Callers.length == 1 && data.Callers[0].Sites.length == 1) { 363 document.location = data.Callers[0].Sites[0].Href; // jump to sole caller 364 return; 365 } 366 367 var html = "Callers of <code>" + escapeHTML(data.Callee) + "</code>:<br/>\n"; 368 for (var i = 0; i < data.Callers.length; i++) { 369 var caller = data.Callers[i]; 370 html += "<code>" + escapeHTML(caller.Func) + "</code>"; 371 var sites = caller.Sites; 372 if (sites != null && sites.length > 0) { 373 html += " at line "; 374 for (var j = 0; j < sites.length; j++) { 375 if (j > 0) { 376 html += ", "; 377 } 378 html += "<code>" + makeAnchor(sites[j]) + "</code>"; 379 } 380 } 381 html += "<br/>\n"; 382 } 383 showLowFrame(html); 384 }; 385 386 // onClickCallees is the onclick action for the '(' token of a function call. 387 document.onClickCallees = function(index) { 388 var data = document.ANALYSIS_DATA[index] 389 if (data.Callees.length == 1) { 390 document.location = data.Callees[0].Href; // jump to sole callee 391 return; 392 } 393 394 var html = "Callees of this " + escapeHTML(data.Descr) + ":<br/>\n"; 395 for (var i = 0; i < data.Callees.length; i++) { 396 html += "<code>" + makeAnchor(data.Callees[i]) + "</code><br/>\n"; 397 } 398 showLowFrame(html); 399 }; 400 401 // onClickTypeInfo is the onclick action for identifiers declaring a named type. 402 document.onClickTypeInfo = function(index) { 403 var data = document.ANALYSIS_DATA[index]; 404 var html = "Type <code>" + data.Name + "</code>: " + 405 " <small>(size=" + data.Size + ", align=" + data.Align + ")</small><br/>\n"; 406 html += implementsHTML(data); 407 html += methodsetHTML(data); 408 showLowFrame(html); 409 }; 410 411 // implementsHTML returns HTML for the implements relation of the 412 // specified TypeInfoJSON value. 413 function implementsHTML(info) { 414 var html = ""; 415 if (info.ImplGroups != null) { 416 for (var i = 0; i < info.ImplGroups.length; i++) { 417 var group = info.ImplGroups[i]; 418 var x = "<code>" + escapeHTML(group.Descr) + "</code> "; 419 for (var j = 0; j < group.Facts.length; j++) { 420 var fact = group.Facts[j]; 421 var y = "<code>" + makeAnchor(fact.Other) + "</code>"; 422 if (fact.ByKind != null) { 423 html += escapeHTML(fact.ByKind) + " type " + y + " implements " + x; 424 } else { 425 html += x + " implements " + y; 426 } 427 html += "<br/>\n"; 428 } 429 } 430 } 431 return html; 432 } 433 434 435 // methodsetHTML returns HTML for the methodset of the specified 436 // TypeInfoJSON value. 437 function methodsetHTML(info) { 438 var html = ""; 439 if (info.Methods != null) { 440 for (var i = 0; i < info.Methods.length; i++) { 441 html += "<code>" + makeAnchor(info.Methods[i]) + "</code><br/>\n"; 442 } 443 } 444 return html; 445 } 446 447 // onClickComm is the onclick action for channel "make" and "<-" 448 // send/receive tokens. 449 document.onClickComm = function(index) { 450 var ops = document.ANALYSIS_DATA[index].Ops 451 if (ops.length == 1) { 452 document.location = ops[0].Op.Href; // jump to sole element 453 return; 454 } 455 456 var html = "Operations on this channel:<br/>\n"; 457 for (var i = 0; i < ops.length; i++) { 458 html += makeAnchor(ops[i].Op) + " by <code>" + escapeHTML(ops[i].Fn) + "</code><br/>\n"; 459 } 460 if (ops.length == 0) { 461 html += "(none)<br/>\n"; 462 } 463 showLowFrame(html); 464 }; 465 466 $(window).load(function() { 467 // Scroll window so that first selection is visible. 468 // (This means we don't need to emit id='L%d' spans for each line.) 469 // TODO(adonovan): ideally, scroll it so that it's under the pointer, 470 // but I don't know how to get the pointer y coordinate. 471 var elts = document.getElementsByClassName("selection"); 472 if (elts.length > 0) { 473 elts[0].scrollIntoView() 474 } 475 }); 476 477 // setupTypeInfo populates the "Implements" and "Method set" toggle for 478 // each type in the package doc. 479 function setupTypeInfo() { 480 for (var i in document.ANALYSIS_DATA) { 481 var data = document.ANALYSIS_DATA[i]; 482 483 var el = document.getElementById("implements-" + i); 484 if (el != null) { 485 // el != null => data is TypeInfoJSON. 486 if (data.ImplGroups != null) { 487 el.innerHTML = implementsHTML(data); 488 el.parentNode.parentNode.style.display = "block"; 489 } 490 } 491 492 var el = document.getElementById("methodset-" + i); 493 if (el != null) { 494 // el != null => data is TypeInfoJSON. 495 if (data.Methods != null) { 496 el.innerHTML = methodsetHTML(data); 497 el.parentNode.parentNode.style.display = "block"; 498 } 499 } 500 } 501 } 502 503 function setupCallgraphs() { 504 if (document.CALLGRAPH == null) { 505 return 506 } 507 document.getElementById("pkg-callgraph").style.display = "block"; 508 509 var treeviews = document.getElementsByClassName("treeview"); 510 for (var i = 0; i < treeviews.length; i++) { 511 var tree = treeviews[i]; 512 if (tree.id == null || tree.id.indexOf("callgraph-") != 0) { 513 continue; 514 } 515 var id = tree.id.substring("callgraph-".length); 516 $(tree).treeview({collapsed: true, animated: "fast"}); 517 document.cgAddChildren(tree, tree, [id]); 518 tree.parentNode.parentNode.style.display = "block"; 519 } 520 } 521 522 document.cgAddChildren = function(tree, ul, indices) { 523 if (indices != null) { 524 for (var i = 0; i < indices.length; i++) { 525 var li = cgAddChild(tree, ul, document.CALLGRAPH[indices[i]]); 526 if (i == indices.length - 1) { 527 $(li).addClass("last"); 528 } 529 } 530 } 531 $(tree).treeview({animated: "fast", add: ul}); 532 } 533 534 // cgAddChild adds an <li> element for document.CALLGRAPH node cgn to 535 // the parent <ul> element ul. tree is the tree's root <ul> element. 536 function cgAddChild(tree, ul, cgn) { 537 var li = document.createElement("li"); 538 ul.appendChild(li); 539 li.className = "closed"; 540 541 var code = document.createElement("code"); 542 543 if (cgn.Callees != null) { 544 $(li).addClass("expandable"); 545 546 // Event handlers and innerHTML updates don't play nicely together, 547 // hence all this explicit DOM manipulation. 548 var hitarea = document.createElement("div"); 549 hitarea.className = "hitarea expandable-hitarea"; 550 li.appendChild(hitarea); 551 552 li.appendChild(code); 553 554 var childUL = document.createElement("ul"); 555 li.appendChild(childUL); 556 childUL.setAttribute('style', "display: none;"); 557 558 var onClick = function() { 559 document.cgAddChildren(tree, childUL, cgn.Callees); 560 hitarea.removeEventListener('click', onClick) 561 }; 562 hitarea.addEventListener('click', onClick); 563 564 } else { 565 li.appendChild(code); 566 } 567 code.innerHTML += " " + makeAnchor(cgn.Func); 568 return li 569 } 570 571 })();