]> git.proxmox.com Git - rustc.git/blame - src/librustdoc/html/static/main.js
New upstream version 1.23.0+dfsg1
[rustc.git] / src / librustdoc / html / static / main.js
CommitLineData
041b39d2
XL
1/*!
2 * Copyright 2014 The Rust Project Developers. See the COPYRIGHT
3 * file at the top-level directory of this distribution and at
4 * http://rust-lang.org/COPYRIGHT.
5 *
6 * Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
7 * http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
8 * <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
9 * option. This file may not be copied, modified, or distributed
10 * except according to those terms.
11 */
1a4d82fc
JJ
12
13/*jslint browser: true, es5: true */
14/*globals $: true, rootPath: true */
15
16(function() {
17 "use strict";
1a4d82fc 18
c34b1796
AL
19 // This mapping table should match the discriminants of
20 // `rustdoc::html::item_type::ItemType` type in Rust.
21 var itemTypes = ["mod",
22 "externcrate",
23 "import",
24 "struct",
25 "enum",
26 "fn",
27 "type",
28 "static",
29 "trait",
30 "impl",
31 "tymethod",
32 "method",
33 "structfield",
34 "variant",
35 "macro",
36 "primitive",
37 "associatedtype",
d9579d0f 38 "constant",
9e0c209e 39 "associatedconstant",
abe05a73
XL
40 "union",
41 "foreigntype"];
42
43 // On the search screen, so you remain on the last tab you opened.
44 //
45 // 0 for "Types/modules"
46 // 1 for "As parameters"
47 // 2 for "As return value"
48 var currentTab = 0;
c34b1796 49
7cac9316
XL
50 function hasClass(elem, className) {
51 if (elem && className && elem.className) {
52 var elemClass = elem.className;
53 var start = elemClass.indexOf(className);
abe05a73 54 if (start === -1) {
7cac9316 55 return false;
abe05a73 56 } else if (elemClass.length === className.length) {
7cac9316
XL
57 return true;
58 } else {
abe05a73 59 if (start > 0 && elemClass[start - 1] !== ' ') {
7cac9316
XL
60 return false;
61 }
62 var end = start + className.length;
abe05a73 63 if (end < elemClass.length && elemClass[end] !== ' ') {
7cac9316
XL
64 return false;
65 }
66 return true;
67 }
abe05a73
XL
68 if (start > 0 && elemClass[start - 1] !== ' ') {
69 return false;
70 }
71 var end = start + className.length;
72 if (end < elemClass.length && elemClass[end] !== ' ') {
73 return false;
74 }
75 return true;
7cac9316
XL
76 }
77 return false;
78 }
79
80 function addClass(elem, className) {
81 if (elem && className && !hasClass(elem, className)) {
82 if (elem.className && elem.className.length > 0) {
83 elem.className += ' ' + className;
84 } else {
85 elem.className = className;
86 }
87 }
88 }
89
90 function removeClass(elem, className) {
91 if (elem && className && elem.className) {
92 elem.className = (" " + elem.className + " ").replace(" " + className + " ", " ")
93 .trim();
94 }
95 }
96
97 function onEach(arr, func) {
98 if (arr && arr.length > 0 && func) {
99 for (var i = 0; i < arr.length; i++) {
100 func(arr[i]);
101 }
102 }
103 }
104
105 function isHidden(elem) {
106 return (elem.offsetParent === null)
107 }
108
62682a34
SL
109 // used for special search precedence
110 var TY_PRIMITIVE = itemTypes.indexOf("primitive");
111
7cac9316
XL
112 onEach(document.getElementsByClassName('js-only'), function(e) {
113 removeClass(e, 'js-only');
114 });
1a4d82fc
JJ
115
116 function getQueryStringParams() {
117 var params = {};
118 window.location.search.substring(1).split("&").
119 map(function(s) {
120 var pair = s.split("=");
121 params[decodeURIComponent(pair[0])] =
122 typeof pair[1] === "undefined" ?
123 null : decodeURIComponent(pair[1]);
124 });
125 return params;
126 }
127
128 function browserSupportsHistoryApi() {
b039eaaf
SL
129 return document.location.protocol != "file:" &&
130 window.history && typeof window.history.pushState === "function";
1a4d82fc
JJ
131 }
132
1a4d82fc 133 function highlightSourceLines(ev) {
abe05a73 134 var search = document.getElementById("search");
1a4d82fc
JJ
135 var i, from, to, match = window.location.hash.match(/^#?(\d+)(?:-(\d+))?$/);
136 if (match) {
137 from = parseInt(match[1], 10);
138 to = Math.min(50000, parseInt(match[2] || match[1], 10));
139 from = Math.min(from, to);
7cac9316
XL
140 var elem = document.getElementById(from);
141 if (!elem) {
1a4d82fc
JJ
142 return;
143 }
7cac9316
XL
144 if (ev === null) {
145 var x = document.getElementById(from);
146 if (x) {
147 x.scrollIntoView();
148 }
abe05a73 149 }
7cac9316
XL
150 onEach(document.getElementsByClassName('line-numbers'), function(e) {
151 onEach(e.getElementsByTagName('span'), function(i_e) {
152 removeClass(i_e, 'line-highlighted');
153 });
154 })
1a4d82fc 155 for (i = from; i <= to; ++i) {
7cac9316 156 addClass(document.getElementById(i), 'line-highlighted');
1a4d82fc 157 }
abe05a73
XL
158 } else if (ev !== null && search && !hasClass(search, "hidden") && ev.newURL) {
159 addClass(search, "hidden");
160 removeClass(document.getElementById("main"), "hidden");
161 var hash = ev.newURL.slice(ev.newURL.indexOf('#') + 1);
162 if (browserSupportsHistoryApi()) {
163 history.replaceState(hash, "", "?search=#" + hash);
164 }
165 var elem = document.getElementById(hash);
166 if (elem) {
167 elem.scrollIntoView();
168 }
1a4d82fc
JJ
169 }
170 }
171 highlightSourceLines(null);
7cac9316 172 window.onhashchange = highlightSourceLines;
1a4d82fc 173
c1a9b12d
SL
174 // Gets the human-readable string for the virtual-key code of the
175 // given KeyboardEvent, ev.
176 //
177 // This function is meant as a polyfill for KeyboardEvent#key,
178 // since it is not supported in Trident. We also test for
179 // KeyboardEvent#keyCode because the handleShortcut handler is
180 // also registered for the keydown event, because Blink doesn't fire
181 // keypress on hitting the Escape key.
182 //
183 // So I guess you could say things are getting pretty interoperable.
184 function getVirtualKey(ev) {
185 if ("key" in ev && typeof ev.key != "undefined")
186 return ev.key;
187
188 var c = ev.charCode || ev.keyCode;
189 if (c == 27)
190 return "Escape";
191 return String.fromCharCode(c);
192 }
193
abe05a73
XL
194 function displayHelp(display, ev) {
195 if (display === true) {
196 if (hasClass(help, "hidden")) {
197 ev.preventDefault();
198 removeClass(help, "hidden");
199 addClass(document.body, "blur");
200 }
201 } else if (!hasClass(help, "hidden")) {
202 ev.preventDefault();
203 addClass(help, "hidden");
204 removeClass(document.body, "blur");
205 }
206 }
207
c1a9b12d 208 function handleShortcut(ev) {
7cac9316 209 if (document.activeElement.tagName === "INPUT")
1a4d82fc 210 return;
1a4d82fc 211
92a42be0
SL
212 // Don't interfere with browser shortcuts
213 if (ev.ctrlKey || ev.altKey || ev.metaKey)
214 return;
215
7cac9316 216 var help = document.getElementById("help");
c1a9b12d
SL
217 switch (getVirtualKey(ev)) {
218 case "Escape":
7cac9316
XL
219 var search = document.getElementById("search");
220 if (!hasClass(help, "hidden")) {
abe05a73 221 displayHelp(false, ev);
7cac9316 222 } else if (!hasClass(search, "hidden")) {
c1a9b12d 223 ev.preventDefault();
7cac9316
XL
224 addClass(search, "hidden");
225 removeClass(document.getElementById("main"), "hidden");
9346a6ac 226 }
c1a9b12d
SL
227 break;
228
229 case "s":
230 case "S":
abe05a73 231 displayHelp(false, ev);
c1a9b12d
SL
232 ev.preventDefault();
233 focusSearchBar();
234 break;
235
a7813a04 236 case "+":
abe05a73 237 case "-":
3157f602 238 ev.preventDefault();
a7813a04
XL
239 toggleAllDocs();
240 break;
241
c1a9b12d 242 case "?":
abe05a73
XL
243 if (ev.shiftKey) {
244 displayHelp(true, ev);
1a4d82fc 245 }
c1a9b12d 246 break;
1a4d82fc 247 }
c1a9b12d
SL
248 }
249
7cac9316
XL
250 document.onkeypress = handleShortcut;
251 document.onkeydown = handleShortcut;
252 document.onclick = function(ev) {
253 if (hasClass(ev.target, 'collapse-toggle')) {
254 collapseDocs(ev.target);
255 } else if (hasClass(ev.target.parentNode, 'collapse-toggle')) {
256 collapseDocs(ev.target.parentNode);
257 } else if (ev.target.tagName === 'SPAN' && hasClass(ev.target.parentNode, 'line-numbers')) {
258 var prev_id = 0;
259
260 var set_fragment = function (name) {
261 if (browserSupportsHistoryApi()) {
262 history.replaceState(null, null, '#' + name);
263 window.hashchange();
264 } else {
265 location.replace('#' + name);
266 }
267 };
268
269 var cur_id = parseInt(ev.target.id, 10);
270
271 if (ev.shiftKey && prev_id) {
272 if (prev_id > cur_id) {
273 var tmp = prev_id;
274 prev_id = cur_id;
275 cur_id = tmp;
276 }
1a4d82fc 277
7cac9316
XL
278 set_fragment(prev_id + '-' + cur_id);
279 } else {
280 prev_id = cur_id;
1a4d82fc 281
7cac9316 282 set_fragment(cur_id);
1a4d82fc 283 }
7cac9316
XL
284 } else if (!hasClass(document.getElementById("help"), "hidden")) {
285 addClass(document.getElementById("help"), "hidden");
286 removeClass(document.body, "blur");
1a4d82fc 287 }
7cac9316 288 };
1a4d82fc 289
7cac9316
XL
290 var x = document.getElementsByClassName('version-selector');
291 if (x.length > 0) {
292 x[0].onchange = function() {
293 var i, match,
294 url = document.location.href,
295 stripped = '',
296 len = rootPath.match(/\.\.\//g).length + 1;
1a4d82fc 297
7cac9316
XL
298 for (i = 0; i < len; ++i) {
299 match = url.match(/\/[^\/]*$/);
300 if (i < len - 1) {
301 stripped = match[0] + stripped;
302 }
303 url = url.substring(0, url.length - match[0].length);
304 }
305
306 url += '/' + document.getElementsByClassName('version-selector')[0].value + stripped;
307
308 document.location.href = url;
309 };
310 }
c1a9b12d 311
1a4d82fc
JJ
312 /**
313 * A function to compute the Levenshtein distance between two strings
314 * Licensed under the Creative Commons Attribution-ShareAlike 3.0 Unported
315 * Full License can be found at http://creativecommons.org/licenses/by-sa/3.0/legalcode
316 * This code is an unmodified version of the code written by Marco de Wit
317 * and was found at http://stackoverflow.com/a/18514751/745719
318 */
319 var levenshtein = (function() {
320 var row2 = [];
321 return function(s1, s2) {
322 if (s1 === s2) {
323 return 0;
62682a34
SL
324 }
325 var s1_len = s1.length, s2_len = s2.length;
326 if (s1_len && s2_len) {
327 var i1 = 0, i2 = 0, a, b, c, c2, row = row2;
328 while (i1 < s1_len) {
329 row[i1] = ++i1;
330 }
331 while (i2 < s2_len) {
332 c2 = s2.charCodeAt(i2);
333 a = i2;
334 ++i2;
335 b = i2;
336 for (i1 = 0; i1 < s1_len; ++i1) {
337 c = a + (s1.charCodeAt(i1) !== c2 ? 1 : 0);
338 a = row[i1];
339 b = b < a ? (b < c ? b + 1 : c) : (a < c ? a + 1 : c);
340 row[i1] = b;
1a4d82fc 341 }
1a4d82fc 342 }
62682a34 343 return b;
1a4d82fc 344 }
62682a34 345 return s1_len + s2_len;
1a4d82fc
JJ
346 };
347 })();
348
349 function initSearch(rawSearchIndex) {
350 var currentResults, index, searchIndex;
351 var MAX_LEV_DISTANCE = 3;
abe05a73 352 var MAX_RESULTS = 200;
1a4d82fc
JJ
353 var params = getQueryStringParams();
354
355 // Populate search bar with query string search term when provided,
356 // but only if the input bar is empty. This avoid the obnoxious issue
357 // where you start trying to do a search, and the index loads, and
358 // suddenly your search is gone!
7cac9316
XL
359 if (document.getElementsByClassName("search-input")[0].value === "") {
360 document.getElementsByClassName("search-input")[0].value = params.search || '';
1a4d82fc
JJ
361 }
362
363 /**
364 * Executes the query and builds an index of results
365 * @param {[Object]} query [The user query]
366 * @param {[type]} max [The maximum results returned]
367 * @param {[type]} searchWords [The list of search words to query
368 * against]
369 * @return {[type]} [A search index of results]
370 */
371 function execQuery(query, max, searchWords) {
372 var valLower = query.query.toLowerCase(),
373 val = valLower,
374 typeFilter = itemTypeFromName(query.type),
abe05a73 375 results = {}, results_in_args = {}, results_returned = {},
1a4d82fc
JJ
376 split = valLower.split("::");
377
abe05a73
XL
378 for (var z = 0; z < split.length; ++z) {
379 if (split[z] === "") {
380 split.splice(z, 1);
381 z -= 1;
382 }
383 }
384
385 function transformResults(results, isType) {
386 var out = [];
387 for (i = 0; i < results.length; ++i) {
388 if (results[i].id > -1) {
389 var obj = searchIndex[results[i].id];
390 obj.lev = results[i].lev;
391 if (isType !== true || obj.type) {
392 out.push(obj);
393 }
394 }
395 if (out.length >= MAX_RESULTS) {
396 break;
397 }
398 }
399 return out;
400 }
401
402 function sortResults(results, isType) {
403 var ar = [];
404 for (var entry in results) {
405 if (results.hasOwnProperty(entry)) {
406 ar.push(results[entry]);
407 }
408 }
409 results = ar;
410 var nresults = results.length;
411 for (var i = 0; i < nresults; ++i) {
412 results[i].word = searchWords[results[i].id];
413 results[i].item = searchIndex[results[i].id] || {};
414 }
415 // if there are no results then return to default and fail
416 if (results.length === 0) {
417 return [];
418 }
419
420 results.sort(function(aaa, bbb) {
421 var a, b;
422
423 // Sort by non levenshtein results and then levenshtein results by the distance
424 // (less changes required to match means higher rankings)
425 a = (aaa.lev);
426 b = (bbb.lev);
427 if (a !== b) { return a - b; }
428
429 // sort by crate (non-current crate goes later)
430 a = (aaa.item.crate !== window.currentCrate);
431 b = (bbb.item.crate !== window.currentCrate);
432 if (a !== b) { return a - b; }
433
434 // sort by exact match (mismatch goes later)
435 a = (aaa.word !== valLower);
436 b = (bbb.word !== valLower);
437 if (a !== b) { return a - b; }
438
439 // sort by item name length (longer goes later)
440 a = aaa.word.length;
441 b = bbb.word.length;
442 if (a !== b) { return a - b; }
443
444 // sort by item name (lexicographically larger goes later)
445 a = aaa.word;
446 b = bbb.word;
447 if (a !== b) { return (a > b ? +1 : -1); }
448
449 // sort by index of keyword in item name (no literal occurrence goes later)
450 a = (aaa.index < 0);
451 b = (bbb.index < 0);
452 if (a !== b) { return a - b; }
453 // (later literal occurrence, if any, goes later)
454 a = aaa.index;
455 b = bbb.index;
456 if (a !== b) { return a - b; }
457
458 // special precedence for primitive pages
459 if ((aaa.item.ty === TY_PRIMITIVE) && (bbb.item.ty !== TY_PRIMITIVE)) {
460 return -1;
461 }
462 if ((bbb.item.ty === TY_PRIMITIVE) && (aaa.item.ty !== TY_PRIMITIVE)) {
463 return 1;
464 }
465
466 // sort by description (no description goes later)
467 a = (aaa.item.desc === '');
468 b = (bbb.item.desc === '');
469 if (a !== b) { return a - b; }
470
471 // sort by type (later occurrence in `itemTypes` goes later)
472 a = aaa.item.ty;
473 b = bbb.item.ty;
474 if (a !== b) { return a - b; }
475
476 // sort by path (lexicographically larger goes later)
477 a = aaa.item.path;
478 b = bbb.item.path;
479 if (a !== b) { return (a > b ? +1 : -1); }
480
481 // que sera, sera
482 return 0;
483 });
484
485 for (var i = 0; i < results.length; ++i) {
486 var result = results[i];
487
488 // this validation does not make sense when searching by types
489 if (result.dontValidate) {
490 continue;
491 }
492 var name = result.item.name.toLowerCase(),
493 path = result.item.path.toLowerCase(),
494 parent = result.item.parent;
495
496 if (isType !== true &&
497 validateResult(name, path, split, parent) === false)
498 {
499 result.id = -1;
500 }
501 }
502 return transformResults(results);
503 }
504
505 function extractGenerics(val) {
506 val = val.toLowerCase();
507 if (val.indexOf('<') !== -1) {
508 var values = val.substring(val.indexOf('<') + 1, val.lastIndexOf('>'));
509 return {
510 name: val.substring(0, val.indexOf('<')),
511 generics: values.split(/\s*,\s*/),
512 };
513 }
514 return {
515 name: val,
516 generics: [],
517 };
518 }
519
520 function checkGenerics(obj, val) {
521 // The names match, but we need to be sure that all generics kinda
522 // match as well.
523 var lev_distance = MAX_LEV_DISTANCE + 1;
524 if (val.generics.length > 0) {
525 if (obj.generics && obj.generics.length >= val.generics.length) {
526 var elems = obj.generics.slice(0);
527 var total = 0;
528 var done = 0;
529 // We need to find the type that matches the most to remove it in order
530 // to move forward.
531 for (var y = 0; y < val.generics.length; ++y) {
532 var lev = { pos: -1, lev: MAX_LEV_DISTANCE + 1};
533 for (var x = 0; x < elems.length; ++x) {
534 var tmp_lev = levenshtein(elems[x], val.generics[y]);
535 if (tmp_lev < lev.lev) {
536 lev.lev = tmp_lev;
537 lev.pos = x;
538 }
539 }
540 if (lev.pos !== -1) {
541 elems.splice(lev.pos, 1);
542 lev_distance = Math.min(lev.lev, lev_distance);
543 total += lev.lev;
544 done += 1;
545 } else {
546 return MAX_LEV_DISTANCE + 1;
547 }
548 }
549 return lev_distance;//Math.ceil(total / done);
550 }
551 }
552 return MAX_LEV_DISTANCE + 1;
553 }
554
555 // Check for type name and type generics (if any).
556 function checkType(obj, val, literalSearch) {
557 var lev_distance = MAX_LEV_DISTANCE + 1;
558 if (obj.name === val.name) {
559 if (literalSearch === true) {
560 if (val.generics.length !== 0) {
561 if (obj.generics && obj.length >= val.generics.length) {
562 var elems = obj.generics.slice(0);
563 var allFound = true;
564 var x;
565
566 for (var y = 0; allFound === true && y < val.generics.length; ++y) {
567 allFound = false;
568 for (x = 0; allFound === false && x < elems.length; ++x) {
569 allFound = elems[x] === val.generics[y];
570 }
571 if (allFound === true) {
572 elems.splice(x - 1, 1);
573 }
574 }
575 if (allFound === true) {
576 return true;
577 }
578 } else {
579 return false;
580 }
581 }
582 return true;
583 }
584 // If the type has generics but don't match, then it won't return at this point.
585 // Otherwise, `checkGenerics` will return 0 and it'll return.
586 if (obj.generics && obj.generics.length !== 0) {
587 var tmp_lev = checkGenerics(obj, val);
588 if (tmp_lev <= MAX_LEV_DISTANCE) {
589 return tmp_lev;
590 }
591 } else {
592 return 0;
593 }
594 }
595 // Names didn't match so let's check if one of the generic types could.
596 if (literalSearch === true) {
597 if (obj.generics.length > 0) {
598 for (var x = 0; x < obj.generics.length; ++x) {
599 if (obj.generics[x] === val.name) {
600 return true;
601 }
602 }
603 }
604 return false;
605 }
606 var lev_distance = Math.min(levenshtein(obj.name, val.name), lev_distance);
607 if (lev_distance <= MAX_LEV_DISTANCE) {
608 lev_distance = Math.min(checkGenerics(obj, val), lev_distance);
609 } else if (obj.generics && obj.generics.length > 0) {
610 // We can check if the type we're looking for is inside the generics!
611 for (var x = 0; x < obj.generics.length; ++x) {
612 lev_distance = Math.min(levenshtein(obj.generics[x], val.name),
613 lev_distance);
614 }
615 }
616 // Now whatever happens, the returned distance is "less good" so we should mark it
617 // as such, and so we add 1 to the distance to make it "less good".
618 return lev_distance + 1;
619 }
620
621 function findArg(obj, val, literalSearch) {
622 var lev_distance = MAX_LEV_DISTANCE + 1;
623
624 if (obj && obj.type && obj.type.inputs.length > 0) {
625 for (var i = 0; i < obj.type.inputs.length; i++) {
626 var tmp = checkType(obj.type.inputs[i], val, literalSearch);
627 if (literalSearch === true && tmp === true) {
628 return true;
629 }
630 lev_distance = Math.min(tmp, lev_distance);
631 if (lev_distance === 0) {
632 return 0;
633 }
634 }
635 }
636 return literalSearch === true ? false : lev_distance;
637 }
638
639 function checkReturned(obj, val, literalSearch) {
640 var lev_distance = MAX_LEV_DISTANCE + 1;
641
642 if (obj && obj.type && obj.type.output) {
643 var tmp = checkType(obj.type.output, val, literalSearch);
644 if (literalSearch === true && tmp === true) {
645 return true;
646 }
647 lev_distance = Math.min(tmp, lev_distance);
648 if (lev_distance === 0) {
649 return 0;
650 }
651 }
652 return literalSearch === true ? false : lev_distance;
653 }
654
655 function checkPath(startsWith, lastElem, ty) {
656 var ret_lev = MAX_LEV_DISTANCE + 1;
657 var path = ty.path.split("::");
658
659 if (ty.parent && ty.parent.name) {
660 path.push(ty.parent.name.toLowerCase());
661 }
662
663 if (startsWith.length > path.length) {
664 return MAX_LEV_DISTANCE + 1;
665 }
666 for (var i = 0; i < path.length; ++i) {
667 if (i + startsWith.length > path.length) {
668 break;
669 }
670 var lev_total = 0;
671 var aborted = false;
672 for (var x = 0; x < startsWith.length; ++x) {
673 var lev = levenshtein(path[i + x], startsWith[x]);
674 if (lev > MAX_LEV_DISTANCE) {
675 aborted = true;
676 break;
677 }
678 lev_total += lev;
679 }
680 if (aborted === false) {
681 var extra = MAX_LEV_DISTANCE + 1;
682 if (i + startsWith.length < path.length) {
683 extra = levenshtein(path[i + startsWith.length], lastElem);
684 }
685 if (extra > MAX_LEV_DISTANCE) {
686 extra = levenshtein(ty.name, lastElem);
687 }
688 if (extra < MAX_LEV_DISTANCE + 1) {
689 lev_total += extra;
690 ret_lev = Math.min(ret_lev,
691 Math.round(lev_total / (startsWith.length + 1)));
692 }
693 }
1a4d82fc 694 }
abe05a73 695 return ret_lev;
1a4d82fc
JJ
696 }
697
e9174d1e
SL
698 function typePassesFilter(filter, type) {
699 // No filter
700 if (filter < 0) return true;
701
702 // Exact match
703 if (filter === type) return true;
704
705 // Match related items
706 var name = itemTypes[type];
707 switch (itemTypes[filter]) {
708 case "constant":
709 return (name == "associatedconstant");
710 case "fn":
711 return (name == "method" || name == "tymethod");
712 case "type":
713 return (name == "primitive");
714 }
715
716 // No match
717 return false;
718 }
719
abe05a73
XL
720 function generateId(ty) {
721 if (ty.parent && ty.parent.name) {
722 return itemTypes[ty.ty] + ty.path + ty.parent.name + ty.name;
723 }
724 return itemTypes[ty.ty] + ty.path + ty.name;
725 }
726
1a4d82fc
JJ
727 // quoted values mean literal search
728 var nSearchWords = searchWords.length;
729 if ((val.charAt(0) === "\"" || val.charAt(0) === "'") &&
730 val.charAt(val.length - 1) === val.charAt(0))
731 {
abe05a73 732 val = extractGenerics(val.substr(1, val.length - 2));
1a4d82fc 733 for (var i = 0; i < nSearchWords; ++i) {
abe05a73
XL
734 var in_args = findArg(searchIndex[i], val, true);
735 var returned = checkReturned(searchIndex[i], val, true);
736 var ty = searchIndex[i];
737 var fullId = generateId(ty);
738
739 if (searchWords[i] === val.name) {
1a4d82fc 740 // filter type: ... queries
abe05a73
XL
741 if (typePassesFilter(typeFilter, searchIndex[i].ty) &&
742 results[fullId] === undefined)
743 {
744 results[fullId] = {id: i, index: -1};
745 }
746 } else if ((in_args === true || returned === true) &&
747 typePassesFilter(typeFilter, searchIndex[i].ty)) {
748 if (in_args === true || returned === true) {
749 if (in_args === true) {
750 results_in_args[fullId] = {
751 id: i,
752 index: -1,
753 dontValidate: true,
754 };
755 }
756 if (returned === true) {
757 results_returned[fullId] = {
758 id: i,
759 index: -1,
760 dontValidate: true,
761 };
762 }
763 } else {
764 results[fullId] = {
765 id: i,
766 index: -1,
767 dontValidate: true,
768 };
1a4d82fc 769 }
1a4d82fc
JJ
770 }
771 }
abe05a73
XL
772 query.inputs = [val];
773 query.output = val;
774 query.search = val;
c34b1796
AL
775 // searching by type
776 } else if (val.search("->") > -1) {
777 var trimmer = function (s) { return s.trim(); };
778 var parts = val.split("->").map(trimmer);
779 var input = parts[0];
780 // sort inputs so that order does not matter
abe05a73
XL
781 var inputs = input.split(",").map(trimmer).sort();
782 for (var i = 0; i < inputs.length; ++i) {
783 inputs[i] = extractGenerics(inputs[i]);
784 }
785 var output = extractGenerics(parts[1]);
c34b1796
AL
786
787 for (var i = 0; i < nSearchWords; ++i) {
788 var type = searchIndex[i].type;
abe05a73 789 var ty = searchIndex[i];
c34b1796
AL
790 if (!type) {
791 continue;
792 }
abe05a73 793 var fullId = generateId(ty);
c34b1796
AL
794
795 // allow searching for void (no output) functions as well
796 var typeOutput = type.output ? type.output.name : "";
abe05a73
XL
797 var returned = checkReturned(ty, output, true);
798 if (output.name === "*" || returned === true) {
799 var in_args = false;
800 var module = false;
801
802 if (input === "*") {
803 module = true;
804 } else {
805 var allFound = true;
806 for (var it = 0; allFound === true && it < inputs.length; it++) {
807 allFound = checkType(type, inputs[it], true);
1a4d82fc 808 }
abe05a73 809 in_args = allFound;
1a4d82fc 810 }
abe05a73
XL
811 if (in_args === true) {
812 results_in_args[fullId] = {
813 id: i,
814 index: -1,
815 dontValidate: true,
816 };
817 }
818 if (returned === true) {
819 results_returned[fullId] = {
820 id: i,
821 index: -1,
822 dontValidate: true,
823 };
824 }
825 if (module === true) {
826 results[fullId] = {
827 id: i,
828 index: -1,
829 dontValidate: true,
830 };
1a4d82fc
JJ
831 }
832 }
833 }
abe05a73
XL
834 query.inputs = inputs.map(function(input) {
835 return input.name;
836 });
837 query.output = output.name;
838 } else {
839 query.inputs = [val];
840 query.output = val;
841 query.search = val;
842 // gather matching search results up to a certain maximum
843 val = val.replace(/\_/g, "");
1a4d82fc 844
abe05a73 845 var valGenerics = extractGenerics(val);
1a4d82fc 846
abe05a73
XL
847 var paths = valLower.split("::");
848 var j;
849 for (j = 0; j < paths.length; ++j) {
850 if (paths[j] === "") {
851 paths.splice(j, 1);
852 j -= 1;
853 }
b039eaaf 854 }
abe05a73
XL
855 val = paths[paths.length - 1];
856 var startsWith = paths.slice(0, paths.length > 1 ? paths.length - 1 : 1);
1a4d82fc 857
abe05a73
XL
858 for (j = 0; j < nSearchWords; ++j) {
859 var lev_distance;
860 var ty = searchIndex[j];
861 if (!ty) {
862 continue;
863 }
864 var lev_add = 0;
865 if (paths.length > 1) {
866 var lev = checkPath(startsWith, paths[paths.length - 1], ty);
867 if (lev > MAX_LEV_DISTANCE) {
868 continue;
869 } else if (lev > 0) {
870 lev_add = 1;
871 }
872 }
1a4d82fc 873
abe05a73
XL
874 var returned = MAX_LEV_DISTANCE + 1;
875 var in_args = MAX_LEV_DISTANCE + 1;
876 var index = -1;
877 // we want lev results to go lower than others
878 var lev = MAX_LEV_DISTANCE + 1;
879 var fullId = generateId(ty);
880
881 if (searchWords[j].indexOf(split[i]) > -1 ||
882 searchWords[j].indexOf(val) > -1 ||
883 searchWords[j].replace(/_/g, "").indexOf(val) > -1)
884 {
885 // filter type: ... queries
886 if (typePassesFilter(typeFilter, ty.ty) && results[fullId] === undefined) {
887 index = searchWords[j].replace(/_/g, "").indexOf(val);
888 }
889 }
890 if ((lev = levenshtein(searchWords[j], val)) <= MAX_LEV_DISTANCE) {
891 if (typePassesFilter(typeFilter, ty.ty) === false) {
892 lev = MAX_LEV_DISTANCE + 1;
893 } else {
894 lev += 1;
895 }
896 }
897 if ((in_args = findArg(ty, valGenerics)) <= MAX_LEV_DISTANCE) {
898 if (typePassesFilter(typeFilter, ty.ty) === false) {
899 in_args = MAX_LEV_DISTANCE + 1;
900 }
901 }
902 if ((returned = checkReturned(ty, valGenerics)) <= MAX_LEV_DISTANCE) {
903 if (typePassesFilter(typeFilter, ty.ty) === false) {
904 returned = MAX_LEV_DISTANCE + 1;
905 }
906 }
1a4d82fc 907
abe05a73
XL
908 lev += lev_add;
909 if (in_args <= MAX_LEV_DISTANCE) {
910 if (results_in_args[fullId] === undefined) {
911 results_in_args[fullId] = {
912 id: j,
913 index: index,
914 lev: in_args,
915 };
916 }
917 results_in_args[fullId].lev =
918 Math.min(results_in_args[fullId].lev, in_args);
919 }
920 if (returned <= MAX_LEV_DISTANCE) {
921 if (results_returned[fullId] === undefined) {
922 results_returned[fullId] = {
923 id: j,
924 index: index,
925 lev: returned,
926 };
927 }
928 results_returned[fullId].lev =
929 Math.min(results_returned[fullId].lev, returned);
930 }
931 if (index !== -1 || lev <= MAX_LEV_DISTANCE) {
932 if (index !== -1) {
933 lev = 0;
934 }
935 if (results[fullId] === undefined) {
936 results[fullId] = {
937 id: j,
938 index: index,
939 lev: lev,
940 };
941 }
942 results[fullId].lev = Math.min(results[fullId].lev, lev);
943 }
1a4d82fc
JJ
944 }
945 }
c34b1796 946
abe05a73
XL
947 return {
948 'in_args': sortResults(results_in_args, true),
949 'returned': sortResults(results_returned, true),
950 'others': sortResults(results),
951 };
1a4d82fc
JJ
952 }
953
954 /**
955 * Validate performs the following boolean logic. For example:
956 * "File::open" will give IF A PARENT EXISTS => ("file" && "open")
957 * exists in (name || path || parent) OR => ("file" && "open") exists in
958 * (name || path )
959 *
960 * This could be written functionally, but I wanted to minimise
961 * functions on stack.
962 *
963 * @param {[string]} name [The name of the result]
964 * @param {[string]} path [The path of the result]
965 * @param {[string]} keys [The keys to be used (["file", "open"])]
966 * @param {[object]} parent [The parent of the result]
967 * @return {[boolean]} [Whether the result is valid or not]
968 */
969 function validateResult(name, path, keys, parent) {
62682a34 970 for (var i = 0; i < keys.length; ++i) {
1a4d82fc
JJ
971 // each check is for validation so we negate the conditions and invalidate
972 if (!(
973 // check for an exact name match
abe05a73 974 name.indexOf(keys[i]) > -1 ||
1a4d82fc 975 // then an exact path match
abe05a73 976 path.indexOf(keys[i]) > -1 ||
1a4d82fc
JJ
977 // next if there is a parent, check for exact parent match
978 (parent !== undefined &&
979 parent.name.toLowerCase().indexOf(keys[i]) > -1) ||
980 // lastly check to see if the name was a levenshtein match
abe05a73 981 levenshtein(name, keys[i]) <= MAX_LEV_DISTANCE)) {
1a4d82fc
JJ
982 return false;
983 }
984 }
985 return true;
986 }
987
988 function getQuery() {
7cac9316
XL
989 var matches, type, query, raw =
990 document.getElementsByClassName('search-input')[0].value;
1a4d82fc
JJ
991 query = raw;
992
e9174d1e 993 matches = query.match(/^(fn|mod|struct|enum|trait|type|const|macro)\s*:\s*/i);
1a4d82fc 994 if (matches) {
e9174d1e 995 type = matches[1].replace(/^const$/, 'constant');
1a4d82fc
JJ
996 query = query.substring(matches[0].length);
997 }
998
999 return {
1000 raw: raw,
1001 query: query,
1002 type: type,
62682a34 1003 id: query + type
1a4d82fc
JJ
1004 };
1005 }
1006
1007 function initSearchNav() {
7cac9316 1008 var hoverTimeout;
1a4d82fc 1009
7cac9316
XL
1010 var click_func = function(e) {
1011 var el = e.target;
1012 // to retrieve the real "owner" of the event.
1013 while (el.tagName !== 'TR') {
1014 el = el.parentNode;
1015 }
1016 var dst = e.target.getElementsByTagName('a');
1017 if (dst.length < 1) {
1018 return;
1019 }
1020 dst = dst[0];
62682a34 1021 if (window.location.pathname === dst.pathname) {
7cac9316
XL
1022 addClass(document.getElementById('search'), 'hidden');
1023 removeClass(document.getElementById('main'), 'hidden');
1a4d82fc
JJ
1024 document.location.href = dst.href;
1025 }
7cac9316
XL
1026 };
1027 var mouseover_func = function(e) {
1028 var el = e.target;
1029 // to retrieve the real "owner" of the event.
1030 while (el.tagName !== 'TR') {
1031 el = el.parentNode;
1032 }
1a4d82fc
JJ
1033 clearTimeout(hoverTimeout);
1034 hoverTimeout = setTimeout(function() {
7cac9316
XL
1035 onEach(document.getElementsByClassName('search-results'), function(e) {
1036 onEach(e.getElementsByClassName('result'), function(i_e) {
1037 removeClass(i_e, 'highlighted');
1038 });
1039 });
1040 addClass(el, 'highlighted');
1a4d82fc 1041 }, 20);
7cac9316
XL
1042 };
1043 onEach(document.getElementsByClassName('search-results'), function(e) {
1044 onEach(e.getElementsByClassName('result'), function(i_e) {
1045 i_e.onclick = click_func;
1046 i_e.onmouseover = mouseover_func;
1047 });
1a4d82fc
JJ
1048 });
1049
7cac9316 1050 var search_input = document.getElementsByClassName('search-input')[0];
7cac9316 1051 search_input.onkeydown = function(e) {
abe05a73
XL
1052 // "actives" references the currently highlighted item in each search tab.
1053 // Each array in "actives" represents a tab.
1054 var actives = [[], [], []];
1055 // "current" is used to know which tab we're looking into.
1056 var current = 0;
7cac9316 1057 onEach(document.getElementsByClassName('search-results'), function(e) {
abe05a73
XL
1058 onEach(e.getElementsByClassName('highlighted'), function(e) {
1059 actives[current].push(e);
7cac9316 1060 });
abe05a73 1061 current += 1;
7cac9316 1062 });
1a4d82fc
JJ
1063
1064 if (e.which === 38) { // up
abe05a73
XL
1065 if (!actives[currentTab].length ||
1066 !actives[currentTab][0].previousElementSibling) {
1a4d82fc
JJ
1067 return;
1068 }
1069
abe05a73
XL
1070 addClass(actives[currentTab][0].previousElementSibling, 'highlighted');
1071 removeClass(actives[currentTab][0], 'highlighted');
1a4d82fc 1072 } else if (e.which === 40) { // down
abe05a73 1073 if (!actives[currentTab].length) {
7cac9316
XL
1074 var results = document.getElementsByClassName('search-results');
1075 if (results.length > 0) {
abe05a73 1076 var res = results[currentTab].getElementsByClassName('result');
7cac9316
XL
1077 if (res.length > 0) {
1078 addClass(res[0], 'highlighted');
1079 }
1080 }
abe05a73
XL
1081 } else if (actives[currentTab][0].nextElementSibling) {
1082 addClass(actives[currentTab][0].nextElementSibling, 'highlighted');
1083 removeClass(actives[currentTab][0], 'highlighted');
1a4d82fc
JJ
1084 }
1085 } else if (e.which === 13) { // return
abe05a73
XL
1086 if (actives[currentTab].length) {
1087 document.location.href =
1088 actives[currentTab][0].getElementsByTagName('a')[0].href;
1089 }
1090 } else if (e.which === 9) { // tab
1091 if (e.shiftKey) {
1092 printTab(currentTab > 0 ? currentTab - 1 : 2);
1093 } else {
1094 printTab(currentTab > 1 ? 0 : currentTab + 1);
1a4d82fc 1095 }
abe05a73
XL
1096 e.preventDefault();
1097 } else if (e.which === 16) { // shift
1098 // Does nothing, it's just to avoid losing "focus" on the highlighted element.
1099 } else if (actives[currentTab].length > 0) {
1100 removeClass(actives[currentTab][0], 'highlighted');
1a4d82fc 1101 }
7cac9316 1102 };
1a4d82fc
JJ
1103 }
1104
1105 function escape(content) {
7cac9316
XL
1106 var h1 = document.createElement('h1');
1107 h1.textContent = content;
1108 return h1.innerHTML;
1a4d82fc
JJ
1109 }
1110
abe05a73
XL
1111 function addTab(array, query, display) {
1112 var extraStyle = '';
1113 if (display === false) {
1114 extraStyle = ' style="display: none;"';
1115 }
1a4d82fc 1116
abe05a73
XL
1117 var output = '';
1118 if (array.length > 0) {
1119 output = '<table class="search-results"' + extraStyle + '>';
1120 var shown = [];
1a4d82fc 1121
abe05a73 1122 array.forEach(function(item) {
1a4d82fc
JJ
1123 var name, type, href, displayPath;
1124
1125 if (shown.indexOf(item) !== -1) {
1126 return;
1127 }
1128
1129 shown.push(item);
1130 name = item.name;
1131 type = itemTypes[item.ty];
1132
1133 if (type === 'mod') {
1134 displayPath = item.path + '::';
1135 href = rootPath + item.path.replace(/::/g, '/') + '/' +
1136 name + '/index.html';
b039eaaf
SL
1137 } else if (type === "primitive") {
1138 displayPath = "";
1139 href = rootPath + item.path.replace(/::/g, '/') +
1140 '/' + type + '.' + name + '.html';
7453a54e
SL
1141 } else if (type === "externcrate") {
1142 displayPath = "";
1143 href = rootPath + name + '/index.html';
1a4d82fc
JJ
1144 } else if (item.parent !== undefined) {
1145 var myparent = item.parent;
1146 var anchor = '#' + type + '.' + name;
9e0c209e
SL
1147 var parentType = itemTypes[myparent.ty];
1148 if (parentType === "primitive") {
1149 displayPath = myparent.name + '::';
1150 } else {
1151 displayPath = item.path + '::' + myparent.name + '::';
1152 }
1a4d82fc 1153 href = rootPath + item.path.replace(/::/g, '/') +
9e0c209e 1154 '/' + parentType +
1a4d82fc
JJ
1155 '.' + myparent.name +
1156 '.html' + anchor;
1157 } else {
1158 displayPath = item.path + '::';
1159 href = rootPath + item.path.replace(/::/g, '/') +
1160 '/' + type + '.' + name + '.html';
1161 }
1162
1163 output += '<tr class="' + type + ' result"><td>' +
1164 '<a href="' + href + '">' +
1165 displayPath + '<span class="' + type + '">' +
1166 name + '</span></a></td><td>' +
1167 '<a href="' + href + '">' +
32a655c1 1168 '<span class="desc">' + escape(item.desc) +
1a4d82fc
JJ
1169 '&nbsp;</span></a></td></tr>';
1170 });
abe05a73 1171 output += '</table>';
1a4d82fc 1172 } else {
abe05a73
XL
1173 output = '<div class="search-failed"' + extraStyle + '>No results :(<br/>' +
1174 'Try on <a href="https://duckduckgo.com/?q=' +
1a4d82fc 1175 encodeURIComponent('rust ' + query.query) +
abe05a73 1176 '">DuckDuckGo</a>?</div>';
1a4d82fc 1177 }
abe05a73
XL
1178 return output;
1179 }
1180
1181 function makeTabHeader(tabNb, text, nbElems) {
1182 if (currentTab === tabNb) {
1183 return '<div class="selected">' + text +
1184 ' <div class="count">(' + nbElems + ')</div></div>';
1185 }
1186 return '<div>' + text + ' <div class="count">(' + nbElems + ')</div></div>';
1187 }
1188
1189 function showResults(results) {
1190 var output, query = getQuery();
1191
1192 currentResults = query.id;
1193 output = '<h1>Results for ' + escape(query.query) +
1194 (query.type ? ' (type: ' + escape(query.type) + ')' : '') + '</h1>' +
1195 '<div id="titles">' +
1196 makeTabHeader(0, "Types/modules", results['others'].length) +
1197 makeTabHeader(1, "As parameters", results['in_args'].length) +
1198 makeTabHeader(2, "As return value", results['returned'].length) +
1199 '</div><div id="results">';
1200
1201 output += addTab(results['others'], query);
1202 output += addTab(results['in_args'], query, false);
1203 output += addTab(results['returned'], query, false);
1204 output += '</div>';
1a4d82fc 1205
7cac9316
XL
1206 addClass(document.getElementById('main'), 'hidden');
1207 var search = document.getElementById('search');
1208 removeClass(search, 'hidden');
1209 search.innerHTML = output;
1210 var tds = search.getElementsByTagName('td');
1211 var td_width = 0;
1212 if (tds.length > 0) {
1213 td_width = tds[0].offsetWidth;
1214 }
1215 var width = search.offsetWidth - 40 - td_width;
1216 onEach(search.getElementsByClassName('desc'), function(e) {
1217 e.style.width = width + 'px';
1218 });
1a4d82fc 1219 initSearchNav();
abe05a73
XL
1220 var elems = document.getElementById('titles').childNodes;
1221 elems[0].onclick = function() { printTab(0); };
1222 elems[1].onclick = function() { printTab(1); };
1223 elems[2].onclick = function() { printTab(2); };
1224 printTab(currentTab);
1a4d82fc
JJ
1225 }
1226
1227 function search(e) {
1228 var query,
1a4d82fc 1229 obj, i, len,
abe05a73 1230 results = {"in_args": [], "returned": [], "others": []},
1a4d82fc
JJ
1231 resultIndex;
1232 var params = getQueryStringParams();
1233
1234 query = getQuery();
1235 if (e) {
1236 e.preventDefault();
1237 }
1238
1239 if (!query.query || query.id === currentResults) {
1240 return;
1241 }
1242
62682a34 1243 // Update document title to maintain a meaningful browser history
7cac9316 1244 document.title = "Results for " + query.query + " - Rust";
62682a34 1245
1a4d82fc
JJ
1246 // Because searching is incremental by character, only the most
1247 // recent search query is added to the browser history.
1248 if (browserSupportsHistoryApi()) {
1249 if (!history.state && !params.search) {
7cac9316 1250 history.pushState(query, "", "?search=" + encodeURIComponent(query.raw));
1a4d82fc 1251 } else {
7cac9316 1252 history.replaceState(query, "", "?search=" + encodeURIComponent(query.raw));
1a4d82fc
JJ
1253 }
1254 }
1255
abe05a73 1256 results = execQuery(query, 20000, index);
1a4d82fc
JJ
1257 showResults(results);
1258 }
1259
1a4d82fc
JJ
1260 function itemTypeFromName(typename) {
1261 for (var i = 0; i < itemTypes.length; ++i) {
abe05a73
XL
1262 if (itemTypes[i] === typename) {
1263 return i;
1264 }
1a4d82fc
JJ
1265 }
1266 return -1;
1267 }
1268
1269 function buildIndex(rawSearchIndex) {
1270 searchIndex = [];
1271 var searchWords = [];
1272 for (var crate in rawSearchIndex) {
62682a34 1273 if (!rawSearchIndex.hasOwnProperty(crate)) { continue; }
1a4d82fc 1274
7453a54e
SL
1275 searchWords.push(crate);
1276 searchIndex.push({
1277 crate: crate,
1278 ty: 1, // == ExternCrate
1279 name: crate,
1280 path: "",
1281 desc: rawSearchIndex[crate].doc,
1282 type: null,
1283 });
1284
1a4d82fc
JJ
1285 // an array of [(Number) item type,
1286 // (String) name,
1287 // (String) full path or empty string for previous path,
1288 // (String) description,
c34b1796
AL
1289 // (Number | null) the parent path index to `paths`]
1290 // (Object | null) the type of the function (if any)
1a4d82fc
JJ
1291 var items = rawSearchIndex[crate].items;
1292 // an array of [(Number) item type,
1293 // (String) name]
1294 var paths = rawSearchIndex[crate].paths;
1295
1296 // convert `paths` into an object form
1297 var len = paths.length;
1298 for (var i = 0; i < len; ++i) {
1299 paths[i] = {ty: paths[i][0], name: paths[i][1]};
1300 }
1301
1302 // convert `items` into an object form, and construct word indices.
1303 //
1304 // before any analysis is performed lets gather the search terms to
1305 // search against apart from the rest of the data. This is a quick
1306 // operation that is cached for the life of the page state so that
1307 // all other search operations have access to this cached data for
1308 // faster analysis operations
1309 var len = items.length;
1310 var lastPath = "";
1311 for (var i = 0; i < len; ++i) {
1312 var rawRow = items[i];
1313 var row = {crate: crate, ty: rawRow[0], name: rawRow[1],
1314 path: rawRow[2] || lastPath, desc: rawRow[3],
c34b1796 1315 parent: paths[rawRow[4]], type: rawRow[5]};
1a4d82fc
JJ
1316 searchIndex.push(row);
1317 if (typeof row.name === "string") {
1318 var word = row.name.toLowerCase();
1319 searchWords.push(word);
1320 } else {
1321 searchWords.push("");
1322 }
1323 lastPath = row.path;
1324 }
1325 }
1326 return searchWords;
1327 }
1328
1329 function startSearch() {
b039eaaf 1330 var searchTimeout;
7cac9316
XL
1331 var callback = function() {
1332 var search_input = document.getElementsByClassName('search-input');
1333 if (search_input.length < 1) { return; }
1334 search_input = search_input[0];
b039eaaf 1335 clearTimeout(searchTimeout);
7cac9316 1336 if (search_input.value.length === 0) {
54a0048b
SL
1337 if (browserSupportsHistoryApi()) {
1338 history.replaceState("", "std - Rust", "?search=");
1339 }
7cac9316
XL
1340 var main = document.getElementById('main');
1341 if (hasClass(main, 'content')) {
1342 removeClass(main, 'hidden');
1343 }
1344 var search_c = document.getElementById('search');
1345 if (hasClass(search_c, 'content')) {
1346 addClass(search_c, 'hidden');
1347 }
b039eaaf
SL
1348 } else {
1349 searchTimeout = setTimeout(search, 500);
1350 }
7cac9316
XL
1351 };
1352 var search_input = document.getElementsByClassName("search-input")[0];
1353 search_input.onkeyup = callback;
1354 search_input.oninput = callback;
abe05a73 1355 document.getElementsByClassName("search-form")[0].onsubmit = function(e) {
b039eaaf
SL
1356 e.preventDefault();
1357 clearTimeout(searchTimeout);
1358 search();
7cac9316
XL
1359 };
1360 search_input.onchange = function(e) {
b039eaaf
SL
1361 // Do NOT e.preventDefault() here. It will prevent pasting.
1362 clearTimeout(searchTimeout);
1363 // zero-timeout necessary here because at the time of event handler execution the
1364 // pasted content is not in the input field yet. Shouldn’t make any difference for
1365 // change, though.
1366 setTimeout(search, 0);
7cac9316
XL
1367 };
1368 search_input.onpaste = search_input.onchange;
1a4d82fc
JJ
1369
1370 // Push and pop states are used to add search results to the browser
1371 // history.
1372 if (browserSupportsHistoryApi()) {
c1a9b12d 1373 // Store the previous <title> so we can revert back to it later.
7cac9316 1374 var previousTitle = document.title;
c1a9b12d 1375
7cac9316 1376 window.onpopstate = function(e) {
1a4d82fc
JJ
1377 var params = getQueryStringParams();
1378 // When browsing back from search results the main page
1379 // visibility must be reset.
1380 if (!params.search) {
7cac9316
XL
1381 var main = document.getElementById('main');
1382 if (hasClass(main, 'content')) {
1383 removeClass(main, 'hidden');
1384 }
1385 var search_c = document.getElementById('search');
1386 if (hasClass(search_c, 'content')) {
1387 addClass(search_c, 'hidden');
1388 }
1a4d82fc 1389 }
c1a9b12d
SL
1390 // Revert to the previous title manually since the History
1391 // API ignores the title parameter.
7cac9316 1392 document.title = previousTitle;
1a4d82fc
JJ
1393 // When browsing forward to search results the previous
1394 // search will be repeated, so the currentResults are
1395 // cleared to ensure the search is successful.
1396 currentResults = null;
1397 // Synchronize search bar with query string state and
1398 // perform the search. This will empty the bar if there's
1399 // nothing there, which lets you really go back to a
1400 // previous state with nothing in the bar.
7cac9316
XL
1401 if (params.search) {
1402 document.getElementsByClassName('search-input')[0].value = params.search;
1403 } else {
1404 document.getElementsByClassName('search-input')[0].value = '';
1405 }
1a4d82fc
JJ
1406 // Some browsers fire 'onpopstate' for every page load
1407 // (Chrome), while others fire the event only when actually
1408 // popping a state (Firefox), which is why search() is
1409 // called both here and at the end of the startSearch()
1410 // function.
1411 search();
7cac9316 1412 };
1a4d82fc
JJ
1413 }
1414 search();
1415 }
1416
1417 index = buildIndex(rawSearchIndex);
1418 startSearch();
1419
1420 // Draw a convenient sidebar of known crates if we have a listing
62682a34 1421 if (rootPath === '../') {
7cac9316
XL
1422 var sidebar = document.getElementsByClassName('sidebar')[0];
1423 var div = document.createElement('div');
1424 div.className = 'block crate';
1425 div.innerHTML = '<h3>Crates</h3>';
1426 var ul = document.createElement('ul');
1427 div.appendChild(ul);
1a4d82fc
JJ
1428
1429 var crates = [];
1430 for (var crate in rawSearchIndex) {
abe05a73
XL
1431 if (!rawSearchIndex.hasOwnProperty(crate)) {
1432 continue;
1433 }
1a4d82fc
JJ
1434 crates.push(crate);
1435 }
1436 crates.sort();
1437 for (var i = 0; i < crates.length; ++i) {
1438 var klass = 'crate';
62682a34 1439 if (crates[i] === window.currentCrate) {
1a4d82fc
JJ
1440 klass += ' current';
1441 }
7cac9316
XL
1442 var link = document.createElement('a');
1443 link.href = '../' + crates[i] + '/index.html';
1444 link.title = rawSearchIndex[crates[i]].doc;
1445 link.className = klass;
1446 link.textContent = crates[i];
1447
1448 var li = document.createElement('li');
1449 li.appendChild(link);
1450 ul.appendChild(li);
1a4d82fc 1451 }
7cac9316 1452 sidebar.appendChild(div);
1a4d82fc
JJ
1453 }
1454 }
1455
1456 window.initSearch = initSearch;
1457
c34b1796
AL
1458 // delayed sidebar rendering.
1459 function initSidebarItems(items) {
7cac9316 1460 var sidebar = document.getElementsByClassName('sidebar')[0];
c34b1796
AL
1461 var current = window.sidebarCurrent;
1462
1463 function block(shortty, longty) {
1464 var filtered = items[shortty];
62682a34 1465 if (!filtered) { return; }
c34b1796 1466
7cac9316
XL
1467 var div = document.createElement('div');
1468 div.className = 'block ' + shortty;
1469 var h3 = document.createElement('h3');
1470 h3.textContent = longty;
1471 div.appendChild(h3);
1472 var ul = document.createElement('ul');
c34b1796
AL
1473
1474 for (var i = 0; i < filtered.length; ++i) {
1475 var item = filtered[i];
1476 var name = item[0];
1477 var desc = item[1]; // can be null
1478
1479 var klass = shortty;
62682a34 1480 if (name === current.name && shortty === current.ty) {
c34b1796
AL
1481 klass += ' current';
1482 }
1483 var path;
1484 if (shortty === 'mod') {
1485 path = name + '/index.html';
1486 } else {
1487 path = shortty + '.' + name + '.html';
1488 }
7cac9316
XL
1489 var link = document.createElement('a');
1490 link.href = current.relpath + path;
1491 link.title = desc;
1492 link.className = klass;
1493 link.textContent = name;
1494 var li = document.createElement('li');
1495 li.appendChild(link);
1496 ul.appendChild(li);
c34b1796 1497 }
7cac9316
XL
1498 div.appendChild(ul);
1499 sidebar.appendChild(div);
c34b1796
AL
1500 }
1501
3157f602 1502 block("primitive", "Primitive Types");
c34b1796 1503 block("mod", "Modules");
3157f602 1504 block("macro", "Macros");
c34b1796
AL
1505 block("struct", "Structs");
1506 block("enum", "Enums");
3b2f2976 1507 block("union", "Unions");
3157f602
XL
1508 block("constant", "Constants");
1509 block("static", "Statics");
c34b1796
AL
1510 block("trait", "Traits");
1511 block("fn", "Functions");
3157f602 1512 block("type", "Type Definitions");
abe05a73 1513 block("foreigntype", "Foreign Types");
c34b1796
AL
1514 }
1515
1516 window.initSidebarItems = initSidebarItems;
1517
1a4d82fc 1518 window.register_implementors = function(imp) {
7cac9316 1519 var list = document.getElementById('implementors-list');
1a4d82fc
JJ
1520 var libs = Object.getOwnPropertyNames(imp);
1521 for (var i = 0; i < libs.length; ++i) {
62682a34 1522 if (libs[i] === currentCrate) { continue; }
1a4d82fc
JJ
1523 var structs = imp[libs[i]];
1524 for (var j = 0; j < structs.length; ++j) {
7cac9316
XL
1525 var code = document.createElement('code');
1526 code.innerHTML = structs[j];
1527
1528 var x = code.getElementsByTagName('a');
1529 for (var k = 0; k < x.length; k++) {
1530 var href = x[k].getAttribute('href');
1a4d82fc 1531 if (href && href.indexOf('http') !== 0) {
7cac9316 1532 x[k].setAttribute('href', rootPath + href);
1a4d82fc 1533 }
7cac9316
XL
1534 }
1535 var li = document.createElement('li');
1536 li.appendChild(code);
1537 list.appendChild(li);
1a4d82fc
JJ
1538 }
1539 }
1540 };
1541 if (window.pending_implementors) {
1542 window.register_implementors(window.pending_implementors);
1543 }
1544
d9579d0f
AL
1545 function labelForToggleButton(sectionIsCollapsed) {
1546 if (sectionIsCollapsed) {
1547 // button will expand the section
1548 return "+";
d9579d0f 1549 }
62682a34
SL
1550 // button will collapse the section
1551 // note that this text is also set in the HTML template in render.rs
1552 return "\u2212"; // "\u2212" is '−' minus sign
d9579d0f 1553 }
1a4d82fc 1554
7cac9316
XL
1555 function onEveryMatchingChild(elem, className, func) {
1556 if (elem && className && func) {
1557 for (var i = 0; i < elem.childNodes.length; i++) {
1558 if (hasClass(elem.childNodes[i], className)) {
1559 func(elem.childNodes[i]);
1560 } else {
1561 onEveryMatchingChild(elem.childNodes[i], className, func);
1562 }
1563 }
1564 }
1565 }
1566
a7813a04 1567 function toggleAllDocs() {
7cac9316
XL
1568 var toggle = document.getElementById("toggle-all-docs");
1569 if (hasClass(toggle, "will-expand")) {
1570 removeClass(toggle, "will-expand");
1571 onEveryMatchingChild(toggle, "inner", function(e) {
1572 e.innerHTML = labelForToggleButton(false);
1573 });
1574 toggle.title = "collapse all docs";
1575 onEach(document.getElementsByClassName("docblock"), function(e) {
1576 e.style.display = 'block';
1577 });
1578 onEach(document.getElementsByClassName("toggle-label"), function(e) {
1579 e.style.display = 'none';
1580 });
1581 onEach(document.getElementsByClassName("toggle-wrapper"), function(e) {
1582 removeClass(e, "collapsed");
1583 });
1584 onEach(document.getElementsByClassName("collapse-toggle"), function(e) {
1585 onEveryMatchingChild(e, "inner", function(i_e) {
1586 i_e.innerHTML = labelForToggleButton(false);
1587 });
1588 });
d9579d0f 1589 } else {
7cac9316
XL
1590 addClass(toggle, "will-expand");
1591 onEveryMatchingChild(toggle, "inner", function(e) {
1592 e.innerHTML = labelForToggleButton(true);
1593 });
1594 toggle.title = "expand all docs";
1595 onEach(document.getElementsByClassName("docblock"), function(e) {
1596 e.style.display = 'none';
1597 });
1598 onEach(document.getElementsByClassName("toggle-label"), function(e) {
1599 e.style.display = 'inline-block';
1600 });
1601 onEach(document.getElementsByClassName("toggle-wrapper"), function(e) {
1602 addClass(e, "collapsed");
1603 });
1604 onEach(document.getElementsByClassName("collapse-toggle"), function(e) {
1605 onEveryMatchingChild(e, "inner", function(i_e) {
1606 i_e.innerHTML = labelForToggleButton(true);
1607 });
1608 });
d9579d0f 1609 }
a7813a04
XL
1610 }
1611
7cac9316
XL
1612 function collapseDocs(toggle) {
1613 if (!toggle || !toggle.parentNode) {
1614 return;
d9579d0f 1615 }
7cac9316
XL
1616 var relatedDoc = toggle.parentNode.nextElementSibling;
1617 if (hasClass(relatedDoc, "stability")) {
1618 relatedDoc = relatedDoc.nextElementSibling;
1619 }
1620 if (hasClass(relatedDoc, "docblock")) {
1621 if (!isHidden(relatedDoc)) {
1622 relatedDoc.style.display = 'none';
1623 onEach(toggle.childNodes, function(e) {
1624 if (hasClass(e, 'toggle-label')) {
1625 e.style.display = 'inline-block';
1626 }
1627 if (hasClass(e, 'inner')) {
1628 e.innerHTML = labelForToggleButton(true);
1629 }
1630 });
1631 addClass(toggle.parentNode, 'collapsed');
1a4d82fc 1632 } else {
7cac9316
XL
1633 relatedDoc.style.display = 'block';
1634 removeClass(toggle.parentNode, 'collapsed');
1635 onEach(toggle.childNodes, function(e) {
1636 if (hasClass(e, 'toggle-label')) {
1637 e.style.display = 'none';
1638 }
1639 if (hasClass(e, 'inner')) {
1640 e.innerHTML = labelForToggleButton(false);
1641 }
1642 });
1a4d82fc
JJ
1643 }
1644 }
476ff2be
SL
1645 }
1646
7cac9316
XL
1647 var x = document.getElementById('toggle-all-docs');
1648 if (x) {
1649 x.onclick = toggleAllDocs;
1650 }
476ff2be 1651
7cac9316
XL
1652 function insertAfter(newNode, referenceNode) {
1653 referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling);
1654 }
1a4d82fc 1655
7cac9316
XL
1656 var toggle = document.createElement('a');
1657 toggle.href = 'javascript:void(0)';
1658 toggle.className = 'collapse-toggle';
1659 toggle.innerHTML = "[<span class='inner'>"+labelForToggleButton(false)+"</span>]";
1a4d82fc 1660
7cac9316
XL
1661 var func = function(e) {
1662 var next = e.nextElementSibling;
1663 if (!next) {
1664 return;
1665 }
1666 if (hasClass(next, 'docblock') ||
1667 (hasClass(next, 'stability') &&
1668 hasClass(next.nextElementSibling, 'docblock'))) {
1669 insertAfter(toggle.cloneNode(true), e.childNodes[e.childNodes.length - 1]);
1670 }
1671 }
1672 onEach(document.getElementsByClassName('method'), func);
1673 onEach(document.getElementsByClassName('impl-items'), function(e) {
1674 onEach(e.getElementsByClassName('associatedconstant'), func);
1675 });
1a4d82fc 1676
041b39d2
XL
1677 function createToggle() {
1678 var span = document.createElement('span');
1679 span.className = 'toggle-label';
1680 span.style.display = 'none';
1681 span.innerHTML = '&nbsp;Expand&nbsp;description';
476ff2be 1682
041b39d2
XL
1683 var mainToggle = toggle.cloneNode(true);
1684 mainToggle.appendChild(span);
1a4d82fc 1685
041b39d2
XL
1686 var wrapper = document.createElement('div');
1687 wrapper.className = 'toggle-wrapper';
1688 wrapper.appendChild(mainToggle);
1689 return wrapper;
1690 }
1a4d82fc 1691
7cac9316
XL
1692 onEach(document.getElementById('main').getElementsByClassName('docblock'), function(e) {
1693 if (e.parentNode.id === "main") {
041b39d2 1694 e.parentNode.insertBefore(createToggle(), e);
1a4d82fc 1695 }
7cac9316 1696 });
1a4d82fc 1697
7cac9316
XL
1698 onEach(document.getElementsByClassName('docblock'), function(e) {
1699 if (hasClass(e, 'autohide')) {
1700 var wrap = e.previousElementSibling;
1701 if (wrap && hasClass(wrap, 'toggle-wrapper')) {
1702 var toggle = wrap.childNodes[0];
1703 if (e.childNodes[0].tagName === 'H3') {
1704 onEach(toggle.getElementsByClassName('toggle-label'), function(i_e) {
1705 i_e.innerHTML = " Show " + e.childNodes[0].innerHTML;
1706 });
1a4d82fc 1707 }
7cac9316
XL
1708 e.style.display = 'none';
1709 addClass(wrap, 'collapsed');
1710 onEach(toggle.getElementsByClassName('inner'), function(e) {
1711 e.innerHTML = labelForToggleButton(true);
1712 });
1713 onEach(toggle.getElementsByClassName('toggle-label'), function(e) {
3b2f2976 1714 e.style.display = 'inline-block';
7cac9316 1715 });
1a4d82fc 1716 }
7cac9316
XL
1717 }
1718 })
1719
041b39d2
XL
1720 function createToggleWrapper() {
1721 var span = document.createElement('span');
1722 span.className = 'toggle-label';
1723 span.style.display = 'none';
1724 span.innerHTML = '&nbsp;Expand&nbsp;attributes';
1725 toggle.appendChild(span);
1726
1727 var wrapper = document.createElement('div');
1728 wrapper.className = 'toggle-wrapper toggle-attributes';
1729 wrapper.appendChild(toggle);
1730 return wrapper;
1731 }
7cac9316 1732
abe05a73
XL
1733 // In the search display, allows to switch between tabs.
1734 function printTab(nb) {
1735 if (nb === 0 || nb === 1 || nb === 2) {
1736 currentTab = nb;
1737 }
1738 var nb_copy = nb;
1739 onEach(document.getElementById('titles').childNodes, function(elem) {
1740 if (nb_copy === 0) {
1741 addClass(elem, 'selected');
1742 } else {
1743 removeClass(elem, 'selected');
1744 }
1745 nb_copy -= 1;
1746 });
1747 onEach(document.getElementById('results').childNodes, function(elem) {
1748 if (nb === 0) {
1749 elem.style.display = '';
1750 } else {
1751 elem.style.display = 'none';
1752 }
1753 nb -= 1;
1754 });
1755 }
1756
7cac9316
XL
1757 onEach(document.getElementById('main').getElementsByTagName('pre'), function(e) {
1758 onEach(e.getElementsByClassName('attributes'), function(i_e) {
041b39d2 1759 i_e.parentNode.insertBefore(createToggleWrapper(), i_e);
7cac9316
XL
1760 collapseDocs(i_e.previousSibling.childNodes[0]);
1761 });
1762 });
ea8adc8c
XL
1763
1764 onEach(document.getElementsByClassName('rust-example-rendered'), function(e) {
1765 if (hasClass(e, 'compile_fail')) {
1766 e.addEventListener("mouseover", function(event) {
1767 e.previousElementSibling.childNodes[0].style.color = '#f00';
1768 });
1769 e.addEventListener("mouseout", function(event) {
1770 e.previousElementSibling.childNodes[0].style.color = '';
1771 });
1772 } else if (hasClass(e, 'ignore')) {
1773 e.addEventListener("mouseover", function(event) {
1774 e.previousElementSibling.childNodes[0].style.color = '#ff9200';
1775 });
1776 e.addEventListener("mouseout", function(event) {
1777 e.previousElementSibling.childNodes[0].style.color = '';
1778 });
1779 }
1780 });
abe05a73
XL
1781
1782 var search_input = document.getElementsByClassName("search-input")[0];
1783
1784 if (search_input) {
1785 search_input.onfocus = function() {
1786 if (search_input.value !== "") {
1787 addClass(document.getElementById("main"), "hidden");
1788 removeClass(document.getElementById("search"), "hidden");
1789 if (browserSupportsHistoryApi()) {
1790 history.replaceState(search_input.value,
1791 "",
1792 "?search=" + encodeURIComponent(search_input.value));
1793 }
1794 }
1795 };
1796 }
1a4d82fc 1797}());
c1a9b12d
SL
1798
1799// Sets the focus on the search bar at the top of the page
1800function focusSearchBar() {
7cac9316 1801 document.getElementsByClassName('search-input')[0].focus();
c1a9b12d 1802}