1 /* This file is part of NIT ( http://www.nitlanguage.org ).
3 Licensed under the Apache License, Version 2.0 (the "License");
4 you may not use this file except in compliance with the License.
5 You may obtain a copy of the License at
7 http://www.apache.org/licenses/LICENSE-2.0
9 Unless required by applicable law or agreed to in writing, software
10 distributed under the License is distributed on an "AS IS" BASIS,
11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 See the License for the specific language governing permissions and
13 limitations under the License.
15 Documentation generator for the nit language.
16 Generate API documentation in HTML format from nit source code.
19 var Nitdoc
= Nitdoc ||
{};
22 * Nitdoc QuickSearch module
26 Nitdoc
.QuickSearch
= function() {
27 var rawList
= nitdocQuickSearchRawList
; // List of raw resulsts generated by nitdoc tool
28 var searchField
= null; // <input:text> search field
29 var currentTable
= null; // current search results <table>
30 var currentIndex
= -1; // current cursor position into search results table
32 // Enable QuickSearch plugin
33 var enableQuickSearch
= function(containerSelector
) {
34 searchField
= $
(document
.createElement("input"))
36 id
: "nitdoc-qs-field",
39 value
: "quick search..."
41 .addClass("nitdoc-qs-field-notused")
42 .keyup(function(event
) {
43 Nitdoc
.QuickSearch
.doKeyAction(event
.keyCode
);
45 .focusout(function() {
46 if($
(this).val() == "") {
47 $
(this).addClass("nitdoc-qs-field-notused");
48 $
(this).val("quick search...");
52 if($
(this).val() == "quick search...") {
53 $
(this).removeClass("nitdoc-qs-field-notused");
58 $
(containerSelector
).append(
59 $
(document
.createElement("li"))
60 .attr("id", "nitdoc-qs-li")
64 // Close quicksearch list on click
65 $
(document
).click(function(e
) {
66 Nitdoc
.QuickSearch
.closeResultsTable();
70 // Respond to key event
71 var doKeyAction
= function(key
) {
91 default: // Other keys
92 var query
= searchField
.val();
96 var results
= rankResults(query
);
97 results
.sort(resultsSort
);
98 displayResultsTable(query
, results
);
103 // Rank raw list entries corresponding to query
104 var rankResults
= function(query
) {
105 var results
= new Array();
106 for(var entry
in rawList
) {
107 for(var i
in rawList
[entry]) {
108 var result
= rawList
[entry][i];
109 result
.entry
= entry
;
110 result
.distance
= query
.dice(entry
);
111 results
[results
.length
] = result
;
117 // Sort an array of results
118 var resultsSort
= function(a
, b
){
119 if(a
.distance
< b
.distance
) {
121 } else if(a
.distance
> b
.distance
) {
127 // Display results in a popup table
128 var displayResultsTable
= function(query
, results
) {
129 // Clear results table
130 if(currentTable
) currentTable
.remove();
132 // Build results table
134 currentTable
= $
(document
.createElement("table"));
136 for(var i
in results
) {
140 var result
= results
[i];
142 $
(document
.createElement("tr"))
143 .data("searchDetails", {name
: result
.entry
, url
: result
.url
})
145 .append($
(document
.createElement("td")).html(result
.entry
))
147 $
(document
.createElement("td"))
148 .addClass("nitdoc-qs-info")
149 .html(result
.txt
+ " »")
151 .mouseover( function() {
152 $
(currentTable
.find("tr")[currentIndex]).removeClass("nitdoc-qs-active");
153 $
(this).addClass("nitdoc-qs-active");
154 currentIndex
= $
(this).data("index");
156 .mouseout( function() {
157 $
(this).removeClass("nitdoc-qs-active");
160 window
.location
= $
(this).data("searchDetails")["url"];
165 $
("<tr class='nitdoc-qs-overflow'>")
167 $
("<td colspan='2'>")
168 .html("Best results for '" + query
+ "'")
172 // Initialize table properties
173 currentTable
.attr("id", "nitdoc-qs-table");
174 currentTable
.css("position", "absolute");
175 currentTable
.width(searchField
.outerWidth());
176 $
("body").append(currentTable
);
177 currentTable
.offset({left
: searchField
.offset().left
+ (searchField
.outerWidth() - currentTable
.outerWidth()), top
: searchField
.offset().top
+ searchField
.outerHeight()});
178 // Preselect first entry
179 if(currentTable
.find("tr").length
> 0) {
181 $
(currentTable
.find("tr")[currentIndex]).addClass("nitdoc-qs-active");
186 // Select the previous result on current table
187 var selectPrevResult
= function() {
188 // If already on first result, focus search input
189 if(currentIndex
== 0) {
190 searchField
.val($
(currentTable
.find("tr")[currentIndex]).data("searchDetails").name
);
192 // Else select previous result
193 } else if(currentIndex
> 0) {
194 $
(currentTable
.find("tr")[currentIndex]).removeClass("nitdoc-qs-active");
196 $
(currentTable
.find("tr")[currentIndex]).addClass("nitdoc-qs-active");
197 searchField
.val($
(currentTable
.find("tr")[currentIndex]).data("searchDetails").name
);
202 // Select the next result on current table
203 var selectNextResult
= function() {
204 if(currentIndex
< currentTable
.find("tr").length
- 1) {
205 if($
(currentTable
.find("tr")[currentIndex
+ 1]).hasClass("nitdoc-qs-overflow")) {
208 $
(currentTable
.find("tr")[currentIndex]).removeClass("nitdoc-qs-active");
210 $
(currentTable
.find("tr")[currentIndex]).addClass("nitdoc-qs-active");
211 searchField
.val($
(currentTable
.find("tr")[currentIndex]).data("searchDetails").name
);
216 // Load selected search result page
217 var goToResult
= function() {
218 if(currentIndex
> -1) {
219 window
.location
= $
(currentTable
.find("tr")[currentIndex]).data("searchDetails").url
;
223 if(searchField
.val().length
== 0) { return; }
225 window
.location
= "search.html#q=" + searchField
.val();
226 if(window
.location
.href
.indexOf("search.html") > -1) {
231 // Close the results table
232 closeResultsTable
= function(target
) {
233 if(target
!= searchField
&& target
!= currentTable
) {
234 if(currentTable
!= null) {
235 currentTable
.remove();
243 enableQuickSearch
: enableQuickSearch
,
244 doKeyAction
: doKeyAction
,
245 closeResultsTable
: closeResultsTable
251 $
(document
).ready(function() {
252 Nitdoc
.QuickSearch
.enableQuickSearch("nav.main ul");
259 // Calculate levenshtein distance beetween two strings
260 // see: http://en.wikipedia.org/wiki/Levenshtein_distance
261 String
.prototype.levenshtein
= function(other
) {
262 var matrix
= new Array();
264 for(var i
= 0; i
<= this.length
; i
++) {
265 matrix
[i] = new Array();
268 for(var j
= 0; j
<= other
.length
; j
++) {
272 for(var i
= 1; i
<= this.length
; i
++) {
273 for(var j
= 1; j
<= other
.length
; j
++) {
274 if(this.charAt(i
- 1) == other
.charAt(j
- 1)) {
276 } else if(this.charAt(i
- 1).toLowerCase() == other
.charAt(j
- 1).toLowerCase()) {
281 matrix
[i][j] = Math
.min(
282 matrix
[i
- 1][j] + 1, // deletion
283 matrix
[i][j
- 1] + 1, // insertion
284 matrix
[i
- 1][j
- 1] + cost
// substitution
288 return matrix
[this.length
][other
.length
]
291 // Compare two strings using Sorensen-Dice Coefficient
292 // see: http://en.wikipedia.org/wiki/S%C3%B8rensen%E2%80%93Dice_coefficient
293 String
.prototype.dice
= function(other
) {
294 var length1
= this.length
- 1;
295 var length2
= other
.length
- 1;
296 if(length1
< 1 || length2
< 1) return 0;
299 for(var i
= 0; i
< length2
; i
++) {
300 bigrams2
.push(other
.substr(i
, 2));
303 var intersection
= 0;
304 for(var i
= 0; i
< length1
; i
++) {
305 var bigram1
= this.substr(i
, 2);
306 for(var j
= 0; j
< length2
; j
++) {
307 if(bigram1
== bigrams2
[j]) {
311 } else if (bigram1
&& bigrams2
[j] && bigram1
.toLowerCase() == bigrams2
[j].toLowerCase()) {
318 return (2.0 * intersection
) / (length1
+ length2
);