| var gSelectedIndex = -1; |
| var gSelectedID = -1; |
| var gMatches = new Array(); |
| var gLastText = ""; |
| var ROW_COUNT = 20; |
| var gInitialized = false; |
| var DEFAULT_TEXT = "search developer docs"; |
| |
| function set_row_selected(row, selected) |
| { |
| var c1 = row.cells[0]; |
| // var c2 = row.cells[1]; |
| if (selected) { |
| c1.className = "jd-autocomplete jd-selected"; |
| // c2.className = "jd-autocomplete jd-selected jd-linktype"; |
| } else { |
| c1.className = "jd-autocomplete"; |
| // c2.className = "jd-autocomplete jd-linktype"; |
| } |
| } |
| |
| function set_row_values(toroot, row, match) |
| { |
| var link = row.cells[0].childNodes[0]; |
| link.innerHTML = match.__hilabel || match.label; |
| link.href = toroot + match.link |
| // row.cells[1].innerHTML = match.type; |
| } |
| |
| function sync_selection_table(toroot) |
| { |
| var filtered = document.getElementById("search_filtered"); |
| var r; //TR DOM object |
| var i; //TR iterator |
| gSelectedID = -1; |
| |
| filtered.onmouseover = function() { |
| if(gSelectedIndex >= 0) { |
| set_row_selected(this.rows[gSelectedIndex], false); |
| gSelectedIndex = -1; |
| } |
| } |
| |
| //initialize the table; draw it for the first time (but not visible). |
| if (!gInitialized) { |
| for (i=0; i<ROW_COUNT; i++) { |
| var r = filtered.insertRow(-1); |
| var c1 = r.insertCell(-1); |
| // var c2 = r.insertCell(-1); |
| c1.className = "jd-autocomplete"; |
| // c2.className = "jd-autocomplete jd-linktype"; |
| var link = document.createElement("a"); |
| c1.onmousedown = function() { |
| window.location = this.firstChild.getAttribute("href"); |
| } |
| c1.onmouseover = function() { |
| this.className = this.className + " jd-selected"; |
| } |
| c1.onmouseout = function() { |
| this.className = "jd-autocomplete"; |
| } |
| c1.appendChild(link); |
| } |
| /* var r = filtered.insertRow(-1); |
| var c1 = r.insertCell(-1); |
| c1.className = "jd-autocomplete jd-linktype"; |
| c1.colSpan = 2; */ |
| gInitialized = true; |
| } |
| |
| //if we have results, make the table visible and initialize result info |
| if (gMatches.length > 0) { |
| document.getElementById("search_filtered_div").className = "showing"; |
| var N = gMatches.length < ROW_COUNT ? gMatches.length : ROW_COUNT; |
| for (i=0; i<N; i++) { |
| r = filtered.rows[i]; |
| r.className = "show-row"; |
| set_row_values(toroot, r, gMatches[i]); |
| set_row_selected(r, i == gSelectedIndex); |
| if (i == gSelectedIndex) { |
| gSelectedID = gMatches[i].id; |
| } |
| } |
| //start hiding rows that are no longer matches |
| for (; i<ROW_COUNT; i++) { |
| r = filtered.rows[i]; |
| r.className = "no-display"; |
| } |
| //if there are more results we're not showing, so say so. |
| /* if (gMatches.length > ROW_COUNT) { |
| r = filtered.rows[ROW_COUNT]; |
| r.className = "show-row"; |
| c1 = r.cells[0]; |
| c1.innerHTML = "plus " + (gMatches.length-ROW_COUNT) + " more"; |
| } else { |
| filtered.rows[ROW_COUNT].className = "hide-row"; |
| }*/ |
| //if we have no results, hide the table |
| } else { |
| document.getElementById("search_filtered_div").className = "no-display"; |
| } |
| } |
| |
| function search_changed(e, kd, toroot) |
| { |
| var search = document.getElementById("search_autocomplete"); |
| var text = search.value.replace(/(^ +)|( +$)/g, ''); |
| |
| // 13 = enter |
| if (e.keyCode == 13) { |
| document.getElementById("search_filtered_div").className = "no-display"; |
| if (kd && gSelectedIndex >= 0) { |
| window.location = toroot + gMatches[gSelectedIndex].link; |
| return false; |
| } else if (gSelectedIndex < 0) { |
| return true; |
| } |
| } |
| // 38 -- arrow up |
| else if (kd && (e.keyCode == 38)) { |
| if (gSelectedIndex >= 0) { |
| gSelectedIndex--; |
| } |
| sync_selection_table(toroot); |
| return false; |
| } |
| // 40 -- arrow down |
| else if (kd && (e.keyCode == 40)) { |
| if (gSelectedIndex < gMatches.length-1 |
| && gSelectedIndex < ROW_COUNT-1) { |
| gSelectedIndex++; |
| } |
| sync_selection_table(toroot); |
| return false; |
| } |
| else if (!kd) { |
| gMatches = new Array(); |
| matchedCount = 0; |
| gSelectedIndex = -1; |
| for (var i=0; i<DATA.length; i++) { |
| var s = DATA[i]; |
| if (text.length != 0 && |
| s.label.toLowerCase().indexOf(text.toLowerCase()) != -1) { |
| gMatches[matchedCount] = s; |
| matchedCount++; |
| } |
| } |
| rank_autocomplete_results(text); |
| for (var i=0; i<gMatches.length; i++) { |
| var s = gMatches[i]; |
| if (gSelectedID == s.id) { |
| gSelectedIndex = i; |
| } |
| } |
| highlight_autocomplete_result_labels(text); |
| sync_selection_table(toroot); |
| return true; // allow the event to bubble up to the search api |
| } |
| } |
| |
| function rank_autocomplete_results(query) { |
| query = query || ''; |
| if (!gMatches || !gMatches.length) |
| return; |
| |
| // helper function that gets the last occurence index of the given regex |
| // in the given string, or -1 if not found |
| var _lastSearch = function(s, re) { |
| if (s == '') |
| return -1; |
| var l = -1; |
| var tmp; |
| while ((tmp = s.search(re)) >= 0) { |
| if (l < 0) l = 0; |
| l += tmp; |
| s = s.substr(tmp + 1); |
| } |
| return l; |
| }; |
| |
| // helper function that counts the occurrences of a given character in |
| // a given string |
| var _countChar = function(s, c) { |
| var n = 0; |
| for (var i=0; i<s.length; i++) |
| if (s.charAt(i) == c) ++n; |
| return n; |
| }; |
| |
| var queryLower = query.toLowerCase(); |
| var queryAlnum = (queryLower.match(/\w+/) || [''])[0]; |
| var partPrefixAlnumRE = new RegExp('\\b' + queryAlnum); |
| var partExactAlnumRE = new RegExp('\\b' + queryAlnum + '\\b'); |
| |
| var _resultScoreFn = function(result) { |
| // scores are calculated based on exact and prefix matches, |
| // and then number of path separators (dots) from the last |
| // match (i.e. favoring classes and deep package names) |
| var score = 1.0; |
| var labelLower = result.label.toLowerCase(); |
| var t; |
| t = _lastSearch(labelLower, partExactAlnumRE); |
| if (t >= 0) { |
| // exact part match |
| var partsAfter = _countChar(labelLower.substr(t + 1), '.'); |
| score *= 200 / (partsAfter + 1); |
| } else { |
| t = _lastSearch(labelLower, partPrefixAlnumRE); |
| if (t >= 0) { |
| // part prefix match |
| var partsAfter = _countChar(labelLower.substr(t + 1), '.'); |
| score *= 20 / (partsAfter + 1); |
| } |
| } |
| |
| return score; |
| }; |
| |
| for (var i=0; i<gMatches.length; i++) { |
| gMatches[i].__resultScore = _resultScoreFn(gMatches[i]); |
| } |
| |
| gMatches.sort(function(a,b){ |
| var n = b.__resultScore - a.__resultScore; |
| if (n == 0) // lexicographical sort if scores are the same |
| n = (a.label < b.label) ? -1 : 1; |
| return n; |
| }); |
| } |
| |
| function highlight_autocomplete_result_labels(query) { |
| query = query || ''; |
| if (!gMatches || !gMatches.length) |
| return; |
| |
| var queryLower = query.toLowerCase(); |
| var queryAlnumDot = (queryLower.match(/[\w\.]+/) || [''])[0]; |
| var queryRE = new RegExp( |
| '(' + queryAlnumDot.replace(/\./g, '\\.') + ')', 'ig'); |
| for (var i=0; i<gMatches.length; i++) { |
| gMatches[i].__hilabel = gMatches[i].label.replace( |
| queryRE, '<b>$1</b>'); |
| } |
| } |
| |
| function search_focus_changed(obj, focused) |
| { |
| if (focused) { |
| if(obj.value == DEFAULT_TEXT){ |
| obj.value = ""; |
| obj.style.color="#000000"; |
| } |
| } else { |
| if(obj.value == ""){ |
| obj.value = DEFAULT_TEXT; |
| obj.style.color="#aaaaaa"; |
| } |
| document.getElementById("search_filtered_div").className = "no-display"; |
| } |
| } |
| |
| function submit_search() { |
| var query = document.getElementById('search_autocomplete').value; |
| document.location = toRoot + 'search.html#q=' + query + '&t=0'; |
| return false; |
| } |