a8b127c09270d6ef76bbebb3780f8a67e289bdf8
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-notused")
42 .keyup(function(event
) {
43 Nitdoc
.QuickSearch
.doKeyAction(event
.keyCode
);
45 .focusout(function() {
46 if($
(this).val() == "") {
47 $
(this).addClass("nitdoc-qs-notused");
48 $
(this).val("quick search...");
52 if($
(this).val() == "quick search...") {
53 $
(this).removeClass("nitdoc-qs-notused");
58 $
(containerSelector
).append(
59 $
(document
.createElement("li"))
61 $
(document
.createElement("form"))
69 // Close quicksearch list on click
70 $
(document
).click(function(e
) {
71 Nitdoc
.QuickSearch
.closeResultsTable();
75 // Respond to key event
76 var doKeyAction
= function(key
) {
96 default: // Other keys
97 var query
= searchField
.val();
101 var results
= rankResults(query
);
102 results
.sort(resultsSort
);
103 displayResultsTable(query
, results
);
108 // Rank raw list entries corresponding to query
109 var rankResults
= function(query
) {
110 var results
= new Array();
111 for(var entry
in rawList
) {
112 for(var i
in rawList
[entry]) {
113 var result
= rawList
[entry][i];
114 result
.entry
= entry
;
115 result
.distance
= query
.dice(entry
);
116 results
[results
.length
] = result
;
122 // Sort an array of results
123 var resultsSort
= function(a
, b
){
124 if(a
.distance
< b
.distance
) {
126 } else if(a
.distance
> b
.distance
) {
132 // Display results in a popup table
133 var displayResultsTable
= function(query
, results
) {
134 // Clear results table
135 if(currentTable
) currentTable
.remove();
137 // Build results table
139 currentTable
= $
(document
.createElement("table"));
141 for(var i
in results
) {
145 var result
= results
[i];
147 $
(document
.createElement("tr"))
148 .data("searchDetails", {name
: result
.entry
, url
: result
.url
})
150 .append($
(document
.createElement("td")).html(result
.entry
))
152 $
(document
.createElement("td"))
153 .addClass("nitdoc-qs-info")
154 .html(result
.txt
+ " »")
156 .mouseover( function() {
157 $
(currentTable
.find("tr")[currentIndex]).removeClass("nitdoc-qs-active");
158 $
(this).addClass("nitdoc-qs-active");
159 currentIndex
= $
(this).data("index");
161 .mouseout( function() {
162 $
(this).removeClass("nitdoc-qs-active");
165 window
.location
= $
(this).data("searchDetails")["url"];
170 $
("<tr class='nitdoc-qs-overflow'>")
172 $
("<td colspan='2'>")
173 .html("Best results for '" + query
+ "'")
177 // Initialize table properties
178 currentTable
.attr("id", "nitdoc-qs-table");
179 currentTable
.css("position", "absolute");
180 currentTable
.width(searchField
.outerWidth());
181 $
("body").append(currentTable
);
182 currentTable
.offset({left
: searchField
.offset().left
+ (searchField
.outerWidth() - currentTable
.outerWidth()), top
: searchField
.offset().top
+ searchField
.outerHeight()});
183 // Preselect first entry
184 if(currentTable
.find("tr").length
> 0) {
186 $
(currentTable
.find("tr")[currentIndex]).addClass("nitdoc-qs-active");
191 // Select the previous result on current table
192 var selectPrevResult
= function() {
193 // If already on first result, focus search input
194 if(currentIndex
== 0) {
195 searchField
.val($
(currentTable
.find("tr")[currentIndex]).data("searchDetails").name
);
197 // Else select previous result
198 } else if(currentIndex
> 0) {
199 $
(currentTable
.find("tr")[currentIndex]).removeClass("nitdoc-qs-active");
201 $
(currentTable
.find("tr")[currentIndex]).addClass("nitdoc-qs-active");
202 searchField
.val($
(currentTable
.find("tr")[currentIndex]).data("searchDetails").name
);
207 // Select the next result on current table
208 var selectNextResult
= function() {
209 if(currentIndex
< currentTable
.find("tr").length
- 1) {
210 if($
(currentTable
.find("tr")[currentIndex
+ 1]).hasClass("nitdoc-qs-overflow")) {
213 $
(currentTable
.find("tr")[currentIndex]).removeClass("nitdoc-qs-active");
215 $
(currentTable
.find("tr")[currentIndex]).addClass("nitdoc-qs-active");
216 searchField
.val($
(currentTable
.find("tr")[currentIndex]).data("searchDetails").name
);
221 // Load selected search result page
222 var goToResult
= function() {
223 if(currentIndex
> -1) {
224 window
.location
= $
(currentTable
.find("tr")[currentIndex]).data("searchDetails").url
;
228 if(searchField
.val().length
== 0) { return; }
230 window
.location
= "search.html#q=" + searchField
.val();
231 if(window
.location
.href
.indexOf("search.html") > -1) {
236 // Close the results table
237 closeResultsTable
= function(target
) {
238 if(target
!= searchField
&& target
!= currentTable
) {
239 if(currentTable
!= null) {
240 currentTable
.remove();
248 enableQuickSearch
: enableQuickSearch
,
249 doKeyAction
: doKeyAction
,
250 closeResultsTable
: closeResultsTable
256 $
(document
).ready(function() {
257 Nitdoc
.QuickSearch
.enableQuickSearch("nav.main ul");
264 // Calculate levenshtein distance beetween two strings
265 // see: http://en.wikipedia.org/wiki/Levenshtein_distance
266 String
.prototype.levenshtein
= function(other
) {
267 var matrix
= new Array();
269 for(var i
= 0; i
<= this.length
; i
++) {
270 matrix
[i] = new Array();
273 for(var j
= 0; j
<= other
.length
; j
++) {
277 for(var i
= 1; i
<= this.length
; i
++) {
278 for(var j
= 1; j
<= other
.length
; j
++) {
279 if(this.charAt(i
- 1) == other
.charAt(j
- 1)) {
281 } else if(this.charAt(i
- 1).toLowerCase() == other
.charAt(j
- 1).toLowerCase()) {
286 matrix
[i][j] = Math
.min(
287 matrix
[i
- 1][j] + 1, // deletion
288 matrix
[i][j
- 1] + 1, // insertion
289 matrix
[i
- 1][j
- 1] + cost
// substitution
293 return matrix
[this.length
][other
.length
]
296 // Compare two strings using Sorensen-Dice Coefficient
297 // see: http://en.wikipedia.org/wiki/S%C3%B8rensen%E2%80%93Dice_coefficient
298 String
.prototype.dice
= function(other
) {
299 var length1
= this.length
- 1;
300 var length2
= other
.length
- 1;
301 if(length1
< 1 || length2
< 1) return 0;
304 for(var i
= 0; i
< length2
; i
++) {
305 bigrams2
.push(other
.substr(i
, 2));
308 var intersection
= 0;
309 for(var i
= 0; i
< length1
; i
++) {
310 var bigram1
= this.substr(i
, 2);
311 for(var j
= 0; j
< length2
; j
++) {
312 if(bigram1
== bigrams2
[j]) {
316 } else if (bigram1
&& bigrams2
[j] && bigram1
.toLowerCase() == bigrams2
[j].toLowerCase()) {
323 return (2.0 * intersection
) / (length1
+ length2
);