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