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, '&amp;').
   331               replace(/\"/g, '&quot;').
   332               replace(/\'/g, '&#39;').
   333               replace(/</g, '&lt;').
   334               replace(/>/g, '&gt;');
   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    "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<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 += "&nbsp;" + makeAnchor(cgn.Func);
   568     return li
   569  }
   570  
   571  })();