]> git.lizzy.rs Git - rust.git/blobdiff - src/librustdoc/html/static/main.js
Add hide/show detail toggles to rustdoc
[rust.git] / src / librustdoc / html / static / main.js
index 2fb824653d3dbd4df42bbe7bf82d4939479f6278..9b44dc63f383b889f1a6b095ca1d661276f90432 100644 (file)
@@ -42,6 +42,9 @@
             $('.docblock.short').width(function() {
                 return contentWidth - 40 - $(this).prev().width();
             }).addClass('nowrap');
+            $('.summary-column').width(function() {
+                return contentWidth - 40 - $(this).prev().width();
+            })
         }, 150);
     }
     resizeShortBlocks();
@@ -58,7 +61,7 @@
             }
             $('#' + from)[0].scrollIntoView();
             $('.line-numbers span').removeClass('line-highlighted');
-            for (i = from; i <= to; i += 1) {
+            for (i = from; i <= to; ++i) {
                 $('#' + i).addClass('line-highlighted');
             }
         }
             return;
         }
 
-        if (e.keyCode === 188 && $('#help').hasClass('hidden')) { // question mark
+        if (e.which === 191 && $('#help').hasClass('hidden')) { // question mark
             e.preventDefault();
             $('#help').removeClass('hidden');
-        } else if (e.keyCode === 27) { // esc
+        } else if (e.which === 27) { // esc
             if (!$('#help').hasClass('hidden')) {
                 e.preventDefault();
                 $('#help').addClass('hidden');
@@ -83,7 +86,7 @@
                 $('#search').addClass('hidden');
                 $('#main').removeClass('hidden');
             }
-        } else if (e.keyCode === 83) { // S
+        } else if (e.which === 83) { // S
             e.preventDefault();
             $('.search-input').focus();
         }
             stripped = '',
             len = rootPath.match(/\.\.\//g).length + 1;
 
-        for (i = 0; i < len; i += 1) {
+        for (i = 0; i < len; ++i) {
             match = url.match(/\/[^\/]*$/);
             if (i < len - 1) {
                 stripped = match[0] + stripped;
 
         document.location.href = url;
     });
+    /**
+     * A function to compute the Levenshtein distance between two strings
+     * Licensed under the Creative Commons Attribution-ShareAlike 3.0 Unported
+     * Full License can be found at http://creativecommons.org/licenses/by-sa/3.0/legalcode
+     * This code is an unmodified version of the code written by Marco de Wit 
+     * and was found at http://stackoverflow.com/a/18514751/745719
+     */
+    var levenshtein = (function() {
+        var row2 = [];
+        return function(s1, s2) {
+            if (s1 === s2) {
+                return 0;
+            } else {
+                var s1_len = s1.length, s2_len = s2.length;
+                if (s1_len && s2_len) {
+                    var i1 = 0, i2 = 0, a, b, c, c2, row = row2;
+                    while (i1 < s1_len)
+                        row[i1] = ++i1;
+                    while (i2 < s2_len) {
+                        c2 = s2.charCodeAt(i2);
+                        a = i2;
+                        ++i2;
+                        b = i2;
+                        for (i1 = 0; i1 < s1_len; ++i1) {
+                            c = a + (s1.charCodeAt(i1) !== c2 ? 1 : 0);
+                            a = row[i1];
+                            b = b < a ? (b < c ? b + 1 : c) : (a < c ? a + 1 : c);
+                            row[i1] = b;
+                        }
+                    }
+                    return b;
+                } else {
+                    return s1_len + s2_len;
+                }
+            }
+        };
+    })();
 
     function initSearch(rawSearchIndex) {
         var currentResults, index, searchIndex;
+        var MAX_LEV_DISTANCE = 3;
         var params = getQueryStringParams();
 
         // Populate search bar with query string search term when provided,
                 split = valLower.split("::");
 
             //remove empty keywords
-            for (var j = 0; j < split.length; j++) {
+            for (var j = 0; j < split.length; ++j) {
                 split[j].toLowerCase();
                 if (split[j] === "") {
                     split.splice(j, 1);
                 val.charAt(val.length - 1) === val.charAt(0))
             {
                 val = val.substr(1, val.length - 2);
-                for (var i = 0; i < nSearchWords; i += 1) {
+                for (var i = 0; i < nSearchWords; ++i) {
                     if (searchWords[i] === val) {
                         // filter type: ... queries
                         if (typeFilter < 0 || typeFilter === searchIndex[i].ty) {
             } else {
                 // gather matching search results up to a certain maximum
                 val = val.replace(/\_/g, "");
-                for (var i = 0; i < split.length; i++) {
-                    for (var j = 0; j < nSearchWords; j += 1) {
+                for (var i = 0; i < split.length; ++i) {
+                    for (var j = 0; j < nSearchWords; ++j) {
+                        var lev_distance;
                         if (searchWords[j].indexOf(split[i]) > -1 ||
                             searchWords[j].indexOf(val) > -1 ||
                             searchWords[j].replace(/_/g, "").indexOf(val) > -1)
                         {
                             // filter type: ... queries
                             if (typeFilter < 0 || typeFilter === searchIndex[j].ty) {
-                                results.push({id: j, index: searchWords[j].replace(/_/g, "").indexOf(val)});
+                                results.push({
+                                    id: j,
+                                    index: searchWords[j].replace(/_/g, "").indexOf(val),
+                                    lev: 0,
+                                });
+                            }
+                        } else if (
+                            (lev_distance = levenshtein(searchWords[j], val)) <= 
+                                MAX_LEV_DISTANCE) {
+                            if (typeFilter < 0 || typeFilter === searchIndex[j].ty) {
+                                results.push({
+                                    id: j,
+                                    index: 0,
+                                    // we want lev results to go lower than others
+                                    lev: lev_distance,
+                                });
                             }
                         }
                         if (results.length === max) {
             }
 
             var nresults = results.length;
-            for (var i = 0; i < nresults; i += 1) {
+            for (var i = 0; i < nresults; ++i) {
                 results[i].word = searchWords[results[i].id];
                 results[i].item = searchIndex[results[i].id] || {};
             }
             results.sort(function(aaa, bbb) {
                 var a, b;
 
+                // Sort by non levenshtein results and then levenshtein results by the distance
+                // (less changes required to match means higher rankings)
+                a = (aaa.lev);
+                b = (bbb.lev);
+                if (a !== b) return a - b;
+
                 // sort by crate (non-current crate goes later)
                 a = (aaa.item.crate !== window.currentCrate);
                 b = (bbb.item.crate !== window.currentCrate);
                     results[i].id = -1;
                 }
             }
-            for (var i = 0; i < results.length; i++) {
+            for (var i = 0; i < results.length; ++i) {
                 var result = results[i],
                     name = result.item.name.toLowerCase(),
                     path = result.item.path.toLowerCase(),
          * @return {[boolean]}       [Whether the result is valid or not]
          */
         function validateResult(name, path, keys, parent) {
-            //initially valid
-            var validate = true;
-            //if there is a parent, then validate against parent
-            if (parent !== undefined) {
-                for (var i = 0; i < keys.length; i++) {
-                    // if previous keys are valid and current key is in the
-                    // path, name or parent
-                    if ((validate) &&
-                        (name.toLowerCase().indexOf(keys[i]) > -1 ||
-                         path.toLowerCase().indexOf(keys[i]) > -1 ||
-                         parent.name.toLowerCase().indexOf(keys[i]) > -1))
-                    {
-                        validate = true;
-                    } else {
-                        validate = false;
-                    }
-                }
-            } else {
-                for (var i = 0; i < keys.length; i++) {
-                    // if previous keys are valid and current key is in the
-                    // path, name
-                    if ((validate) &&
-                        (name.toLowerCase().indexOf(keys[i]) > -1 ||
-                         path.toLowerCase().indexOf(keys[i]) > -1))
-                    {
-                        validate = true;
-                    } else {
-                        validate = false;
-                    }
+            for (var i=0; i < keys.length; ++i) {
+                // each check is for validation so we negate the conditions and invalidate
+                if (!( 
+                    // check for an exact name match
+                    name.toLowerCase().indexOf(keys[i]) > -1 ||
+                    // then an exact path match
+                    path.toLowerCase().indexOf(keys[i]) > -1 ||
+                    // next if there is a parent, check for exact parent match
+                    (parent !== undefined && 
+                        parent.name.toLowerCase().indexOf(keys[i]) > -1) ||
+                    // lastly check to see if the name was a levenshtein match
+                    levenshtein(name.toLowerCase(), keys[i]) <= 
+                        MAX_LEV_DISTANCE)) {
+                    return false;
                 }
             }
-            return validate;
+            return true;
         }
 
         function getQuery() {
                 }, 20);
             });
 
-            $(document).off('keypress.searchnav');
-            $(document).on('keypress.searchnav', function(e) {
+            $(document).off('keydown.searchnav');
+            $(document).on('keydown.searchnav', function(e) {
                 var $active = $results.filter('.highlighted');
 
-                if (e.keyCode === 38) { // up
+                if (e.which === 38) { // up
                     e.preventDefault();
                     if (!$active.length || !$active.prev()) {
                         return;
 
                     $active.prev().addClass('highlighted');
                     $active.removeClass('highlighted');
-                } else if (e.keyCode === 40) { // down
+                } else if (e.which === 40) { // down
                     e.preventDefault();
                     if (!$active.length) {
                         $results.first().addClass('highlighted');
                         $active.next().addClass('highlighted');
                         $active.removeClass('highlighted');
                     }
-                } else if (e.keyCode === 13) { // return
+                } else if (e.which === 13) { // return
                     e.preventDefault();
                     if ($active.length) {
                         document.location.href = $active.find('a').prop('href');
 
             resultIndex = execQuery(query, 20000, index);
             len = resultIndex.length;
-            for (i = 0; i < len; i += 1) {
+            for (i = 0; i < len; ++i) {
                 if (resultIndex[i].id > -1) {
                     obj = searchIndex[resultIndex[i].id];
                     filterdata.push([obj.name, obj.ty, obj.path, obj.desc]);
                          "variant",
                          "ffi",
                          "ffs",
-                         "macro"];
+                         "macro",
+                         "primitive"];
 
         function itemTypeFromName(typename) {
             for (var i = 0; i < itemTypes.length; ++i) {
                 // faster analysis operations
                 var len = items.length;
                 var lastPath = "";
-                for (var i = 0; i < len; i += 1) {
+                for (var i = 0; i < len; ++i) {
                     var rawRow = items[i];
                     var row = {crate: crate, ty: rawRow[0], name: rawRow[1],
                                path: rawRow[2] || lastPath, desc: rawRow[3],
                 crates.push(crate);
             }
             crates.sort();
-            for (var i = 0; i < crates.length; i++) {
+            for (var i = 0; i < crates.length; ++i) {
                 var klass = 'crate';
                 if (crates[i] == window.currentCrate) {
                     klass += ' current';
                 }
                 div.append($('<a>', {'href': '../' + crates[i] + '/index.html',
                                     'class': klass}).text(crates[i]));
-                div.append($('<br>'));
             }
             sidebar.append(div);
         }
     window.register_implementors = function(imp) {
         var list = $('#implementors-list');
         var libs = Object.getOwnPropertyNames(imp);
-        for (var i = 0; i < libs.length; i++) {
-            var structs = Object.getOwnPropertyNames(imp[libs[i]]);
-            for (var j = 0; j < structs.length; j++) {
-                console.log(i, structs[j]);
-                var path = rootPath + imp[libs[i]][structs[j]];
-                var klass = path.contains("type.") ? "type" : "struct";
-                var link = $('<a>').text(structs[j])
-                                   .attr('href', path)
-                                   .attr('class', klass);
-                var code = $('<code>').append(link);
+        for (var i = 0; i < libs.length; ++i) {
+            if (libs[i] == currentCrate) continue;
+            var structs = imp[libs[i]];
+            for (var j = 0; j < structs.length; ++j) {
+                var code = $('<code>').append(structs[j]);
+                $.each(code.find('a'), function(idx, a) {
+                    var href = $(a).attr('href');
+                    if (!href.startsWith('http')) {
+                        $(a).attr('href', rootPath + $(a).attr('href'));
+                    }
+                });
                 var li = $('<li>').append(code);
                 list.append(li);
             }
         window.register_implementors(window.pending_implementors);
     }
 
-    // See documentaiton in html/render.rs for what this is doing.
+    // See documentation in html/render.rs for what this is doing.
     var query = getQueryStringParams();
     if (query['gotosrc']) {
         window.location = $('#src-' + query['gotosrc']).attr('href');
     }
+
+    $("#expand-all").on("click", function() {
+        $(".docblock").show();
+        $(".toggle-label").hide();
+        $(".toggle-wrapper").removeClass("collapsed");
+        $(".collapse-toggle").children(".inner").html("-");
+    });
+
+    $("#collapse-all").on("click", function() {
+        $(".docblock").hide();
+        $(".toggle-label").show();
+        $(".toggle-wrapper").addClass("collapsed");
+        $(".collapse-toggle").children(".inner").html("+");
+    });
+
+    $(document).on("click", ".collapse-toggle", function() {
+        var toggle = $(this);
+        var relatedDoc = toggle.parent().next();
+        if (relatedDoc.is(".docblock")) {
+            if (relatedDoc.is(":visible")) {
+                relatedDoc.slideUp({duration:'fast', easing:'linear'});
+                toggle.parent(".toggle-wrapper").addClass("collapsed");
+                toggle.children(".inner").html("+");
+                toggle.children(".toggle-label").fadeIn();
+            } else {
+                relatedDoc.slideDown({duration:'fast', easing:'linear'});
+                toggle.parent(".toggle-wrapper").removeClass("collapsed");
+                toggle.children(".inner").html("-");
+                toggle.children(".toggle-label").hide();
+            }
+        }
+    });
+
+    $(function() {
+        var toggle = "<a href='javascript:void(0)'"
+            + "class='collapse-toggle'>[<span class='inner'>-</span>]</a>";
+
+        $(".method").each(function() {
+           if ($(this).next().is(".docblock")) {
+               $(this).children().first().after(toggle);
+           }
+        });
+
+        var mainToggle = $(toggle);
+        mainToggle.append("<span class='toggle-label' style='display:none'>"
+            + "&nbsp;Expand&nbsp;description</span></a>")
+        var wrapper =  $("<div class='toggle-wrapper'>");
+        wrapper.append(mainToggle);
+        $("#main > .docblock").before(wrapper);
+    });
+
 }());