uni

Thing1's amazing uni repo
Log | Files | Refs | Submodules

search-page.js (12825B)


      1 /*
      2  * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved.
      3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      4  *
      5  * Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
      6  */
      7 
      8 "use strict";
      9 $(function() {
     10     var copy = $("#page-search-copy");
     11     var expand = $("#page-search-expand");
     12     var searchLink = $("span#page-search-link");
     13     var redirect = $("input#search-redirect");
     14     function setSearchUrlTemplate() {
     15         var href = document.location.href.split(/[#?]/)[0];
     16         href += "?q=" + "%s";
     17         if (redirect.is(":checked")) {
     18             href += "&r=1";
     19         }
     20         searchLink.html(href);
     21         copy[0].onmouseenter();
     22     }
     23     function copyLink(e) {
     24         copyToClipboard(this.previousSibling.innerText);
     25         switchCopyLabel(this, this.lastElementChild);
     26     }
     27     copy.on("click", copyLink);
     28     copy[0].onmouseenter = function() {};
     29     redirect.on("click", setSearchUrlTemplate);
     30     setSearchUrlTemplate();
     31     copy.prop("disabled", false);
     32     redirect.prop("disabled", false);
     33     expand.on("click", function (e) {
     34         var searchInfo = $("div.page-search-info");
     35         if(this.parentElement.hasAttribute("open")) {
     36             searchInfo.attr("style", " display:none;");
     37         } else {
     38             searchInfo.attr("style", "display:block;");
     39         }
     40     });
     41 });
     42 $(window).on("load", function() {
     43     var input = $("#page-search-input");
     44     var reset = $("#page-search-reset");
     45     var modules = $("#search-modules");
     46     var notify = $("#page-search-notify");
     47     var resultSection = $("div#result-section");
     48     var resultContainer = $("div#result-container");
     49     var selectedLink;
     50     var searchTerm = "";
     51     var activeTab = "";
     52     var fixedTab = false;
     53     var visibleTabs = [];
     54     var feelingLucky = false;
     55     const MIN_TABBED_RESULTS = 10;
     56     function renderResults(result) {
     57         if (!result.length) {
     58             notify.html(messages.noResult);
     59         } else if (result.length === 1) {
     60             notify.html(messages.oneResult);
     61         } else {
     62             notify.html(messages.manyResults.replace("{0}", result.length));
     63         }
     64         resultContainer.empty();
     65         var r = {
     66             "types": [],
     67             "members": [],
     68             "packages": [],
     69             "modules": [],
     70             "searchTags": []
     71         };
     72         for (var i in result) {
     73             var item = result[i];
     74             var arr = r[item.category];
     75             arr.push(item);
     76         }
     77         if (!activeTab || r[activeTab].length === 0) {
     78             activeTab = Object.keys(r).find(category => r[category].length > 0);
     79         }
     80         if (feelingLucky && activeTab) {
     81             notify.html(messages.redirecting)
     82             var firstItem = r[activeTab][0];
     83             window.location = getURL(firstItem.indexItem, firstItem.category);
     84             return;
     85         }
     86         if (searchTerm.endsWith(".") && result.length > MIN_TABBED_RESULTS) {
     87             if (activeTab === "types" && r["members"].length > r["types"].length) {
     88                 activeTab = "members";
     89             } else if (activeTab === "packages" && r["types"].length > r["packages"].length) {
     90                 activeTab = "types";
     91             }
     92         }
     93         var categoryCount = Object.keys(r).reduce(function(prev, curr) {
     94             return prev + (r[curr].length > 0 ? 1 : 0);
     95         }, 0);
     96         visibleTabs = [];
     97         var tabContainer = $("<div class='table-tabs'></div>").appendTo(resultContainer);
     98         for (var key in r) {
     99             var id = "#result-tab-" + key.replace("searchTags", "search_tags");
    100             if (r[key].length) {
    101                 var count = r[key].length >= 1000 ? "999+" : r[key].length;
    102                 if (result.length > MIN_TABBED_RESULTS && categoryCount > 1) {
    103                     let button = $("<button/>")
    104                         .attr("id", "result-tab-" + key)
    105                         .attr("tabIndex", "-1")
    106                         .addClass("page-search-header")
    107                         .append($("<span/>")
    108                             .html(categories[key])
    109                             .append($("<span/>")
    110                                 .attr("style", "font-weight:normal;")
    111                                 .html(" (" + count + ")")))
    112                         .on("click", null, key, function(e) {
    113                             fixedTab = true;
    114                             renderResult(e.data, $(this));
    115                         }).appendTo(tabContainer);
    116                     visibleTabs.push(key);
    117                 } else {
    118                     $("<span class='page-search-header'>" + categories[key]
    119                         + "<span style='font-weight: normal'> (" + count + ")</span></span>").appendTo(tabContainer);
    120                     renderTable(key, r[key]).appendTo(resultContainer);
    121                     tabContainer = $("<div class='table-tabs'></div>").appendTo(resultContainer);
    122                 }
    123             }
    124         }
    125         if (activeTab && result.length > MIN_TABBED_RESULTS && categoryCount > 1) {
    126             $("button#result-tab-" + activeTab).addClass("active-table-tab").attr("tabIndex", "0");
    127             renderTable(activeTab, r[activeTab]).appendTo(resultContainer);
    128         }
    129         resultSection.show();
    130         function renderResult(category, button) {
    131             activeTab = category;
    132             setSearchUrl();
    133             resultContainer.find("div.result-table").remove();
    134             renderTable(activeTab, r[activeTab]).appendTo(resultContainer);
    135             button.siblings().removeClass("active-table-tab").attr("tabIndex", "-1");
    136             button.addClass("active-table-tab").attr("tabIndex", "0");
    137         }
    138     }
    139     function selectTab(category) {
    140         $("button#result-tab-" + category).focus().trigger("click");
    141     }
    142     function renderTable(category, items) {
    143         var table = $("<div class='result-table'>");
    144         var col1, col2;
    145         if (category === "modules") {
    146             col1 = mdlDesc;
    147         } else if (category === "packages") {
    148             col1 = pkgDesc;
    149         } else if (category === "types") {
    150             col1 = clsDesc;
    151         } else if (category === "members") {
    152             col1 = mbrDesc;
    153         } else if (category === "searchTags") {
    154             col1 = tagDesc;
    155         }
    156         col2 = descDesc;
    157         $("<div class='table-header'/>")
    158             .append($("<span class='table-header'/>").html(col1))
    159             .append($("<span class='table-header'/>").html(col2))
    160             .appendTo(table);
    161         $.each(items, function(index, item) {
    162             renderItem(item, table);
    163         });
    164         return table;
    165     }
    166     function select() {
    167         if (!this.classList.contains("selected")) {
    168             setSelected(this);
    169         }
    170     }
    171     function unselect() {
    172         if (this.classList.contains("selected")) {
    173             setSelected(null);
    174         }
    175     }
    176     function renderItem(item, table) {
    177         var label = getResultLabel(item);
    178         var desc = getResultDescription(item);
    179         var link = $("<a/>")
    180             .attr("href",  getURL(item.indexItem, item.category))
    181             .attr("tabindex", "0")
    182             .addClass("search-result-link");
    183         link.on("mousemove", select.bind(link[0]))
    184             .on("focus", select.bind(link[0]))
    185             .on("mouseleave", unselect.bind(link[0]))
    186             .on("blur", unselect.bind(link[0]))
    187             .append($("<span/>").addClass("search-result-label").html(label))
    188             .append($("<span/>").addClass("search-result-desc").html(desc))
    189             .appendTo(table);
    190     }
    191     var timeout;
    192     function schedulePageSearch() {
    193         if (timeout) {
    194             clearTimeout(timeout);
    195         }
    196         timeout = setTimeout(function () {
    197             doPageSearch()
    198         }, 100);
    199     }
    200     function doPageSearch() {
    201         setSearchUrl();
    202         var term = searchTerm = input.val().trim();
    203         if (term === "") {
    204             notify.html(messages.enterTerm);
    205             activeTab = "";
    206             fixedTab = false;
    207             resultContainer.empty();
    208             resultSection.hide();
    209         } else {
    210             notify.html(messages.searching);
    211             var module = modules.val();
    212             doSearch({ term: term, maxResults: 1200, module: module}, renderResults);
    213         }
    214     }
    215     function setSearchUrl() {
    216         var query = input.val().trim();
    217         var url = document.location.pathname;
    218         if (query) {
    219             url += "?q=" + encodeURI(query);
    220             if (activeTab && fixedTab) {
    221                 url += "&c=" + activeTab;
    222             }
    223             if (modules.val()) {
    224                 url += "&m=" + modules.val();
    225             }
    226         }
    227         history.replaceState({query: query}, "", url);
    228     }
    229     input.on("input", function(e) {
    230         feelingLucky = false;
    231         reset.css("visibility", input.val() ? "visible" : "hidden");
    232         schedulePageSearch();
    233     });
    234     function setSelected(link) {
    235         if (selectedLink) {
    236             selectedLink.classList.remove("selected");
    237             selectedLink.blur();
    238         }
    239         if (link) {
    240             link.classList.add("selected");
    241             link.focus({focusVisible: true});
    242         }
    243         selectedLink = link;
    244     }
    245     document.addEventListener("keydown", e => {
    246         if (e.ctrlKey || e.altKey || e.metaKey) {
    247             return;
    248         }
    249         if (e.key === "Escape" && input.val()) {
    250             input.val("").focus();
    251             doPageSearch();
    252             e.preventDefault();
    253         }
    254         if (e.target === modules[0]) {
    255             return;
    256         }
    257         if (e.key === "ArrowLeft" || e.key === "ArrowRight") {
    258             if (activeTab && visibleTabs.length > 1 && e.target !== input[0]) {
    259                 var tab = visibleTabs.indexOf(activeTab);
    260                 var newTab = e.key === "ArrowLeft"
    261                     ? Math.max(0, tab - 1)
    262                     : Math.min(visibleTabs.length - 1, tab + 1);
    263                 if (newTab !== tab) {
    264                     selectTab(visibleTabs[newTab]);
    265                 }
    266                 e.preventDefault();
    267             }
    268         } else if (e.key === "ArrowUp" || e.key === "ArrowDown") {
    269             let links = Array.from(
    270                 document.querySelectorAll("div.result-table > a.search-result-link"));
    271             let current = links.indexOf(selectedLink);
    272             let activeButton = document.querySelector("button.active-table-tab");
    273             if (e.key === "ArrowUp" || (e.key === "Tab" && e.shiftKey)) {
    274                 if (current > 0) {
    275                     setSelected(links[current - 1]);
    276                 } else {
    277                     setSelected(null);
    278                     if (activeButton && current === 0) {
    279                         activeButton.focus();
    280                     } else {
    281                         input.focus();
    282                     }
    283                 }
    284             } else if (e.key === "ArrowDown") {
    285                 if (document.activeElement === input[0] && activeButton) {
    286                     activeButton.focus();
    287                 } else if (current < links.length - 1) {
    288                     setSelected(links[current + 1]);
    289                 }
    290             }
    291             e.preventDefault();
    292         } else if (e.key.length === 1 || e.key === "Backspace") {
    293             setSelected(null);
    294             input.focus();
    295         }
    296     });
    297     reset.on("click", function() {
    298         notify.html(messages.enterTerm);
    299         resultSection.hide();
    300         activeTab = "";
    301         fixedTab = false;
    302         resultContainer.empty();
    303         input.val('').focus();
    304         setSearchUrl();
    305     });
    306     modules.on("change", function() {
    307         if (input.val()) {
    308             doPageSearch();
    309         }
    310         input.focus();
    311         try {
    312             localStorage.setItem("search-modules", modules.val());
    313         } catch (unsupported) {}
    314     });
    315 
    316     input.prop("disabled", false);
    317     input.attr("autocapitalize", "off");
    318     reset.prop("disabled", false);
    319 
    320     var urlParams = new URLSearchParams(window.location.search);
    321     if (urlParams.has("m")) {
    322         modules.val(urlParams.get("m"));
    323     } else {
    324         try {
    325             var searchModules = localStorage.getItem("search-modules");
    326             if (searchModules) {
    327                 modules.val(searchModules);
    328             }
    329         } catch (unsupported) {}
    330     }
    331     if (urlParams.has("q")) {
    332         input.val(urlParams.get("q"));
    333         reset.css("visibility", input.val() ? "visible" : "hidden");
    334     }
    335     if (urlParams.has("c")) {
    336         activeTab = urlParams.get("c");
    337         fixedTab = true;
    338     }
    339     if (urlParams.get("r")) {
    340         feelingLucky = true;
    341     }
    342     if (input.val()) {
    343         doPageSearch();
    344     } else {
    345         notify.html(messages.enterTerm);
    346     }
    347     input.select().focus();
    348 });