]>
git.proxmox.com Git - rustc.git/blob - src/librustdoc/html/static/main.js
1 // Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 /*jslint browser: true, es5: true */
12 /*globals $: true, rootPath: true */
17 // This mapping table should match the discriminants of
18 // `rustdoc::html::item_type::ItemType` type in Rust.
19 var itemTypes
= ["mod",
37 "associatedconstant"];
39 // used for special search precedence
40 var TY_PRIMITIVE
= itemTypes
.indexOf("primitive");
42 $('.js-only').removeClass('js-only');
44 function getQueryStringParams() {
46 window
.location
.search
.substring(1).split("&").
48 var pair
= s
.split("=");
49 params
[decodeURIComponent(pair
[0])] =
50 typeof pair
[1] === "undefined" ?
51 null : decodeURIComponent(pair
[1]);
56 function browserSupportsHistoryApi() {
57 return document
.location
.protocol
!= "file:" &&
58 window
.history
&& typeof window
.history
.pushState
=== "function";
61 function highlightSourceLines(ev
) {
62 var i
, from, to
, match
= window
.location
.hash
.match(/^#?(\d+)(?:-(\d+))?$/);
64 from = parseInt(match
[1], 10);
65 to
= Math
.min(50000, parseInt(match
[2] || match
[1], 10));
66 from = Math
.min(from, to
);
67 if ($('#' + from).length
=== 0) {
70 if (ev
=== null) { $('#' + from)[0].scrollIntoView(); };
71 $('.line-numbers span').removeClass('line-highlighted');
72 for (i
= from; i
<= to
; ++i
) {
73 $('#' + i
).addClass('line-highlighted');
77 highlightSourceLines(null);
78 $(window
).on('hashchange', highlightSourceLines
);
80 // Gets the human-readable string for the virtual-key code of the
81 // given KeyboardEvent, ev.
83 // This function is meant as a polyfill for KeyboardEvent#key,
84 // since it is not supported in Trident. We also test for
85 // KeyboardEvent#keyCode because the handleShortcut handler is
86 // also registered for the keydown event, because Blink doesn't fire
87 // keypress on hitting the Escape key.
89 // So I guess you could say things are getting pretty interoperable.
90 function getVirtualKey(ev
) {
91 if ("key" in ev
&& typeof ev
.key
!= "undefined")
94 var c
= ev
.charCode
|| ev
.keyCode
;
97 return String
.fromCharCode(c
);
100 function handleShortcut(ev
) {
101 if (document
.activeElement
.tagName
== "INPUT")
104 // Don't interfere with browser shortcuts
105 if (ev
.ctrlKey
|| ev
.altKey
|| ev
.metaKey
)
108 switch (getVirtualKey(ev
)) {
110 if (!$("#help").hasClass("hidden")) {
112 $("#help").addClass("hidden");
113 $("body").removeClass("blur");
114 } else if (!$("#search").hasClass("hidden")) {
116 $("#search").addClass("hidden");
117 $("#main").removeClass("hidden");
128 if (ev
.shiftKey
&& $("#help").hasClass("hidden")) {
130 $("#help").removeClass("hidden");
131 $("body").addClass("blur");
137 $(document
).on("keypress", handleShortcut
);
138 $(document
).on("keydown", handleShortcut
);
139 $(document
).on("click", function(ev
) {
140 if (!$(ev
.target
).closest("#help > div").length
) {
141 $("#help").addClass("hidden");
142 $("body").removeClass("blur");
146 $('.version-selector').on('change', function() {
148 url
= document
.location
.href
,
150 len
= rootPath
.match(/\.\.\//g).length
+ 1;
152 for (i
= 0; i
< len
; ++i
) {
153 match
= url
.match(/\/[^\/]*$/);
155 stripped
= match
[0] + stripped
;
157 url
= url
.substring(0, url
.length
- match
[0].length
);
160 url
+= '/' + $('.version-selector').val() + stripped
;
162 document
.location
.href
= url
;
166 * A function to compute the Levenshtein distance between two strings
167 * Licensed under the Creative Commons Attribution-ShareAlike 3.0 Unported
168 * Full License can be found at http://creativecommons.org/licenses/by-sa/3.0/legalcode
169 * This code is an unmodified version of the code written by Marco de Wit
170 * and was found at http://stackoverflow.com/a/18514751/745719
172 var levenshtein
= (function() {
174 return function(s1
, s2
) {
178 var s1_len
= s1
.length
, s2_len
= s2
.length
;
179 if (s1_len
&& s2_len
) {
180 var i1
= 0, i2
= 0, a
, b
, c
, c2
, row
= row2
;
181 while (i1
< s1_len
) {
184 while (i2
< s2_len
) {
185 c2
= s2
.charCodeAt(i2
);
189 for (i1
= 0; i1
< s1_len
; ++i1
) {
190 c
= a
+ (s1
.charCodeAt(i1
) !== c2
? 1 : 0);
192 b
= b
< a
? (b
< c
? b
+ 1 : c
) : (a
< c
? a
+ 1 : c
);
198 return s1_len
+ s2_len
;
202 function initSearch(rawSearchIndex
) {
203 var currentResults
, index
, searchIndex
;
204 var MAX_LEV_DISTANCE
= 3;
205 var params
= getQueryStringParams();
207 // Populate search bar with query string search term when provided,
208 // but only if the input bar is empty. This avoid the obnoxious issue
209 // where you start trying to do a search, and the index loads, and
210 // suddenly your search is gone!
211 if ($(".search-input")[0].value
=== "") {
212 $(".search-input")[0].value
= params
.search
|| '';
216 * Executes the query and builds an index of results
217 * @param {[Object]} query [The user query]
218 * @param {[type]} max [The maximum results returned]
219 * @param {[type]} searchWords [The list of search words to query
221 * @return {[type]} [A search index of results]
223 function execQuery(query
, max
, searchWords
) {
224 var valLower
= query
.query
.toLowerCase(),
226 typeFilter
= itemTypeFromName(query
.type
),
228 split
= valLower
.split("::");
230 // remove empty keywords
231 for (var j
= 0; j
< split
.length
; ++j
) {
232 split
[j
].toLowerCase();
233 if (split
[j
] === "") {
238 function typePassesFilter(filter
, type
) {
240 if (filter
< 0) return true;
243 if (filter
=== type
) return true;
245 // Match related items
246 var name
= itemTypes
[type
];
247 switch (itemTypes
[filter
]) {
249 return (name
== "associatedconstant");
251 return (name
== "method" || name
== "tymethod");
253 return (name
== "primitive");
260 // quoted values mean literal search
261 var nSearchWords
= searchWords
.length
;
262 if ((val
.charAt(0) === "\"" || val
.charAt(0) === "'") &&
263 val
.charAt(val
.length
- 1) === val
.charAt(0))
265 val
= val
.substr(1, val
.length
- 2);
266 for (var i
= 0; i
< nSearchWords
; ++i
) {
267 if (searchWords
[i
] === val
) {
268 // filter type: ... queries
269 if (typePassesFilter(typeFilter
, searchIndex
[i
].ty
)) {
270 results
.push({id
: i
, index
: -1});
273 if (results
.length
=== max
) {
278 } else if (val
.search("->") > -1) {
279 var trimmer = function (s
) { return s
.trim(); };
280 var parts
= val
.split("->").map(trimmer
);
281 var input
= parts
[0];
282 // sort inputs so that order does not matter
283 var inputs
= input
.split(",").map(trimmer
).sort().toString();
284 var output
= parts
[1];
286 for (var i
= 0; i
< nSearchWords
; ++i
) {
287 var type
= searchIndex
[i
].type
;
292 // sort index inputs so that order does not matter
293 var typeInputs
= type
.inputs
.map(function (input
) {
297 // allow searching for void (no output) functions as well
298 var typeOutput
= type
.output
? type
.output
.name
: "";
299 if ((inputs
=== "*" || inputs
=== typeInputs
.toString()) &&
300 (output
=== "*" || output
== typeOutput
)) {
301 results
.push({id
: i
, index
: -1, dontValidate
: true});
305 // gather matching search results up to a certain maximum
306 val
= val
.replace(/\_/g, "");
307 for (var i
= 0; i
< split
.length
; ++i
) {
308 for (var j
= 0; j
< nSearchWords
; ++j
) {
310 if (searchWords
[j
].indexOf(split
[i
]) > -1 ||
311 searchWords
[j
].indexOf(val
) > -1 ||
312 searchWords
[j
].replace(/_
/g
, "").indexOf(val
) > -1)
314 // filter type: ... queries
315 if (typePassesFilter(typeFilter
, searchIndex
[j
].ty
)) {
318 index
: searchWords
[j
].replace(/_
/g
, "").indexOf(val
),
323 (lev_distance
= levenshtein(searchWords
[j
], val
)) <=
325 if (typePassesFilter(typeFilter
, searchIndex
[j
].ty
)) {
329 // we want lev results to go lower than others
334 if (results
.length
=== max
) {
341 var nresults
= results
.length
;
342 for (var i
= 0; i
< nresults
; ++i
) {
343 results
[i
].word
= searchWords
[results
[i
].id
];
344 results
[i
].item
= searchIndex
[results
[i
].id
] || {};
346 // if there are no results then return to default and fail
347 if (results
.length
=== 0) {
351 results
.sort(function sortResults(aaa
, bbb
) {
354 // Sort by non levenshtein results and then levenshtein results by the distance
355 // (less changes required to match means higher rankings)
358 if (a
!== b
) { return a
- b
; }
360 // sort by crate (non-current crate goes later)
361 a
= (aaa
.item
.crate
!== window
.currentCrate
);
362 b
= (bbb
.item
.crate
!== window
.currentCrate
);
363 if (a
!== b
) { return a
- b
; }
365 // sort by exact match (mismatch goes later)
366 a
= (aaa
.word
!== valLower
);
367 b
= (bbb
.word
!== valLower
);
368 if (a
!== b
) { return a
- b
; }
370 // sort by item name length (longer goes later)
373 if (a
!== b
) { return a
- b
; }
375 // sort by item name (lexicographically larger goes later)
378 if (a
!== b
) { return (a
> b
? +1 : -1); }
380 // sort by index of keyword in item name (no literal occurrence goes later)
383 if (a
!== b
) { return a
- b
; }
384 // (later literal occurrence, if any, goes later)
387 if (a
!== b
) { return a
- b
; }
389 // special precedence for primitive pages
390 if ((aaa
.item
.ty
=== TY_PRIMITIVE
) && (bbb
.item
.ty
!== TY_PRIMITIVE
)) {
393 if ((bbb
.item
.ty
=== TY_PRIMITIVE
) && (aaa
.item
.ty
!== TY_PRIMITIVE
)) {
397 // sort by description (no description goes later)
398 a
= (aaa
.item
.desc
=== '');
399 b
= (bbb
.item
.desc
=== '');
400 if (a
!== b
) { return a
- b
; }
402 // sort by type (later occurrence in `itemTypes` goes later)
405 if (a
!== b
) { return a
- b
; }
407 // sort by path (lexicographically larger goes later)
410 if (a
!== b
) { return (a
> b
? +1 : -1); }
416 // remove duplicates, according to the data provided
417 for (var i
= results
.length
- 1; i
> 0; i
-= 1) {
418 if (results
[i
].word
=== results
[i
- 1].word
&&
419 results
[i
].item
.ty
=== results
[i
- 1].item
.ty
&&
420 results
[i
].item
.path
=== results
[i
- 1].item
.path
&&
421 (results
[i
].item
.parent
|| {}).name
=== (results
[i
- 1].item
.parent
|| {}).name
)
426 for (var i
= 0; i
< results
.length
; ++i
) {
427 var result
= results
[i
],
428 name
= result
.item
.name
.toLowerCase(),
429 path
= result
.item
.path
.toLowerCase(),
430 parent
= result
.item
.parent
;
432 // this validation does not make sense when searching by types
433 if (result
.dontValidate
) {
437 var valid
= validateResult(name
, path
, split
, parent
);
446 * Validate performs the following boolean logic. For example:
447 * "File::open" will give IF A PARENT EXISTS => ("file" && "open")
448 * exists in (name || path || parent) OR => ("file" && "open") exists in
451 * This could be written functionally, but I wanted to minimise
452 * functions on stack.
454 * @param {[string]} name [The name of the result]
455 * @param {[string]} path [The path of the result]
456 * @param {[string]} keys [The keys to be used (["file", "open"])]
457 * @param {[object]} parent [The parent of the result]
458 * @return {[boolean]} [Whether the result is valid or not]
460 function validateResult(name
, path
, keys
, parent
) {
461 for (var i
= 0; i
< keys
.length
; ++i
) {
462 // each check is for validation so we negate the conditions and invalidate
464 // check for an exact name match
465 name
.toLowerCase().indexOf(keys
[i
]) > -1 ||
466 // then an exact path match
467 path
.toLowerCase().indexOf(keys
[i
]) > -1 ||
468 // next if there is a parent, check for exact parent match
469 (parent
!== undefined &&
470 parent
.name
.toLowerCase().indexOf(keys
[i
]) > -1) ||
471 // lastly check to see if the name was a levenshtein match
472 levenshtein(name
.toLowerCase(), keys
[i
]) <=
480 function getQuery() {
481 var matches
, type
, query
, raw
= $('.search-input').val();
484 matches
= query
.match(/^(fn|mod|struct|enum|trait|type|const|macro)\s*:\s*/i);
486 type
= matches
[1].replace(/^const$/, 'constant');
487 query
= query
.substring(matches
[0].length
);
498 function initSearchNav() {
499 var hoverTimeout
, $results
= $('.search-results .result');
501 $results
.on('click', function() {
502 var dst
= $(this).find('a')[0];
503 if (window
.location
.pathname
=== dst
.pathname
) {
504 $('#search').addClass('hidden');
505 $('#main').removeClass('hidden');
506 document
.location
.href
= dst
.href
;
508 }).on('mouseover', function() {
510 clearTimeout(hoverTimeout
);
511 hoverTimeout
= setTimeout(function() {
512 $results
.removeClass('highlighted');
513 $el
.addClass('highlighted');
517 $(document
).off('keydown.searchnav');
518 $(document
).on('keydown.searchnav', function(e
) {
519 var $active
= $results
.filter('.highlighted');
521 if (e
.which
=== 38) { // up
522 if (!$active
.length
|| !$active
.prev()) {
526 $active
.prev().addClass('highlighted');
527 $active
.removeClass('highlighted');
528 } else if (e
.which
=== 40) { // down
529 if (!$active
.length
) {
530 $results
.first().addClass('highlighted');
531 } else if ($active
.next().length
) {
532 $active
.next().addClass('highlighted');
533 $active
.removeClass('highlighted');
535 } else if (e
.which
=== 13) { // return
536 if ($active
.length
) {
537 document
.location
.href
= $active
.find('a').prop('href');
540 $active
.removeClass('highlighted');
545 function escape(content
) {
546 return $('<h1/>').text(content
).html();
549 function showResults(results
) {
550 var output
, shown
, query
= getQuery();
552 currentResults
= query
.id
;
553 output
= '<h1>Results for ' + escape(query
.query
) +
554 (query
.type
? ' (type: ' + escape(query
.type
) + ')' : '') + '</h1>';
555 output
+= '<table class="search-results">';
557 if (results
.length
> 0) {
560 results
.forEach(function(item
) {
561 var name
, type
, href
, displayPath
;
563 if (shown
.indexOf(item
) !== -1) {
569 type
= itemTypes
[item
.ty
];
571 if (type
=== 'mod') {
572 displayPath
= item
.path
+ '::';
573 href
= rootPath
+ item
.path
.replace(/::/g, '/') + '/' +
574 name
+ '/index.html';
575 } else if (type
=== 'static' || type
=== 'reexport') {
576 displayPath
= item
.path
+ '::';
577 href
= rootPath
+ item
.path
.replace(/::/g, '/') +
579 } else if (type
=== "primitive") {
581 href
= rootPath
+ item
.path
.replace(/::/g, '/') +
582 '/' + type
+ '.' + name
+ '.html';
583 } else if (type
=== "externcrate") {
585 href
= rootPath
+ name
+ '/index.html';
586 } else if (item
.parent
!== undefined) {
587 var myparent
= item
.parent
;
588 var anchor
= '#' + type
+ '.' + name
;
589 displayPath
= item
.path
+ '::' + myparent
.name
+ '::';
590 href
= rootPath
+ item
.path
.replace(/::/g, '/') +
591 '/' + itemTypes
[myparent
.ty
] +
592 '.' + myparent
.name
+
595 displayPath
= item
.path
+ '::';
596 href
= rootPath
+ item
.path
.replace(/::/g, '/') +
597 '/' + type
+ '.' + name
+ '.html';
600 output
+= '<tr class="' + type
+ ' result"><td>' +
601 '<a href="' + href
+ '">' +
602 displayPath
+ '<span class="' + type
+ '">' +
603 name
+ '</span></a></td><td>' +
604 '<a href="' + href
+ '">' +
605 '<span class="desc">' + item
.desc
+
606 ' </span></a></td></tr>';
609 output
+= 'No results :( <a href="https://duckduckgo.com/?q=' +
610 encodeURIComponent('rust ' + query
.query
) +
611 '">Try on DuckDuckGo?</a>';
615 $('#main.content').addClass('hidden');
616 $('#search.content').removeClass('hidden').html(output
);
617 $('#search .desc').width($('#search').width() - 40 -
618 $('#search td:first-child').first().width());
629 var params
= getQueryStringParams();
636 if (!query
.query
|| query
.id
=== currentResults
) {
640 // Update document title to maintain a meaningful browser history
641 $(document
).prop("title", "Results for " + query
.query
+ " - Rust");
643 // Because searching is incremental by character, only the most
644 // recent search query is added to the browser history.
645 if (browserSupportsHistoryApi()) {
646 if (!history
.state
&& !params
.search
) {
647 history
.pushState(query
, "", "?search=" +
648 encodeURIComponent(query
.raw
));
650 history
.replaceState(query
, "", "?search=" +
651 encodeURIComponent(query
.raw
));
655 resultIndex
= execQuery(query
, 20000, index
);
656 len
= resultIndex
.length
;
657 for (i
= 0; i
< len
; ++i
) {
658 if (resultIndex
[i
].id
> -1) {
659 obj
= searchIndex
[resultIndex
[i
].id
];
660 filterdata
.push([obj
.name
, obj
.ty
, obj
.path
, obj
.desc
]);
663 if (results
.length
>= maxResults
) {
668 showResults(results
);
671 function itemTypeFromName(typename
) {
672 for (var i
= 0; i
< itemTypes
.length
; ++i
) {
673 if (itemTypes
[i
] === typename
) { return i
; }
678 function buildIndex(rawSearchIndex
) {
680 var searchWords
= [];
681 for (var crate
in rawSearchIndex
) {
682 if (!rawSearchIndex
.hasOwnProperty(crate
)) { continue; }
684 searchWords
.push(crate
);
687 ty
: 1, // == ExternCrate
690 desc
: rawSearchIndex
[crate
].doc
,
694 // an array of [(Number) item type,
696 // (String) full path or empty string for previous path,
697 // (String) description,
698 // (Number | null) the parent path index to `paths`]
699 // (Object | null) the type of the function (if any)
700 var items
= rawSearchIndex
[crate
].items
;
701 // an array of [(Number) item type,
703 var paths
= rawSearchIndex
[crate
].paths
;
705 // convert `paths` into an object form
706 var len
= paths
.length
;
707 for (var i
= 0; i
< len
; ++i
) {
708 paths
[i
] = {ty
: paths
[i
][0], name
: paths
[i
][1]};
711 // convert `items` into an object form, and construct word indices.
713 // before any analysis is performed lets gather the search terms to
714 // search against apart from the rest of the data. This is a quick
715 // operation that is cached for the life of the page state so that
716 // all other search operations have access to this cached data for
717 // faster analysis operations
718 var len
= items
.length
;
720 for (var i
= 0; i
< len
; ++i
) {
721 var rawRow
= items
[i
];
722 var row
= {crate
: crate
, ty
: rawRow
[0], name
: rawRow
[1],
723 path
: rawRow
[2] || lastPath
, desc
: rawRow
[3],
724 parent
: paths
[rawRow
[4]], type
: rawRow
[5]};
725 searchIndex
.push(row
);
726 if (typeof row
.name
=== "string") {
727 var word
= row
.name
.toLowerCase();
728 searchWords
.push(word
);
730 searchWords
.push("");
738 function startSearch() {
740 $(".search-input").on("keyup input",function() {
741 clearTimeout(searchTimeout
);
742 if ($(this).val().length
=== 0) {
743 if (browserSupportsHistoryApi()) {
744 history
.replaceState("", "std - Rust", "?search=");
746 $('#main.content').removeClass('hidden');
747 $('#search.content').addClass('hidden');
749 searchTimeout
= setTimeout(search
, 500);
752 $('.search-form').on('submit', function(e
){
754 clearTimeout(searchTimeout
);
757 $('.search-input').on('change paste', function(e
) {
758 // Do NOT e.preventDefault() here. It will prevent pasting.
759 clearTimeout(searchTimeout
);
760 // zero-timeout necessary here because at the time of event handler execution the
761 // pasted content is not in the input field yet. Shouldn’t make any difference for
763 setTimeout(search
, 0);
766 // Push and pop states are used to add search results to the browser
768 if (browserSupportsHistoryApi()) {
769 // Store the previous <title> so we can revert back to it later.
770 var previousTitle
= $(document
).prop("title");
772 $(window
).on('popstate', function(e
) {
773 var params
= getQueryStringParams();
774 // When browsing back from search results the main page
775 // visibility must be reset.
776 if (!params
.search
) {
777 $('#main.content').removeClass('hidden');
778 $('#search.content').addClass('hidden');
780 // Revert to the previous title manually since the History
781 // API ignores the title parameter.
782 $(document
).prop("title", previousTitle
);
783 // When browsing forward to search results the previous
784 // search will be repeated, so the currentResults are
785 // cleared to ensure the search is successful.
786 currentResults
= null;
787 // Synchronize search bar with query string state and
788 // perform the search. This will empty the bar if there's
789 // nothing there, which lets you really go back to a
790 // previous state with nothing in the bar.
791 $('.search-input').val(params
.search
);
792 // Some browsers fire 'onpopstate' for every page load
793 // (Chrome), while others fire the event only when actually
794 // popping a state (Firefox), which is why search() is
795 // called both here and at the end of the startSearch()
803 function plainSummaryLine(markdown
) {
804 markdown
.replace(/\n/g, ' ')
806 .replace(/^#+? (.+?)/, "$1")
807 .replace(/\[(.*?)\]\(.*?\)/g, "$1")
808 .replace(/\[(.*?)\]\[.*?\]/g, "$1");
811 index = buildIndex(rawSearchIndex);
814 // Draw a convenient sidebar of known crates if we have a listing
815 if (rootPath === '../') {
816 var sidebar = $('.sidebar
');
817 var div = $('<div
>').attr('class', 'block crate
');
818 div.append($('<h3
>').text('Crates
'));
819 var ul = $('<ul
>').appendTo(div);
822 for (var crate in rawSearchIndex) {
823 if (!rawSearchIndex.hasOwnProperty(crate)) { continue; }
827 for (var i = 0; i < crates.length; ++i) {
829 if (crates[i] === window.currentCrate) {
832 if (rawSearchIndex[crates[i]].items[0]) {
833 var desc = rawSearchIndex[crates[i]].items[0][3];
834 var link = $('<a
>', {'href
': '../' + crates[i] + '/index.html
',
835 'title
': plainSummaryLine(desc),
836 'class': klass}).text(crates[i]);
837 ul.append($('<li
>').append(link));
844 window.initSearch = initSearch;
846 // delayed sidebar rendering.
847 function initSidebarItems(items) {
848 var sidebar = $('.sidebar
');
849 var current = window.sidebarCurrent;
851 function block(shortty, longty) {
852 var filtered = items[shortty];
853 if (!filtered) { return; }
855 var div = $('<div
>').attr('class', 'block
' + shortty);
856 div.append($('<h3
>').text(longty));
857 var ul = $('<ul
>').appendTo(div);
859 for (var i = 0; i < filtered.length; ++i) {
860 var item = filtered[i];
862 var desc = item[1]; // can be null
865 if (name === current.name && shortty === current.ty) {
869 if (shortty === 'mod
') {
870 path = name + '/index
.html
';
872 path = shortty + '.' + name + '.html
';
874 var link = $('<a
>', {'href
': current.relpath + path,
876 'class': klass}).text(name);
877 ul.append($('<li
>').append(link));
882 block("mod", "Modules");
883 block("struct", "Structs");
884 block("enum", "Enums");
885 block("trait", "Traits");
886 block("fn", "Functions");
887 block("macro", "Macros");
890 window.initSidebarItems = initSidebarItems;
892 window.register_implementors = function(imp) {
893 var list = $('#implementors
-list
');
894 var libs = Object.getOwnPropertyNames(imp);
895 for (var i = 0; i < libs.length; ++i) {
896 if (libs[i] === currentCrate) { continue; }
897 var structs = imp[libs[i]];
898 for (var j = 0; j < structs.length; ++j) {
899 var code = $('<code
>').append(structs[j]);
900 $.each(code.find('a
'), function(idx, a) {
901 var href = $(a).attr('href
');
902 if (href && href.indexOf('http
') !== 0) {
903 $(a).attr('href
', rootPath + href);
906 var li = $('<li
>').append(code);
911 if (window.pending_implementors) {
912 window.register_implementors(window.pending_implementors);
915 // See documentation in html/render.rs for what this is doing.
916 var query = getQueryStringParams();
917 if (query['gotosrc
']) {
918 window.location = $('#src
-' + query['gotosrc
']).attr('href
');
920 if (query['gotomacrosrc
']) {
921 window.location = $('.srclink
').attr('href
');
924 function labelForToggleButton(sectionIsCollapsed) {
925 if (sectionIsCollapsed) {
926 // button will expand the section
929 // button will collapse the section
930 // note that this text is also set in the HTML template in render.rs
931 return "\u2212"; // "\u2212" is '−' minus sign
934 $("#toggle-all-docs").on("click", function() {
935 var toggle = $("#toggle-all-docs");
936 if (toggle.hasClass("will-expand")) {
937 toggle.removeClass("will-expand");
938 toggle.children(".inner").text(labelForToggleButton(false));
939 toggle.attr("title", "collapse all docs");
940 $(".docblock").show();
941 $(".toggle-label").hide();
942 $(".toggle-wrapper").removeClass("collapsed");
943 $(".collapse-toggle").children(".inner").text(labelForToggleButton(false));
945 toggle.addClass("will-expand");
946 toggle.children(".inner").text(labelForToggleButton(true));
947 toggle.attr("title", "expand all docs");
948 $(".docblock").hide();
949 $(".toggle-label").show();
950 $(".toggle-wrapper").addClass("collapsed");
951 $(".collapse-toggle").children(".inner").text(labelForToggleButton(true));
955 $(document).on("click", ".collapse-toggle", function() {
956 var toggle = $(this);
957 var relatedDoc = toggle.parent().next();
958 if (relatedDoc.is(".stability")) {
959 relatedDoc = relatedDoc.next();
961 if (relatedDoc.is(".docblock")) {
962 if (relatedDoc.is(":visible")) {
963 relatedDoc.slideUp({duration: 'fast
', easing: 'linear
'});
964 toggle.parent(".toggle-wrapper").addClass("collapsed");
965 toggle.children(".inner").text(labelForToggleButton(true));
966 toggle.children(".toggle-label").fadeIn();
968 relatedDoc.slideDown({duration: 'fast
', easing: 'linear
'});
969 toggle.parent(".toggle-wrapper").removeClass("collapsed");
970 toggle.children(".inner").text(labelForToggleButton(false));
971 toggle.children(".toggle-label").hide();
977 var toggle = $("<a/>", {'href
': 'javascript
:void(0)', 'class': 'collapse
-toggle
'})
978 .html("[<span class='inner
'></span>]");
979 toggle.children(".inner").text(labelForToggleButton(false));
981 $(".method").each(function() {
982 if ($(this).next().is(".docblock") ||
983 ($(this).next().is(".stability") && $(this).next().next().is(".docblock"))) {
984 $(this).children().first().after(toggle.clone());
990 $('<span
/>', {'class': 'toggle
-label
'})
991 .css('display
', 'none
')
992 .html(' 
;Expand
 
;description
'));
993 var wrapper = $("<div class='toggle
-wrapper
'>").append(mainToggle);
994 $("#main > .docblock").before(wrapper);
997 $('pre
.line
-numbers
').on('click
', 'span
', function() {
1000 function set_fragment(name) {
1001 if (browserSupportsHistoryApi()) {
1002 history.replaceState(null, null, '#' + name);
1003 $(window).trigger('hashchange
');
1005 location.replace('#' + name);
1009 return function(ev) {
1010 var cur_id = parseInt(ev.target.id, 10);
1012 if (ev.shiftKey && prev_id) {
1013 if (prev_id > cur_id) {
1019 set_fragment(prev_id + '-' + cur_id);
1023 set_fragment(cur_id);
1030 // Sets the focus on the search bar at the top of the page
1031 function focusSearchBar() {
1032 $('.search
-input
').focus();