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