]>
git.proxmox.com Git - rustc.git/blob - src/librustdoc/html/static/main.js
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.
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.
13 /*jslint browser: true, es5: true */
14 /*globals $: true, rootPath: true */
19 // This mapping table should match the discriminants of
20 // `rustdoc::html::item_type::ItemType` type in Rust.
21 var itemTypes
= ["mod",
42 function hasClass(elem
, className
) {
43 if (elem
&& className
&& elem
.className
) {
44 var elemClass
= elem
.className
;
45 var start
= elemClass
.indexOf(className
);
48 } else if (elemClass
.length
== className
.length
) {
51 if (start
> 0 && elemClass
[start
- 1] != ' ') {
54 var end
= start
+ className
.length
;
55 if (end
< elemClass
.length
&& elemClass
[end
] != ' ') {
64 function addClass(elem
, className
) {
65 if (elem
&& className
&& !hasClass(elem
, className
)) {
66 if (elem
.className
&& elem
.className
.length
> 0) {
67 elem
.className
+= ' ' + className
;
69 elem
.className
= className
;
74 function removeClass(elem
, className
) {
75 if (elem
&& className
&& elem
.className
) {
76 elem
.className
= (" " + elem
.className
+ " ").replace(" " + className
+ " ", " ")
81 function onEach(arr
, func
) {
82 if (arr
&& arr
.length
> 0 && func
) {
83 for (var i
= 0; i
< arr
.length
; i
++) {
89 function isHidden(elem
) {
90 return (elem
.offsetParent
=== null)
93 // used for special search precedence
94 var TY_PRIMITIVE
= itemTypes
.indexOf("primitive");
96 onEach(document
.getElementsByClassName('js-only'), function(e
) {
97 removeClass(e
, 'js-only');
100 function getQueryStringParams() {
102 window
.location
.search
.substring(1).split("&").
104 var pair
= s
.split("=");
105 params
[decodeURIComponent(pair
[0])] =
106 typeof pair
[1] === "undefined" ?
107 null : decodeURIComponent(pair
[1]);
112 function browserSupportsHistoryApi() {
113 return document
.location
.protocol
!= "file:" &&
114 window
.history
&& typeof window
.history
.pushState
=== "function";
117 function highlightSourceLines(ev
) {
118 var i
, from, to
, match
= window
.location
.hash
.match(/^#?(\d+)(?:-(\d+))?$/);
120 from = parseInt(match
[1], 10);
121 to
= Math
.min(50000, parseInt(match
[2] || match
[1], 10));
122 from = Math
.min(from, to
);
123 var elem
= document
.getElementById(from);
128 var x
= document
.getElementById(from);
133 onEach(document
.getElementsByClassName('line-numbers'), function(e
) {
134 onEach(e
.getElementsByTagName('span'), function(i_e
) {
135 removeClass(i_e
, 'line-highlighted');
138 for (i
= from; i
<= to
; ++i
) {
139 addClass(document
.getElementById(i
), 'line-highlighted');
143 highlightSourceLines(null);
144 window
.onhashchange
= highlightSourceLines
;
146 // Gets the human-readable string for the virtual-key code of the
147 // given KeyboardEvent, ev.
149 // This function is meant as a polyfill for KeyboardEvent#key,
150 // since it is not supported in Trident. We also test for
151 // KeyboardEvent#keyCode because the handleShortcut handler is
152 // also registered for the keydown event, because Blink doesn't fire
153 // keypress on hitting the Escape key.
155 // So I guess you could say things are getting pretty interoperable.
156 function getVirtualKey(ev
) {
157 if ("key" in ev
&& typeof ev
.key
!= "undefined")
160 var c
= ev
.charCode
|| ev
.keyCode
;
163 return String
.fromCharCode(c
);
166 function handleShortcut(ev
) {
167 if (document
.activeElement
.tagName
=== "INPUT")
170 // Don't interfere with browser shortcuts
171 if (ev
.ctrlKey
|| ev
.altKey
|| ev
.metaKey
)
174 var help
= document
.getElementById("help");
175 switch (getVirtualKey(ev
)) {
177 var search
= document
.getElementById("search");
178 if (!hasClass(help
, "hidden")) {
180 addClass(help
, "hidden");
181 removeClass(document
.body
, "blur");
182 } else if (!hasClass(search
, "hidden")) {
184 addClass(search
, "hidden");
185 removeClass(document
.getElementById("main"), "hidden");
201 if (ev
.shiftKey
&& hasClass(help
, "hidden")) {
203 removeClass(help
, "hidden");
204 addClass(document
.body
, "blur");
210 document
.onkeypress
= handleShortcut
;
211 document
.onkeydown
= handleShortcut
;
212 document
.onclick = function(ev
) {
213 if (hasClass(ev
.target
, 'collapse-toggle')) {
214 collapseDocs(ev
.target
);
215 } else if (hasClass(ev
.target
.parentNode
, 'collapse-toggle')) {
216 collapseDocs(ev
.target
.parentNode
);
217 } else if (ev
.target
.tagName
=== 'SPAN' && hasClass(ev
.target
.parentNode
, 'line-numbers')) {
220 var set_fragment = function (name
) {
221 if (browserSupportsHistoryApi()) {
222 history
.replaceState(null, null, '#' + name
);
225 location
.replace('#' + name
);
229 var cur_id
= parseInt(ev
.target
.id
, 10);
231 if (ev
.shiftKey
&& prev_id
) {
232 if (prev_id
> cur_id
) {
238 set_fragment(prev_id
+ '-' + cur_id
);
242 set_fragment(cur_id
);
244 } else if (!hasClass(document
.getElementById("help"), "hidden")) {
245 addClass(document
.getElementById("help"), "hidden");
246 removeClass(document
.body
, "blur");
250 var x
= document
.getElementsByClassName('version-selector');
252 x
[0].onchange = function() {
254 url
= document
.location
.href
,
256 len
= rootPath
.match(/\.\.\//g).length
+ 1;
258 for (i
= 0; i
< len
; ++i
) {
259 match
= url
.match(/\/[^\/]*$/);
261 stripped
= match
[0] + stripped
;
263 url
= url
.substring(0, url
.length
- match
[0].length
);
266 url
+= '/' + document
.getElementsByClassName('version-selector')[0].value
+ stripped
;
268 document
.location
.href
= url
;
273 * A function to compute the Levenshtein distance between two strings
274 * Licensed under the Creative Commons Attribution-ShareAlike 3.0 Unported
275 * Full License can be found at http://creativecommons.org/licenses/by-sa/3.0/legalcode
276 * This code is an unmodified version of the code written by Marco de Wit
277 * and was found at http://stackoverflow.com/a/18514751/745719
279 var levenshtein
= (function() {
281 return function(s1
, s2
) {
285 var s1_len
= s1
.length
, s2_len
= s2
.length
;
286 if (s1_len
&& s2_len
) {
287 var i1
= 0, i2
= 0, a
, b
, c
, c2
, row
= row2
;
288 while (i1
< s1_len
) {
291 while (i2
< s2_len
) {
292 c2
= s2
.charCodeAt(i2
);
296 for (i1
= 0; i1
< s1_len
; ++i1
) {
297 c
= a
+ (s1
.charCodeAt(i1
) !== c2
? 1 : 0);
299 b
= b
< a
? (b
< c
? b
+ 1 : c
) : (a
< c
? a
+ 1 : c
);
305 return s1_len
+ s2_len
;
309 function initSearch(rawSearchIndex
) {
310 var currentResults
, index
, searchIndex
;
311 var MAX_LEV_DISTANCE
= 3;
312 var params
= getQueryStringParams();
314 // Populate search bar with query string search term when provided,
315 // but only if the input bar is empty. This avoid the obnoxious issue
316 // where you start trying to do a search, and the index loads, and
317 // suddenly your search is gone!
318 if (document
.getElementsByClassName("search-input")[0].value
=== "") {
319 document
.getElementsByClassName("search-input")[0].value
= params
.search
|| '';
323 * Executes the query and builds an index of results
324 * @param {[Object]} query [The user query]
325 * @param {[type]} max [The maximum results returned]
326 * @param {[type]} searchWords [The list of search words to query
328 * @return {[type]} [A search index of results]
330 function execQuery(query
, max
, searchWords
) {
331 var valLower
= query
.query
.toLowerCase(),
333 typeFilter
= itemTypeFromName(query
.type
),
335 split
= valLower
.split("::");
337 // remove empty keywords
338 for (var j
= 0; j
< split
.length
; ++j
) {
339 split
[j
].toLowerCase();
340 if (split
[j
] === "") {
345 function typePassesFilter(filter
, type
) {
347 if (filter
< 0) return true;
350 if (filter
=== type
) return true;
352 // Match related items
353 var name
= itemTypes
[type
];
354 switch (itemTypes
[filter
]) {
356 return (name
== "associatedconstant");
358 return (name
== "method" || name
== "tymethod");
360 return (name
== "primitive");
367 // quoted values mean literal search
368 var nSearchWords
= searchWords
.length
;
369 if ((val
.charAt(0) === "\"" || val
.charAt(0) === "'") &&
370 val
.charAt(val
.length
- 1) === val
.charAt(0))
372 val
= val
.substr(1, val
.length
- 2);
373 for (var i
= 0; i
< nSearchWords
; ++i
) {
374 if (searchWords
[i
] === val
) {
375 // filter type: ... queries
376 if (typePassesFilter(typeFilter
, searchIndex
[i
].ty
)) {
377 results
.push({id
: i
, index
: -1});
380 if (results
.length
=== max
) {
385 } else if (val
.search("->") > -1) {
386 var trimmer = function (s
) { return s
.trim(); };
387 var parts
= val
.split("->").map(trimmer
);
388 var input
= parts
[0];
389 // sort inputs so that order does not matter
390 var inputs
= input
.split(",").map(trimmer
).sort().toString();
391 var output
= parts
[1];
393 for (var i
= 0; i
< nSearchWords
; ++i
) {
394 var type
= searchIndex
[i
].type
;
399 // sort index inputs so that order does not matter
400 var typeInputs
= type
.inputs
.map(function (input
) {
404 // allow searching for void (no output) functions as well
405 var typeOutput
= type
.output
? type
.output
.name
: "";
406 if ((inputs
=== "*" || inputs
=== typeInputs
.toString()) &&
407 (output
=== "*" || output
== typeOutput
)) {
408 results
.push({id
: i
, index
: -1, dontValidate
: true});
412 // gather matching search results up to a certain maximum
413 val
= val
.replace(/\_/g, "");
414 for (var i
= 0; i
< split
.length
; ++i
) {
415 for (var j
= 0; j
< nSearchWords
; ++j
) {
417 if (searchWords
[j
].indexOf(split
[i
]) > -1 ||
418 searchWords
[j
].indexOf(val
) > -1 ||
419 searchWords
[j
].replace(/_
/g
, "").indexOf(val
) > -1)
421 // filter type: ... queries
422 if (typePassesFilter(typeFilter
, searchIndex
[j
].ty
)) {
425 index
: searchWords
[j
].replace(/_
/g
, "").indexOf(val
),
430 (lev_distance
= levenshtein(searchWords
[j
], val
)) <=
432 if (typePassesFilter(typeFilter
, searchIndex
[j
].ty
)) {
436 // we want lev results to go lower than others
441 if (results
.length
=== max
) {
448 var nresults
= results
.length
;
449 for (var i
= 0; i
< nresults
; ++i
) {
450 results
[i
].word
= searchWords
[results
[i
].id
];
451 results
[i
].item
= searchIndex
[results
[i
].id
] || {};
453 // if there are no results then return to default and fail
454 if (results
.length
=== 0) {
458 results
.sort(function sortResults(aaa
, bbb
) {
461 // Sort by non levenshtein results and then levenshtein results by the distance
462 // (less changes required to match means higher rankings)
465 if (a
!== b
) { return a
- b
; }
467 // sort by crate (non-current crate goes later)
468 a
= (aaa
.item
.crate
!== window
.currentCrate
);
469 b
= (bbb
.item
.crate
!== window
.currentCrate
);
470 if (a
!== b
) { return a
- b
; }
472 // sort by exact match (mismatch goes later)
473 a
= (aaa
.word
!== valLower
);
474 b
= (bbb
.word
!== valLower
);
475 if (a
!== b
) { return a
- b
; }
477 // sort by item name length (longer goes later)
480 if (a
!== b
) { return a
- b
; }
482 // sort by item name (lexicographically larger goes later)
485 if (a
!== b
) { return (a
> b
? +1 : -1); }
487 // sort by index of keyword in item name (no literal occurrence goes later)
490 if (a
!== b
) { return a
- b
; }
491 // (later literal occurrence, if any, goes later)
494 if (a
!== b
) { return a
- b
; }
496 // special precedence for primitive pages
497 if ((aaa
.item
.ty
=== TY_PRIMITIVE
) && (bbb
.item
.ty
!== TY_PRIMITIVE
)) {
500 if ((bbb
.item
.ty
=== TY_PRIMITIVE
) && (aaa
.item
.ty
!== TY_PRIMITIVE
)) {
504 // sort by description (no description goes later)
505 a
= (aaa
.item
.desc
=== '');
506 b
= (bbb
.item
.desc
=== '');
507 if (a
!== b
) { return a
- b
; }
509 // sort by type (later occurrence in `itemTypes` goes later)
512 if (a
!== b
) { return a
- b
; }
514 // sort by path (lexicographically larger goes later)
517 if (a
!== b
) { return (a
> b
? +1 : -1); }
523 // remove duplicates, according to the data provided
524 for (var i
= results
.length
- 1; i
> 0; i
-= 1) {
525 if (results
[i
].word
=== results
[i
- 1].word
&&
526 results
[i
].item
.ty
=== results
[i
- 1].item
.ty
&&
527 results
[i
].item
.path
=== results
[i
- 1].item
.path
&&
528 (results
[i
].item
.parent
|| {}).name
=== (results
[i
- 1].item
.parent
|| {}).name
)
533 for (var i
= 0; i
< results
.length
; ++i
) {
534 var result
= results
[i
],
535 name
= result
.item
.name
.toLowerCase(),
536 path
= result
.item
.path
.toLowerCase(),
537 parent
= result
.item
.parent
;
539 // this validation does not make sense when searching by types
540 if (result
.dontValidate
) {
544 var valid
= validateResult(name
, path
, split
, parent
);
553 * Validate performs the following boolean logic. For example:
554 * "File::open" will give IF A PARENT EXISTS => ("file" && "open")
555 * exists in (name || path || parent) OR => ("file" && "open") exists in
558 * This could be written functionally, but I wanted to minimise
559 * functions on stack.
561 * @param {[string]} name [The name of the result]
562 * @param {[string]} path [The path of the result]
563 * @param {[string]} keys [The keys to be used (["file", "open"])]
564 * @param {[object]} parent [The parent of the result]
565 * @return {[boolean]} [Whether the result is valid or not]
567 function validateResult(name
, path
, keys
, parent
) {
568 for (var i
= 0; i
< keys
.length
; ++i
) {
569 // each check is for validation so we negate the conditions and invalidate
571 // check for an exact name match
572 name
.toLowerCase().indexOf(keys
[i
]) > -1 ||
573 // then an exact path match
574 path
.toLowerCase().indexOf(keys
[i
]) > -1 ||
575 // next if there is a parent, check for exact parent match
576 (parent
!== undefined &&
577 parent
.name
.toLowerCase().indexOf(keys
[i
]) > -1) ||
578 // lastly check to see if the name was a levenshtein match
579 levenshtein(name
.toLowerCase(), keys
[i
]) <=
587 function getQuery() {
588 var matches
, type
, query
, raw
=
589 document
.getElementsByClassName('search-input')[0].value
;
592 matches
= query
.match(/^(fn|mod|struct|enum|trait|type|const|macro)\s*:\s*/i);
594 type
= matches
[1].replace(/^const$/, 'constant');
595 query
= query
.substring(matches
[0].length
);
606 function initSearchNav() {
609 var click_func = function(e
) {
611 // to retrieve the real "owner" of the event.
612 while (el
.tagName
!== 'TR') {
615 var dst
= e
.target
.getElementsByTagName('a');
616 if (dst
.length
< 1) {
620 if (window
.location
.pathname
=== dst
.pathname
) {
621 addClass(document
.getElementById('search'), 'hidden');
622 removeClass(document
.getElementById('main'), 'hidden');
623 document
.location
.href
= dst
.href
;
626 var mouseover_func = function(e
) {
628 // to retrieve the real "owner" of the event.
629 while (el
.tagName
!== 'TR') {
632 clearTimeout(hoverTimeout
);
633 hoverTimeout
= setTimeout(function() {
634 onEach(document
.getElementsByClassName('search-results'), function(e
) {
635 onEach(e
.getElementsByClassName('result'), function(i_e
) {
636 removeClass(i_e
, 'highlighted');
639 addClass(el
, 'highlighted');
642 onEach(document
.getElementsByClassName('search-results'), function(e
) {
643 onEach(e
.getElementsByClassName('result'), function(i_e
) {
644 i_e
.onclick
= click_func
;
645 i_e
.onmouseover
= mouseover_func
;
649 var search_input
= document
.getElementsByClassName('search-input')[0];
650 search_input
.onkeydown
= null;
651 search_input
.onkeydown = function(e
) {
653 onEach(document
.getElementsByClassName('search-results'), function(e
) {
654 onEach(document
.getElementsByClassName('highlighted'), function(e
) {
659 if (e
.which
=== 38) { // up
660 if (!actives
.length
|| !actives
[0].previousElementSibling
) {
664 addClass(actives
[0].previousElementSibling
, 'highlighted');
665 removeClass(actives
[0], 'highlighted');
666 } else if (e
.which
=== 40) { // down
667 if (!actives
.length
) {
668 var results
= document
.getElementsByClassName('search-results');
669 if (results
.length
> 0) {
670 var res
= results
[0].getElementsByClassName('result');
671 if (res
.length
> 0) {
672 addClass(res
[0], 'highlighted');
675 } else if (actives
[0].nextElementSibling
) {
676 addClass(actives
[0].nextElementSibling
, 'highlighted');
677 removeClass(actives
[0], 'highlighted');
679 } else if (e
.which
=== 13) { // return
680 if (actives
.length
) {
681 document
.location
.href
= actives
[0].getElementsByTagName('a')[0].href
;
683 } else if (actives
.length
> 0) {
684 removeClass(actives
[0], 'highlighted');
689 function escape(content
) {
690 var h1
= document
.createElement('h1');
691 h1
.textContent
= content
;
695 function showResults(results
) {
696 var output
, shown
, query
= getQuery();
698 currentResults
= query
.id
;
699 output
= '<h1>Results for ' + escape(query
.query
) +
700 (query
.type
? ' (type: ' + escape(query
.type
) + ')' : '') + '</h1>';
701 output
+= '<table class="search-results">';
703 if (results
.length
> 0) {
706 results
.forEach(function(item
) {
707 var name
, type
, href
, displayPath
;
709 if (shown
.indexOf(item
) !== -1) {
715 type
= itemTypes
[item
.ty
];
717 if (type
=== 'mod') {
718 displayPath
= item
.path
+ '::';
719 href
= rootPath
+ item
.path
.replace(/::/g, '/') + '/' +
720 name
+ '/index.html';
721 } else if (type
=== "primitive") {
723 href
= rootPath
+ item
.path
.replace(/::/g, '/') +
724 '/' + type
+ '.' + name
+ '.html';
725 } else if (type
=== "externcrate") {
727 href
= rootPath
+ name
+ '/index.html';
728 } else if (item
.parent
!== undefined) {
729 var myparent
= item
.parent
;
730 var anchor
= '#' + type
+ '.' + name
;
731 var parentType
= itemTypes
[myparent
.ty
];
732 if (parentType
=== "primitive") {
733 displayPath
= myparent
.name
+ '::';
735 displayPath
= item
.path
+ '::' + myparent
.name
+ '::';
737 href
= rootPath
+ item
.path
.replace(/::/g, '/') +
739 '.' + myparent
.name
+
742 displayPath
= item
.path
+ '::';
743 href
= rootPath
+ item
.path
.replace(/::/g, '/') +
744 '/' + type
+ '.' + name
+ '.html';
747 output
+= '<tr class="' + type
+ ' result"><td>' +
748 '<a href="' + href
+ '">' +
749 displayPath
+ '<span class="' + type
+ '">' +
750 name
+ '</span></a></td><td>' +
751 '<a href="' + href
+ '">' +
752 '<span class="desc">' + escape(item
.desc
) +
753 ' </span></a></td></tr>';
756 output
+= 'No results :( <a href="https://duckduckgo.com/?q=' +
757 encodeURIComponent('rust ' + query
.query
) +
758 '">Try on DuckDuckGo?</a>';
762 addClass(document
.getElementById('main'), 'hidden');
763 var search
= document
.getElementById('search');
764 removeClass(search
, 'hidden');
765 search
.innerHTML
= output
;
766 var tds
= search
.getElementsByTagName('td');
768 if (tds
.length
> 0) {
769 td_width
= tds
[0].offsetWidth
;
771 var width
= search
.offsetWidth
- 40 - td_width
;
772 onEach(search
.getElementsByClassName('desc'), function(e
) {
773 e
.style
.width
= width
+ 'px';
785 var params
= getQueryStringParams();
792 if (!query
.query
|| query
.id
=== currentResults
) {
796 // Update document title to maintain a meaningful browser history
797 document
.title
= "Results for " + query
.query
+ " - Rust";
799 // Because searching is incremental by character, only the most
800 // recent search query is added to the browser history.
801 if (browserSupportsHistoryApi()) {
802 if (!history
.state
&& !params
.search
) {
803 history
.pushState(query
, "", "?search=" + encodeURIComponent(query
.raw
));
805 history
.replaceState(query
, "", "?search=" + encodeURIComponent(query
.raw
));
809 resultIndex
= execQuery(query
, 20000, index
);
810 len
= resultIndex
.length
;
811 for (i
= 0; i
< len
; ++i
) {
812 if (resultIndex
[i
].id
> -1) {
813 obj
= searchIndex
[resultIndex
[i
].id
];
814 filterdata
.push([obj
.name
, obj
.ty
, obj
.path
, obj
.desc
]);
817 if (results
.length
>= maxResults
) {
822 showResults(results
);
825 function itemTypeFromName(typename
) {
826 for (var i
= 0; i
< itemTypes
.length
; ++i
) {
827 if (itemTypes
[i
] === typename
) { return i
; }
832 function buildIndex(rawSearchIndex
) {
834 var searchWords
= [];
835 for (var crate
in rawSearchIndex
) {
836 if (!rawSearchIndex
.hasOwnProperty(crate
)) { continue; }
838 searchWords
.push(crate
);
841 ty
: 1, // == ExternCrate
844 desc
: rawSearchIndex
[crate
].doc
,
848 // an array of [(Number) item type,
850 // (String) full path or empty string for previous path,
851 // (String) description,
852 // (Number | null) the parent path index to `paths`]
853 // (Object | null) the type of the function (if any)
854 var items
= rawSearchIndex
[crate
].items
;
855 // an array of [(Number) item type,
857 var paths
= rawSearchIndex
[crate
].paths
;
859 // convert `paths` into an object form
860 var len
= paths
.length
;
861 for (var i
= 0; i
< len
; ++i
) {
862 paths
[i
] = {ty
: paths
[i
][0], name
: paths
[i
][1]};
865 // convert `items` into an object form, and construct word indices.
867 // before any analysis is performed lets gather the search terms to
868 // search against apart from the rest of the data. This is a quick
869 // operation that is cached for the life of the page state so that
870 // all other search operations have access to this cached data for
871 // faster analysis operations
872 var len
= items
.length
;
874 for (var i
= 0; i
< len
; ++i
) {
875 var rawRow
= items
[i
];
876 var row
= {crate
: crate
, ty
: rawRow
[0], name
: rawRow
[1],
877 path
: rawRow
[2] || lastPath
, desc
: rawRow
[3],
878 parent
: paths
[rawRow
[4]], type
: rawRow
[5]};
879 searchIndex
.push(row
);
880 if (typeof row
.name
=== "string") {
881 var word
= row
.name
.toLowerCase();
882 searchWords
.push(word
);
884 searchWords
.push("");
892 function startSearch() {
894 var callback = function() {
895 var search_input
= document
.getElementsByClassName('search-input');
896 if (search_input
.length
< 1) { return; }
897 search_input
= search_input
[0];
898 clearTimeout(searchTimeout
);
899 if (search_input
.value
.length
=== 0) {
900 if (browserSupportsHistoryApi()) {
901 history
.replaceState("", "std - Rust", "?search=");
903 var main
= document
.getElementById('main');
904 if (hasClass(main
, 'content')) {
905 removeClass(main
, 'hidden');
907 var search_c
= document
.getElementById('search');
908 if (hasClass(search_c
, 'content')) {
909 addClass(search_c
, 'hidden');
912 searchTimeout
= setTimeout(search
, 500);
915 var search_input
= document
.getElementsByClassName("search-input")[0];
916 search_input
.onkeyup
= callback
;
917 search_input
.oninput
= callback
;
918 document
.getElementsByClassName("search-form")[0].onsubmit = function(e
){
920 clearTimeout(searchTimeout
);
923 search_input
.onchange = function(e
) {
924 // Do NOT e.preventDefault() here. It will prevent pasting.
925 clearTimeout(searchTimeout
);
926 // zero-timeout necessary here because at the time of event handler execution the
927 // pasted content is not in the input field yet. Shouldn’t make any difference for
929 setTimeout(search
, 0);
931 search_input
.onpaste
= search_input
.onchange
;
933 // Push and pop states are used to add search results to the browser
935 if (browserSupportsHistoryApi()) {
936 // Store the previous <title> so we can revert back to it later.
937 var previousTitle
= document
.title
;
939 window
.onpopstate = function(e
) {
940 var params
= getQueryStringParams();
941 // When browsing back from search results the main page
942 // visibility must be reset.
943 if (!params
.search
) {
944 var main
= document
.getElementById('main');
945 if (hasClass(main
, 'content')) {
946 removeClass(main
, 'hidden');
948 var search_c
= document
.getElementById('search');
949 if (hasClass(search_c
, 'content')) {
950 addClass(search_c
, 'hidden');
953 // Revert to the previous title manually since the History
954 // API ignores the title parameter.
955 document
.title
= previousTitle
;
956 // When browsing forward to search results the previous
957 // search will be repeated, so the currentResults are
958 // cleared to ensure the search is successful.
959 currentResults
= null;
960 // Synchronize search bar with query string state and
961 // perform the search. This will empty the bar if there's
962 // nothing there, which lets you really go back to a
963 // previous state with nothing in the bar.
965 document
.getElementsByClassName('search-input')[0].value
= params
.search
;
967 document
.getElementsByClassName('search-input')[0].value
= '';
969 // Some browsers fire 'onpopstate' for every page load
970 // (Chrome), while others fire the event only when actually
971 // popping a state (Firefox), which is why search() is
972 // called both here and at the end of the startSearch()
980 index
= buildIndex(rawSearchIndex
);
983 // Draw a convenient sidebar of known crates if we have a listing
984 if (rootPath
=== '../') {
985 var sidebar
= document
.getElementsByClassName('sidebar')[0];
986 var div
= document
.createElement('div');
987 div
.className
= 'block crate';
988 div
.innerHTML
= '<h3>Crates</h3>';
989 var ul
= document
.createElement('ul');
993 for (var crate
in rawSearchIndex
) {
994 if (!rawSearchIndex
.hasOwnProperty(crate
)) { continue; }
998 for (var i
= 0; i
< crates
.length
; ++i
) {
1000 if (crates
[i
] === window
.currentCrate
) {
1001 klass
+= ' current';
1003 var link
= document
.createElement('a');
1004 link
.href
= '../' + crates
[i
] + '/index.html';
1005 link
.title
= rawSearchIndex
[crates
[i
]].doc
;
1006 link
.className
= klass
;
1007 link
.textContent
= crates
[i
];
1009 var li
= document
.createElement('li');
1010 li
.appendChild(link
);
1013 sidebar
.appendChild(div
);
1017 window
.initSearch
= initSearch
;
1019 // delayed sidebar rendering.
1020 function initSidebarItems(items
) {
1021 var sidebar
= document
.getElementsByClassName('sidebar')[0];
1022 var current
= window
.sidebarCurrent
;
1024 function block(shortty
, longty
) {
1025 var filtered
= items
[shortty
];
1026 if (!filtered
) { return; }
1028 var div
= document
.createElement('div');
1029 div
.className
= 'block ' + shortty
;
1030 var h3
= document
.createElement('h3');
1031 h3
.textContent
= longty
;
1032 div
.appendChild(h3
);
1033 var ul
= document
.createElement('ul');
1035 for (var i
= 0; i
< filtered
.length
; ++i
) {
1036 var item
= filtered
[i
];
1038 var desc
= item
[1]; // can be null
1040 var klass
= shortty
;
1041 if (name
=== current
.name
&& shortty
=== current
.ty
) {
1042 klass
+= ' current';
1045 if (shortty
=== 'mod') {
1046 path
= name
+ '/index.html';
1048 path
= shortty
+ '.' + name
+ '.html';
1050 var link
= document
.createElement('a');
1051 link
.href
= current
.relpath
+ path
;
1053 link
.className
= klass
;
1054 link
.textContent
= name
;
1055 var li
= document
.createElement('li');
1056 li
.appendChild(link
);
1059 div
.appendChild(ul
);
1060 sidebar
.appendChild(div
);
1063 block("primitive", "Primitive Types");
1064 block("mod", "Modules");
1065 block("macro", "Macros");
1066 block("struct", "Structs");
1067 block("enum", "Enums");
1068 block("union", "Unions");
1069 block("constant", "Constants");
1070 block("static", "Statics");
1071 block("trait", "Traits");
1072 block("fn", "Functions");
1073 block("type", "Type Definitions");
1076 window
.initSidebarItems
= initSidebarItems
;
1078 window
.register_implementors = function(imp
) {
1079 var list
= document
.getElementById('implementors-list');
1080 var libs
= Object
.getOwnPropertyNames(imp
);
1081 for (var i
= 0; i
< libs
.length
; ++i
) {
1082 if (libs
[i
] === currentCrate
) { continue; }
1083 var structs
= imp
[libs
[i
]];
1084 for (var j
= 0; j
< structs
.length
; ++j
) {
1085 var code
= document
.createElement('code');
1086 code
.innerHTML
= structs
[j
];
1088 var x
= code
.getElementsByTagName('a');
1089 for (var k
= 0; k
< x
.length
; k
++) {
1090 var href
= x
[k
].getAttribute('href');
1091 if (href
&& href
.indexOf('http') !== 0) {
1092 x
[k
].setAttribute('href', rootPath
+ href
);
1095 var li
= document
.createElement('li');
1096 li
.appendChild(code
);
1097 list
.appendChild(li
);
1101 if (window
.pending_implementors
) {
1102 window
.register_implementors(window
.pending_implementors
);
1105 function labelForToggleButton(sectionIsCollapsed
) {
1106 if (sectionIsCollapsed
) {
1107 // button will expand the section
1110 // button will collapse the section
1111 // note that this text is also set in the HTML template in render.rs
1112 return "\u2212"; // "\u2212" is '−' minus sign
1115 function onEveryMatchingChild(elem
, className
, func
) {
1116 if (elem
&& className
&& func
) {
1117 for (var i
= 0; i
< elem
.childNodes
.length
; i
++) {
1118 if (hasClass(elem
.childNodes
[i
], className
)) {
1119 func(elem
.childNodes
[i
]);
1121 onEveryMatchingChild(elem
.childNodes
[i
], className
, func
);
1127 function toggleAllDocs() {
1128 var toggle
= document
.getElementById("toggle-all-docs");
1129 if (hasClass(toggle
, "will-expand")) {
1130 removeClass(toggle
, "will-expand");
1131 onEveryMatchingChild(toggle
, "inner", function(e
) {
1132 e
.innerHTML
= labelForToggleButton(false);
1134 toggle
.title
= "collapse all docs";
1135 onEach(document
.getElementsByClassName("docblock"), function(e
) {
1136 e
.style
.display
= 'block';
1138 onEach(document
.getElementsByClassName("toggle-label"), function(e
) {
1139 e
.style
.display
= 'none';
1141 onEach(document
.getElementsByClassName("toggle-wrapper"), function(e
) {
1142 removeClass(e
, "collapsed");
1144 onEach(document
.getElementsByClassName("collapse-toggle"), function(e
) {
1145 onEveryMatchingChild(e
, "inner", function(i_e
) {
1146 i_e
.innerHTML
= labelForToggleButton(false);
1150 addClass(toggle
, "will-expand");
1151 onEveryMatchingChild(toggle
, "inner", function(e
) {
1152 e
.innerHTML
= labelForToggleButton(true);
1154 toggle
.title
= "expand all docs";
1155 onEach(document
.getElementsByClassName("docblock"), function(e
) {
1156 e
.style
.display
= 'none';
1158 onEach(document
.getElementsByClassName("toggle-label"), function(e
) {
1159 e
.style
.display
= 'inline-block';
1161 onEach(document
.getElementsByClassName("toggle-wrapper"), function(e
) {
1162 addClass(e
, "collapsed");
1164 onEach(document
.getElementsByClassName("collapse-toggle"), function(e
) {
1165 onEveryMatchingChild(e
, "inner", function(i_e
) {
1166 i_e
.innerHTML
= labelForToggleButton(true);
1172 function collapseDocs(toggle
) {
1173 if (!toggle
|| !toggle
.parentNode
) {
1176 var relatedDoc
= toggle
.parentNode
.nextElementSibling
;
1177 if (hasClass(relatedDoc
, "stability")) {
1178 relatedDoc
= relatedDoc
.nextElementSibling
;
1180 if (hasClass(relatedDoc
, "docblock")) {
1181 if (!isHidden(relatedDoc
)) {
1182 relatedDoc
.style
.display
= 'none';
1183 onEach(toggle
.childNodes
, function(e
) {
1184 if (hasClass(e
, 'toggle-label')) {
1185 e
.style
.display
= 'inline-block';
1187 if (hasClass(e
, 'inner')) {
1188 e
.innerHTML
= labelForToggleButton(true);
1191 addClass(toggle
.parentNode
, 'collapsed');
1193 relatedDoc
.style
.display
= 'block';
1194 removeClass(toggle
.parentNode
, 'collapsed');
1195 onEach(toggle
.childNodes
, function(e
) {
1196 if (hasClass(e
, 'toggle-label')) {
1197 e
.style
.display
= 'none';
1199 if (hasClass(e
, 'inner')) {
1200 e
.innerHTML
= labelForToggleButton(false);
1207 var x
= document
.getElementById('toggle-all-docs');
1209 x
.onclick
= toggleAllDocs
;
1212 function insertAfter(newNode
, referenceNode
) {
1213 referenceNode
.parentNode
.insertBefore(newNode
, referenceNode
.nextSibling
);
1216 var toggle
= document
.createElement('a');
1217 toggle
.href
= 'javascript:void(0)';
1218 toggle
.className
= 'collapse-toggle';
1219 toggle
.innerHTML
= "[<span class='inner'>"+labelForToggleButton(false)+"</span>]";
1221 var func = function(e
) {
1222 var next
= e
.nextElementSibling
;
1226 if (hasClass(next
, 'docblock') ||
1227 (hasClass(next
, 'stability') &&
1228 hasClass(next
.nextElementSibling
, 'docblock'))) {
1229 insertAfter(toggle
.cloneNode(true), e
.childNodes
[e
.childNodes
.length
- 1]);
1232 onEach(document
.getElementsByClassName('method'), func
);
1233 onEach(document
.getElementsByClassName('impl-items'), function(e
) {
1234 onEach(e
.getElementsByClassName('associatedconstant'), func
);
1237 function createToggle() {
1238 var span
= document
.createElement('span');
1239 span
.className
= 'toggle-label';
1240 span
.style
.display
= 'none';
1241 span
.innerHTML
= ' Expand description';
1243 var mainToggle
= toggle
.cloneNode(true);
1244 mainToggle
.appendChild(span
);
1246 var wrapper
= document
.createElement('div');
1247 wrapper
.className
= 'toggle-wrapper';
1248 wrapper
.appendChild(mainToggle
);
1252 onEach(document
.getElementById('main').getElementsByClassName('docblock'), function(e
) {
1253 if (e
.parentNode
.id
=== "main") {
1254 e
.parentNode
.insertBefore(createToggle(), e
);
1258 onEach(document
.getElementsByClassName('docblock'), function(e
) {
1259 if (hasClass(e
, 'autohide')) {
1260 var wrap
= e
.previousElementSibling
;
1261 if (wrap
&& hasClass(wrap
, 'toggle-wrapper')) {
1262 var toggle
= wrap
.childNodes
[0];
1263 if (e
.childNodes
[0].tagName
=== 'H3') {
1264 onEach(toggle
.getElementsByClassName('toggle-label'), function(i_e
) {
1265 i_e
.innerHTML
= " Show " + e
.childNodes
[0].innerHTML
;
1268 e
.style
.display
= 'none';
1269 addClass(wrap
, 'collapsed');
1270 onEach(toggle
.getElementsByClassName('inner'), function(e
) {
1271 e
.innerHTML
= labelForToggleButton(true);
1273 onEach(toggle
.getElementsByClassName('toggle-label'), function(e
) {
1274 e
.style
.display
= 'inline-block';
1280 function createToggleWrapper() {
1281 var span
= document
.createElement('span');
1282 span
.className
= 'toggle-label';
1283 span
.style
.display
= 'none';
1284 span
.innerHTML
= ' Expand attributes';
1285 toggle
.appendChild(span
);
1287 var wrapper
= document
.createElement('div');
1288 wrapper
.className
= 'toggle-wrapper toggle-attributes';
1289 wrapper
.appendChild(toggle
);
1293 onEach(document
.getElementById('main').getElementsByTagName('pre'), function(e
) {
1294 onEach(e
.getElementsByClassName('attributes'), function(i_e
) {
1295 i_e
.parentNode
.insertBefore(createToggleWrapper(), i_e
);
1296 collapseDocs(i_e
.previousSibling
.childNodes
[0]);
1301 // Sets the focus on the search bar at the top of the page
1302 function focusSearchBar() {
1303 document
.getElementsByClassName('search-input')[0].focus();