diff --git a/collects/scribblings/main/private/make-search.ss b/collects/scribblings/main/private/make-search.ss
index 4e02559ab1..8955ce609d 100644
--- a/collects/scribblings/main/private/make-search.ss
+++ b/collects/scribblings/main/private/make-search.ss
@@ -81,7 +81,7 @@
[e (if (method-index-desc? desc)
`(,@e ,(make-element "smaller"
`(" (method of "
- ,(make-element "schemevariable"
+ ,(make-element "schemevaluelink"
(list (symbol->string
(exported-index-desc-name desc))))
")")))
diff --git a/collects/scribblings/main/private/search.js b/collects/scribblings/main/private/search.js
new file mode 100644
index 0000000000..8d5cb37702
--- /dev/null
+++ b/collects/scribblings/main/private/search.js
@@ -0,0 +1,516 @@
+// 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;
+
+(function(){
+
+// Configuration options (use || in case a cookie exists but is empty)
+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 background_color = "#f8f8f8";
+
+var query, status, results_container, result_links,
+ prev_page_link, next_page_link;
+
+// tabIndex fields are set:
+// 1 query
+// 2 index links
+// 3 help/pref toggle
+// 4 pref widgets
+// -1 prev/next page (un-tab-able)
+
+function InitializeSearch() {
+ var n;
+ n = document.getElementById("plt_search_container").parentNode;
+ // hack the table in
+ n.innerHTML = ''
+ +'
';
+ // get the widgets we use
+ query = document.getElementById("search_box");
+ status = 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
+ result_links = new Array();
+ n = document.getElementById("search_result");
+ results_container = n.parentNode;
+ results_container.normalize();
+ result_links.push(n);
+ AdjustResultsNum();
+ // get search string
+ if (location.search.length > 0) {
+ var paramstrs = location.search.substring(1).split(/[;&]/);
+ for (var i=0; i results_num)
+ results_container.removeChild(result_links.pop());
+ while (result_links.length < results_num) {
+ var n = result_links[0].cloneNode(true);
+ result_links.push(n);
+ results_container.appendChild(n);
+ }
+}
+
+// constants for Compare(() results;
+// `rexact' is for an actual exact match, so we know that we matched
+// *something* and can show exact matches as such, in other words:
+// - < exact => this match is inexact
+// - = exact => does not affect the exactness of this match
+// - > exact => this is an exact match as far as this predicate goes
+var C_fail = 0, C_match = 1, C_prefix = 2, C_exact = 3, C_rexact = 4;
+
+function Compare(pat, str) {
+ var i = str.indexOf(pat);
+ if (i < 0) return C_fail;
+ else if (i > 0) return C_match;
+ else if (pat.length == str.length) return C_rexact;
+ else return C_prefix;
+}
+function MaxCompares(pat, strs) {
+ var r = C_fail;
+ for (var i=0; i)/, "");
+}
+
+function CompileTerm(term) {
+ var flag = ((term.search(/^[LMT]:/)==0) && term.substring(0,1));
+ if (flag) term = term.substring(2);
+ term = term.toLowerCase();
+ switch(flag) {
+ case "L": return function(x) {
+ if (!x[3]) return C_fail;
+ if (x[3] == "module") return Compare(term,x[0]); // rexact allowed!
+ 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!
+ return (MaxCompares(term,x[3]) >= C_match) ? C_exact : C_fail;
+ }
+ case "T": return function(x) {
+ if (Compare(term,UrlToManual(x[1])) < C_exact) return C_fail;
+ else if (x[1].search(/\/index\.html$/) > 0) return C_rexact;
+ else return C_exact;
+ }
+ default: return function(x) {
+ switch (Compare(term,x[0])) {
+ case C_fail: return C_fail;
+ case C_match: case C_prefix: return C_match;
+ case C_exact: case C_rexact: return (x[3] ? C_rexact : C_match);
+ }
+ }
+ }
+}
+
+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
+ 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);
+ }
+ first_search_result = 0;
+ status.innerHTML = "" + search_results.length + " entries found";
+ query.style.backgroundColor =
+ ((search_results.length == 0) && (term != "")) ? "#ffe0e0" : "white";
+ UpdateResults();
+}
+
+function UncompactUrl(url) {
+ return url.replace(/^>/, plt_main_url);
+}
+
+function UncompactHtml(x) {
+ if (typeof x == "string") {
+ return x;
+ } else if (! (x instanceof Array)) {
+ alert("Internal error in PLT docs");
+ } else if ((x.length == 2) && (typeof(x[0]) == "number")) {
+ return '' + UncompactHtml(x[1]) + '';
+ } else {
+ var s = "";
+ for (var i=0; i= search_results.length)
+ first_search_result = 0;
+ for (var i=0; i 0)) {
+ note = 'provided from ';
+ for (var j=0; j'
+ + desc[j] + '';
+ } else if (desc == "module") {
+ note = 'module';
+ }
+ if (show_manuals == 2 || (show_manuals == 1 && !desc)) {
+ var manual = UrlToManual(res[1]),
+ idx = (show_manual_titles && plt_manual_ptrs[manual]);
+ note = (note ? (note + " ") : "");
+ note += 'in '
+ + ''
+ + ((typeof idx == "number")
+ ? (''+UncompactHtml(plt_search_data[idx][2])+'')
+ : manual)
+ + '';
+ }
+ if (note)
+ note = ' ' + note + '';
+ result_links[i].innerHTML =
+ ''
+ + UncompactHtml(res[2]) + '' + (note || "");
+ result_links[i].style.backgroundColor =
+ (n < exact_results_num) ? highlight_color : background_color;
+ result_links[i].style.display = "block";
+ } else {
+ result_links[i].style.display = "none";
+ }
+ }
+ var exact = Math.min((exact_results_num - first_search_result),
+ results_num);
+ exact = (exact <= 0) ? ''
+ : ' ('
+ + ((exact == results_num) ? 'all' : exact)
+ + ' exact)';
+ if (search_results.length == 0)
+ status.innerHTML = ((last_search_term=="") ? "" : "No matches found");
+ else if (search_results.length <= results_num)
+ status.innerHTML = "Showing all matches" + exact;
+ else
+ status.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");
+ 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";
+}
+
+var search_timer = null;
+function HandleKeyEvent(event) {
+ if (search_timer != null) {
+ var t = search_timer;
+ search_timer = null;
+ clearTimeout(t);
+ }
+ var key = null;
+ if (typeof event == "string") key = event;
+ else if (event) {
+ switch (event.which || event.keyCode) {
+ case 13: key = "Enter"; break;
+ case 33: key = "PgUp"; break;
+ case 34: key = "PgDn"; break;
+ }
+ }
+ switch (key) {
+ case "Enter": // enter with no change scrolls
+ if (query.value == last_search_term_raw) {
+ first_search_result += results_num;
+ UpdateResults();
+ } else {
+ DoSearch();
+ }
+ return false;
+ case "PgUp":
+ DoSearch(); // in case we didn't update it yet
+ first_search_result -= results_num;
+ UpdateResults();
+ return false;
+ case "PgDn":
+ DoSearch(); // in case we didn't update it yet
+ if (first_search_result + results_num < search_results.length) {
+ first_search_result += results_num;
+ UpdateResults();
+ }
+ return false;
+ }
+ search_timer = setTimeout(DoSearch, type_delay);
+ return true;
+}
+key_handler = HandleKeyEvent;
+
+// use this one to set the query field without jumping to the current
+// url again, since some browsers will reload the whole page for that
+// (it would be nice if there was a way to add it to the history too)
+function NewQuery(node) {
+ var m = node.href.search(/[?]q=[^?&;]+$/);
+ if (m < 0) return true;
+ else {
+ query.value = decodeURIComponent(node.href.substring(m+3));
+ query.focus();
+ DoSearch();
+ return false;
+ }
+}
+new_query = NewQuery;
+
+// and this appends the the query to the current value (it's hooked
+// on the oncontextmenu handler that doesn't work everywhere, but at
+// least in FF and IE)
+function RefineQuery(node) {
+ var m = node.href.search(/[?]q=[^?&;]+$/);
+ if (m < 0) return true;
+ m = decodeURIComponent(node.href.substring(m+3));
+ if (query.value.indexOf(m) >= 0) return true;
+ else {
+ query.value = m + " " + query.value;
+ query.focus();
+ DoSearch();
+ return false;
+ }
+}
+refine_query = RefineQuery;
+
+var panel_shown = false;
+function TogglePanel(name) {
+ if (panel_shown)
+ 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("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("highlight_color_pref").value = highlight_color;
+ }
+ if (panel_shown)
+ document.getElementById(panel_shown+"_panel").style.display = "block";
+}
+toggle_panel = TogglePanel;
+
+function HidePrefs(event) {
+ if ((event.which || event.keyCode) == 27) {
+ query.focus();
+ TogglePanel("prefs"); // this function is called only when it's shown
+ }
+}
+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 SetShowManualTitles(inp) {
+ if (inp.checked != show_manual_titles) {
+ show_manual_titles = inp.checked;
+ SetCookie("PLT_ManualSettings", show_manuals+(show_manual_titles?10:0));
+ UpdateResults();
+ }
+}
+set_show_manual_titles = SetShowManualTitles;
+
+function SetResultsNum(inp) {
+ var n = (parseInt(inp.value.replace(/[^0-9]+/g,"")) || results_num);
+ inp.value = n;
+ if (n != results_num) {
+ results_num = n;
+ SetCookie("PLT_ResultsNum", results_num);
+ AdjustResultsNum();
+ UpdateResults();
+ }
+}
+set_results_num = SetResultsNum;
+
+function SetTypeDelay(inp) {
+ var n = (parseInt(inp.value.replace(/[^0-9]+/g,"")) || type_delay);
+ inp.value = n;
+ if (n != type_delay) {
+ type_delay = n;
+ SetCookie("PLT_TypeDelay", type_delay);
+ }
+}
+set_type_delay = SetTypeDelay;
+
+function SetHighlightColor(inp) {
+ var c = (inp.value.replace(/[^a-zA-Z0-9#]/g,"") || highlight_color);
+ inp.value = c;
+ if (c != highlight_color) {
+ highlight_color = c;
+ SetCookie("PLT_HighlightColor", highlight_color);
+ UpdateResults();
+ }
+}
+set_highlight_color = SetHighlightColor;
+
+window.onload = InitializeSearch;
+
+})();