From e4b8a771dfcca2b1dcee75529a06c833e876e389 Mon Sep 17 00:00:00 2001 From: Eli Barzilay Date: Wed, 4 Jun 2008 13:30:27 +0000 Subject: [PATCH] * C-S-Enter scrolls back * abstract html preference boilerplate code * added help blurbs on prefs * reorganize search code (better for adding tests in the future) * added some "test cases", basically queries to try * added pre-query that pre-filters the data svn: r10127 --- collects/scribblings/main/private/search.js | 215 +++++++++++++------- 1 file changed, 141 insertions(+), 74 deletions(-) diff --git a/collects/scribblings/main/private/search.js b/collects/scribblings/main/private/search.js index df32217505..f08f2b072b 100644 --- a/collects/scribblings/main/private/search.js +++ b/collects/scribblings/main/private/search.js @@ -1,21 +1,21 @@ // Globally visible bindings var key_handler, toggle_panel, hide_prefs, new_query, refine_query, - set_show_manuals, set_show_manual_titles, set_results_num, - set_type_delay, set_highlight_color; + set_pre_query, set_show_manuals, set_show_manual_titles, set_results_num, + set_type_delay, set_highlight_color, status_line, saved_status = false; (function(){ // Configuration options (use || in case a cookie exists but is empty) +var pre_query = GetCookie("PLT_PreQuery",""); var manual_settings = parseInt(GetCookie("PLT_ManualSettings",1)); var show_manuals = manual_settings % 10; var show_manual_titles = ((manual_settings - show_manuals) / 10) > 0; -var results_num = (parseInt(GetCookie("PLT_ResultsNum", false)) || 20); -var type_delay = (parseInt(GetCookie("PLT_TypeDelay", false)) || 300); -var highlight_color = (GetCookie("PLT_HighlightColor", false) || "#ffd"); +var results_num = (parseInt(GetCookie("PLT_ResultsNum",false)) || 20); +var type_delay = (parseInt(GetCookie("PLT_TypeDelay",false)) || 300); +var highlight_color = (GetCookie("PLT_HighlightColor",false) || "#ffd"); var background_color = "#f8f8f8"; -var query, status, results_container, result_links, - prev_page_link, next_page_link; +var query, results_container, result_links, prev_page_link, next_page_link; // tabIndex fields are set: // 1 query @@ -24,6 +24,21 @@ var query, status, results_container, result_links, // 4 pref widgets // -1 prev/next page (un-tab-able) +function MakePref(label, input) { + return '' + label + ':  ' + +'' + input + ''; +} +descriptions = new Array(); +function PrefInputArgs(name, desc) { + descriptions[name] = desc; + return 'tabIndex="4" id="'+name+'_pref"' + +' onkeypress="hide_prefs(event);"' + +' onchange="set_'+name+'(this); return true;"' + +' onfocus="saved_status=status_line.innerHTML;' + +'status_line.innerHTML=descriptions[\''+name+'\'];"' + +' onblur="if (saved_status) status_line.innerHTML=saved_status;"'; +} + function InitializeSearch() { var n; n = document.getElementById("plt_search_container").parentNode; @@ -79,40 +94,47 @@ function InitializeSearch() { +' style="display: none; border: 1px solid #222; border-top: 0px;' +' font-family: arial, sans-serif; margin: 0em 0em 1em 0em;' +' padding: 0.5em; background-color: #f0f0f0;">' - +'' - +'' + +'' + +' use titles') + + MakePref('Results per page', + '') + + MakePref('Type delay', + '') + + MakePref('Exact matches color', + '') + + MakePref('Pre-Query', + 'M:” to" + +" search only bindings, “T:reference”" + +" to search only the reference manual") + +'>') + +'
' - +'Show manuals:' - +'' - +' ' + + MakePref('Show manuals', + '' - +' ' - +' use titles
' - +'
' - +'Results per page:' - +'' - +'
' - +'
' - +'Type delay:' - +'' - +'
' - +'
' - +'Exact matches color:' - +'' - +'
' - +'
' +'' +''; // get the widgets we use query = document.getElementById("search_box"); - status = document.getElementById("search_status"); + status_line = document.getElementById("search_status"); prev_page_link = document.getElementById("prev_page_link"); next_page_link = document.getElementById("next_page_link"); // result_links is the array of result link pairs @@ -145,6 +167,7 @@ function InitializeSearch() { results_container.normalize(); result_links.push(n); AdjustResultsNum(); + PreFilter(); // get search string if (location.search.length > 0) { var paramstrs = location.search.substring(1).split(/[;&]/); @@ -195,6 +218,11 @@ function MaxCompares(pat, strs) { return r; } +function NormalizeSpaces(str) { + return str.replace(/\s\s*/g," ") // single spaces + replace(/^\s/g,"").replace(/\s$/g,""); // trim edge spaces +} + function UrlToManual(url) { return url.replace(/#.*$/, "") // remove fragment, .replace(/\?.*$/, "") // query, @@ -202,6 +230,12 @@ function UrlToManual(url) { .replace(/^(.*\/|>)/, ""); // and directory. } +// Tests for matches and highlights: +// "append" +// "L:scheme append" +// "L:scheme" (no exact matches except for the `scheme' module) +// "L:schem" (only module names that match `schem') + function CompileTerm(term) { var flag = ((term.search(/^[LMT]:/)==0) && term.substring(0,1)); if (flag) term = term.substring(2); @@ -209,12 +243,13 @@ function CompileTerm(term) { switch(flag) { case "L": return function(x) { if (!x[3]) return C_fail; - if (x[3] == "module") return Compare(term,x[0]); // rexact allowed! + if (x[3] == "module") // rexact allowed, show partial module matches + return Compare(term,x[0]); return (MaxCompares(term,x[3]) >= C_exact) ? C_exact : C_fail; } case "M": return function(x) { if (!x[3]) return C_fail; - if (x[3] == "module") return Compare(term,x[0]); // rexact allowed! + if (x[3] == "module") return Compare(term,x[0]); // rexact allowed return (MaxCompares(term,x[3]) >= C_match) ? C_exact : C_fail; } case "T": return function(x) { @@ -232,37 +267,45 @@ function CompileTerm(term) { } } +function Search(data, term, is_pre) { + var preds = (term=="") ? [] : term.split(/ /); + for (var i=0; i= C_rexact && min >= C_exact) exacts.push(data[i]); + else if (min > C_fail) matches.push(data[i]); + } + exact_results_num = exacts.length; + if (exacts.length > 0) return exacts.concat(matches); + else return matches; +} + +var search_data; // pre-filtered searchable index data +function PreFilter() { + pre_query = NormalizeSpaces(pre_query); + search_data = Search(plt_search_data, pre_query, true); + last_search_term = null; + last_search_term_raw = null; +} + var last_search_term, last_search_term_raw; var search_results = [], first_search_result, exact_results_num; function DoSearch() { var term = query.value; if (term == last_search_term_raw) return; last_search_term_raw = term; - term = term.replace(/\s\s*/g," ") // single spaces - .replace(/^\s/g,"").replace(/\s$/g,""); // trim edge spaces + term = NormalizeSpaces(term); if (term == last_search_term) return; last_search_term = term; - status.innerHTML = "Searching " + plt_search_data.length + " entries"; - var terms = (term=="") ? [] : term.split(/ /); - for (var i=0; i= C_rexact) exact_results.push(plt_search_data[i]); - else if (r > C_fail) search_results.push(plt_search_data[i]); - } - exact_results_num = exact_results.length; - if (exact_results.length > 0) - search_results = exact_results.concat(search_results); - } + status_line.innerHTML = "Searching " + search_data.length + " entries"; + search_results = Search(search_data, term, false); first_search_result = 0; - status.innerHTML = "" + search_results.length + " entries found"; + status_line.innerHTML = "" + search_results.length + " entries found"; query.style.backgroundColor = ((search_results.length == 0) && (term != "")) ? "#ffe0e0" : "white"; UpdateResults(); @@ -319,7 +362,7 @@ function UpdateResults() { +' onclick="return new_query(this);"' +' oncontextmenu="return refine_query(this);">' + ((typeof idx == "number") - ? (''+UncompactHtml(plt_search_data[idx][2])+'') + ? (''+UncompactHtml(search_data[idx][2])+'') : manual) + ''; } @@ -343,22 +386,23 @@ function UpdateResults() { + ((exact == results_num) ? 'all' : exact) + ' exact)'; if (search_results.length == 0) - status.innerHTML = ((last_search_term=="") ? "" : "No matches found"); + status_line.innerHTML = ((last_search_term=="") ? "" : "No matches found"); else if (search_results.length <= results_num) - status.innerHTML = "Showing all matches" + exact; + status_line.innerHTML = "Showing all matches" + exact; else - status.innerHTML = + status_line.innerHTML = "Showing " + (first_search_result+1) + "-" + Math.min(first_search_result+results_num,search_results.length) + exact + " of " + search_results.length - + ((search_results.length==plt_search_data.length) ? "" : " matches"); + + ((search_results.length==search_data.length) ? "" : " matches"); prev_page_link.style.color = (first_search_result-results_num >= 0) ? "black" : "#e0e0e0"; next_page_link.style.color = (first_search_result+results_num < search_results.length) ? "black" : "#e0e0e0"; + saved_status = false; } var search_timer = null; @@ -372,15 +416,18 @@ function HandleKeyEvent(event) { if (typeof event == "string") key = event; else if (event) { switch (event.which || event.keyCode) { - case 13: if (event.ctrlKey) key = "Enter"; break; + case 13: if (event.ctrlKey) key = "C-Enter"; + break; case 33: key = "PgUp"; break; case 34: key = "PgDn"; break; } } switch (key) { - case "Enter": // enter with no change scrolls + case "C-Enter": // C-enter with no change scrolls down (S -> up) if (query.value == last_search_term_raw) { - first_search_result += results_num; + if (!event.shiftKey) first_search_result += results_num; + else if (first_search_result > 0) first_search_result -= results_num; + else first_search_result = search_results.length - results_num; UpdateResults(); } else { DoSearch(); @@ -442,12 +489,12 @@ function TogglePanel(name) { document.getElementById(panel_shown+"_panel").style.display = "none"; panel_shown = ((panel_shown != name) && name); if (panel_shown == "prefs") { - document.getElementById("show_manuals_pref").selectedIndex - = show_manuals; + document.getElementById("pre_query_pref").value = pre_query; + document.getElementById("show_manuals_pref").selectedIndex = show_manuals; document.getElementById("show_manual_titles_pref").checked = show_manual_titles; - document.getElementById("results_num_pref").value = results_num; - document.getElementById("type_delay_pref").value = type_delay; + document.getElementById("results_num_pref").value = results_num; + document.getElementById("type_delay_pref").value = type_delay; document.getElementById("highlight_color_pref").value = highlight_color; } if (panel_shown) @@ -463,6 +510,26 @@ function HidePrefs(event) { } hide_prefs = HidePrefs; +function SetShowManuals(inp) { + if (inp.selectedIndex != show_manuals) { + show_manuals = inp.selectedIndex; + SetCookie("PLT_ManualSettings", show_manuals+(show_manual_titles?10:0)); + UpdateResults(); + } +} +set_show_manuals = SetShowManuals; + +function SetPreQuery(inp) { + if (inp.value != pre_query) { + pre_query = inp.value; + SetCookie("PLT_PreQuery", pre_query); + PreFilter(); + DoSearch(); + } +} +set_pre_query = SetPreQuery; + + function SetShowManuals(inp) { if (inp.selectedIndex != show_manuals) { show_manuals = inp.selectedIndex;