nitdoc: refactor Nitdoc.QuickSearch JS module into quicksearch plugin
authorAlexandre Terrasa <alexandre@moz-code.org>
Fri, 7 Feb 2014 07:31:03 +0000 (02:31 -0500)
committerAlexandre Terrasa <alexandre@moz-code.org>
Thu, 20 Feb 2014 19:11:58 +0000 (14:11 -0500)
Signed-off-by: Alexandre Terrasa <alexandre@moz-code.org>

share/nitdoc/js/nitdoc.js
share/nitdoc/js/plugins/quicksearch.js [new file with mode: 0644]
share/nitdoc/js/plugins/utils.js
share/nitdoc/scripts/Nitdoc.QuickSearch.js [deleted file]

index 4d12538..dde4546 100644 (file)
@@ -13,5 +13,6 @@ require.config({
 // nitdoc main module
 define([
        "plugins/ui",
+       "plugins/quicksearch",
 ], function() {});
 
diff --git a/share/nitdoc/js/plugins/quicksearch.js b/share/nitdoc/js/plugins/quicksearch.js
new file mode 100644 (file)
index 0000000..a3b29c1
--- /dev/null
@@ -0,0 +1,361 @@
+/* This file is part of NIT ( http://www.nitlanguage.org ).
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+   Documentation generator for the nit language.
+   Generate API documentation in HTML format from nit source code.
+*/
+
+/*
+ * Nitdoc QuickSearch module
+ */
+define([
+       "jquery",
+       "plugins/utils",
+       "quicksearchList",
+], function($, utils) {
+
+       var QuickSearch = {
+               rawList: this.nitdocQuickSearchRawList, // List of raw resulsts generated by nitdoc tool
+               searchField: null, // <input:text> search field
+               currentTable: null, // current search results <table>
+               currentIndex: -1, // current cursor position into search results table
+
+               // Enable QuickSearch plugin
+               enableQuickSearch: function(containerSelector) {
+                       this.searchField = $(document.createElement("input"))
+                       .attr({
+                               id: "nitdoc-qs-field",
+                               type: "text",
+                               autocomplete: "off",
+                               value: "quick search..."
+                       })
+                       .addClass("nitdoc-qs-field-notused")
+                       .keydown(function(event) {
+                               return QuickSearch.doKeyDownAction(event.keyCode);
+                       })
+                       .keyup(function(event) {
+                               QuickSearch.doKeyUpAction(event.keyCode);
+                       })
+                       .focusout(function() {
+                               if($(this).val() == "") {
+                                       $(this).addClass("nitdoc-qs-field-notused");
+                                       $(this).val("quick search...");
+                               }
+                       })
+                       .focusin(function() {
+                               if($(this).val() == "quick search...") {
+                                       $(this).removeClass("nitdoc-qs-field-notused");
+                                       $(this).val("");
+                               }
+                       });
+
+                       $(containerSelector).append(
+                               $(document.createElement("li"))
+                               .attr("id", "nitdoc-qs-li")
+                               .append(this.searchField)
+                       );
+
+                       // Close quicksearch list on click
+                       $(document).click(function(e) {
+                               QuickSearch.closeResultsTable();
+                       });
+               },
+
+               doKeyDownAction: function(key) {
+                       switch(key) {
+                               case 38: // Up
+                                       this.selectPrevResult();
+                                       return false;
+                               case 40: // Down
+                                       this.selectNextResult();
+                                       return false;
+                               default:
+                                       return true;
+                        }
+               },
+
+               doKeyUpAction: function(key) {
+                       switch(key) {
+                               case 38: // Up
+                               case 40: // Down
+                               break;
+
+                               case 13: // Enter
+                                       this.goToResult();
+                                       return false;
+                               break;
+
+                               case 27: // Escape
+                                       $(this).blur();
+                                       this.closeResultsTable();
+                               break;
+
+                               default: // Other keys
+                                       var query = this.searchField.val();
+                                       if(!query) {
+                                               return false;
+                                       }
+                                       var results = QuickSearch.getResults(query);
+                                       this.displayResultsTable(query, results);
+                               break;
+                       }
+               },
+
+               // Get results corresponding to search query
+               getResults: function(query) {
+                       var results = {};
+                       results.matches = new Array();
+                       for(var entry in this.rawList) {
+                               if(!entry.startsWith(query, true)) {
+                                       continue;
+                               }
+                               var cat = new Object();
+                               cat.name = entry;
+                               cat.entries = this.rawList[entry];
+                               results.matches[results.matches.length] = cat;
+
+                               if(entry == query) {
+                                       cat.rank = 3;
+                               } else if(entry.toUpperCase() == query.toUpperCase()) {
+                                       cat.rank = 2;
+                               } else {
+                                       cat.rank = 1 + query.dice(entry);
+                               }
+                       }
+                       results.matches.sort(this.rankSorter);
+                       results.partials = new Array();
+                       if(results.matches.length == 0) {
+                               for(var entry in this.rawList) {
+                                       var cat = new Object();
+                                       cat.name = entry;
+                                       cat.entries = this.rawList[entry];
+                                       cat.rank = query.dice(entry);
+                                       if(cat.rank > 0) {
+                                               results.partials[results.partials.length] = cat;
+                                       }
+                               }
+                               results.partials.sort(this.rankSorter);
+                       }
+                       return results;
+               },
+
+               // Sort an array of results by rank
+               rankSorter: function(a, b){
+                       if(a.rank < b.rank) {
+                               return 1;
+                       } else if(a.rank > b.rank) {
+                               return -1;
+                       }
+                       return 0;
+               },
+
+               // Display results in a popup table
+               displayResultsTable: function(query, results) {
+                       // Clear results table
+                       if(this.currentTable) this.currentTable.remove();
+
+                       // Build results table
+                       this.currentIndex = -1;
+                       this.currentTable = $(document.createElement("table"));
+                       this.currentTable.attr("id", "nitdoc-qs-table");
+                       this.currentTable.css("position", "absolute");
+                       this.currentTable.width(this.searchField.outerWidth());
+
+                       var maxSize = 10;
+                       var count = 0;
+                       var resultSet;
+                       if(results.matches.length == 0) {
+                               resultSet = results.partials
+                       } else {
+                               resultSet = results.matches
+                       }
+                       for(var i in resultSet) {
+                               var cat = resultSet[i];
+                               var result = cat.entries[0];
+
+                               this.addResultRow(count, cat.name, result.txt, result.url, "nitdoc-qs-cat")
+                               if(count >= maxSize) {
+                                       this.currentTable.find("tbody").children().last().hide();
+                               }
+                               count++;
+
+                               for(var j = 1; j < cat.entries.length; j++) {
+                                       var result = cat.entries[j];
+                                       this.addResultRow(count, cat.name, result.txt, result.url, "nitdoc-qs-sub")
+                                       if(count >= maxSize) {
+                                               this.currentTable.find("tr.nitdoc-qs-row").last().hide();
+                                       }
+                                       count++;
+                               }
+                       }
+                       if(count >= maxSize) {
+                               this.currentTable.prepend(
+                                       $(document.createElement("tr"))
+                                       .addClass("nitdoc-qs-overflow-up")
+                                       .addClass("nitdoc-qs-overflow-inactive")
+                                       .append(
+                                               $(document.createElement("td"))
+                                               .attr("colspan", 2)
+                                               .html("&#x25B2;")
+                                       )
+                                       .click( function(e) {
+                                               e.stopPropagation();
+                                               QuickSearch.selectPrevResult();
+                                       })
+                               );
+                               this.currentTable.append(
+                                       $(document.createElement("tr"))
+                                       .addClass("nitdoc-qs-overflow-down")
+                                       .addClass(count >= maxSize ? "nitdoc-qs-overflow-active" : "nitdoc-qs-overflow-inactive")
+                                       .append(
+                                               $(document.createElement("td"))
+                                               .attr("colspan", 2)
+                                               .html("&#x25BC;")
+                                       )
+                                       .click( function(e) {
+                                               e.stopPropagation();
+                                               console.log("nest");
+                                               QuickSearch.selectNextResult();
+                                       })
+                               );
+                       }
+                       if(results.matches.length == 0) {
+                               this.currentTable.prepend(
+                                       $("<tr class='nitdoc-qs-noresult'>")
+                                       .append(
+                                               $("<td colspan='2'>")
+                                               .html("Sorry, there is no match, best results are:")
+                                       )
+                               );
+                       }
+
+                       // Initialize table
+                       $("body").append(this.currentTable);
+                       this.resizeResultsTable();
+                       if(this.currentTable.find("tr").length > 0) {
+                               this.setIndex(0);
+                       }
+               },
+
+               // adds a result row to the current result table
+               addResultRow: function(index, name, txt, url, cls) {
+                       this.currentTable.append(
+                               $(document.createElement("tr"))
+                               .addClass("nitdoc-qs-row")
+                               .data("searchDetails", {name: name, url: url})
+                               .data("index", index)
+                               .append(
+                                       $(document.createElement("td")).html(name)
+                                       .addClass(cls)
+                               )
+                               .append(
+                                       $(document.createElement("td"))
+                                               .addClass("nitdoc-qs-info")
+                                               .html(txt + "&nbsp;&raquo;")
+                               )
+                               .mouseover( function() {
+                                       QuickSearch.setIndex($(this).data("index"));
+                               })
+                               .mouseout( function() {
+                                       $(this).removeClass("nitdoc-qs-active");
+                                })
+                               .click( function() {
+                                       window.location = $(this).data("searchDetails")["url"];
+                               })
+                       );
+               },
+
+               // adapts result table to content
+               resizeResultsTable: function() {
+                       this.currentTable.offset({
+                               left: this.searchField.offset().left + (this.searchField.outerWidth() - this.currentTable.outerWidth()),
+                               top: this.searchField.offset().top + this.searchField.outerHeight()
+                       });
+               },
+
+               // select row at index
+               setIndex: function(index) {
+                       $(this.currentTable.find("tr.nitdoc-qs-row")[this.currentIndex]).removeClass("nitdoc-qs-active");
+                       this.currentIndex = index;
+                       var currentRow = $(this.currentTable.find("tr.nitdoc-qs-row")[this.currentIndex]);
+                       currentRow.addClass("nitdoc-qs-active");
+                       //searchField.val(currentRow.data("searchDetails").name);
+               },
+
+               hasPrev: function(index) {
+                       return index - 1 >= 0;
+               },
+
+               hasNext: function(index) {
+                       return index + 1 < this.currentTable.find("tr.nitdoc-qs-row").length;
+               },
+
+               selectPrevResult: function() {
+                       if(this.hasPrev(this.currentIndex)) {
+                               this.setIndex(this.currentIndex - 1);
+                               if(!$(this.currentTable.find("tr.nitdoc-qs-row")[this.currentIndex]).is(":visible")) {
+                                       this.currentTable.find("tr.nitdoc-qs-row:visible").last().hide();
+                                       this.currentTable.find("tr.nitdoc-qs-overflow-down").addClass("nitdoc-qs-overflow-active");
+                                       $(this.currentTable.find("tr.nitdoc-qs-row")[this.currentIndex]).show();
+                                       if(!this.hasPrev(this.currentIndex)) {
+                                               this.currentTable.find("tr.nitdoc-qs-overflow-up").removeClass("nitdoc-qs-overflow-active");
+                                       }
+                                       this.resizeResultsTable();
+                               }
+                       }
+               },
+
+               selectNextResult: function() {
+                       if(this.hasNext(this.currentIndex)) {
+                               this.setIndex(this.currentIndex + 1);
+                               if(!$(this.currentTable.find("tr.nitdoc-qs-row")[this.currentIndex]).is(":visible")) {
+                                       this.currentTable.find("tr.nitdoc-qs-row:visible").first().hide();
+                                       this.currentTable.find("tr.nitdoc-qs-overflow-up").addClass("nitdoc-qs-overflow-active");
+                                       $(this.currentTable.find("tr.nitdoc-qs-row")[this.currentIndex]).show();
+                                       if(!this.hasNext(this.currentIndex)) {
+                                               this.currentTable.find("tr.nitdoc-qs-overflow-down").removeClass("nitdoc-qs-overflow-active");
+                                       }
+                                       this.resizeResultsTable();
+                               }
+                       }
+               },
+
+               // Load selected search result page
+               goToResult: function() {
+                       if(this.currentIndex > -1) {
+                               window.location = $(this.currentTable.find("tr.nitdoc-qs-row")[this.currentIndex]).data("searchDetails").url;
+                               return;
+                       }
+
+                       if(this.searchField.val().length == 0) { return; }
+
+                       window.location = "search.html#q=" + this.searchField.val();
+                       if(window.location.href.indexOf("search.html") > -1) {
+                               location.reload();
+                       }
+               },
+
+               // Close the results table
+               closeResultsTable: function(target) {
+                       if(target != this.searchField && target != this.currentTable) {
+                               if(this.currentTable != null) {
+                                       this.currentTable.remove();
+                                       this.currentTable = null;
+                               }
+                       }
+               }
+       };
+
+       QuickSearch.enableQuickSearch("nav.main ul");
+});
index 4ce7c04..fe9dca1 100644 (file)
@@ -23,6 +23,39 @@ define([
        "jquery",\r
 ], function($) {\r
 \r
+       String.prototype.startsWith = function(prefix, caseSensitive) {\r
+               if(caseSensitive) {\r
+                       return this.toUpperCase().indexOf(prefix.toUpperCase()) === 0;\r
+               }\r
+               return this.indexOf(prefix) === 0;\r
+       }\r
+\r
+       // Compare two strings using Sorensen-Dice Coefficient\r
+       // see: http://en.wikipedia.org/wiki/S%C3%B8rensen%E2%80%93Dice_coefficient\r
+       String.prototype.dice = function(other) {\r
+               var length1 = this.length - 1;\r
+               var length2 = other.length - 1;\r
+               if(length1 < 1 || length2 < 1) return 0;\r
+\r
+               var bigrams2 = [];\r
+               for(var i = 0; i < length2; i++) {\r
+                       bigrams2.push(other.substr(i, 2));\r
+               }\r
+\r
+               var intersection = 0;\r
+               for(var i = 0; i < length1; i++) {\r
+                       var bigram1 = this.substr(i, 2);\r
+                       for(var j = 0; j < length2; j++) {\r
+                               if(bigram1 == bigrams2[j]) {\r
+                                       intersection++;\r
+                                       bigrams2[j] = null;\r
+                                       break;\r
+                               }\r
+                       }\r
+               }\r
+               return (2.0 * intersection) / (length1 + length2);\r
+       }\r
+\r
        // JQuery Case Insensitive :icontains selector\r
        $.expr[':'].icontains = function(obj, index, meta, stack){\r
                return (obj.textContent.replace(/\[[0-9]+\]/g, "") || obj.innerText.replace(/\[[0-9]+\]/g, "") || jQuery(obj).text().replace(/\[[0-9]+\]/g, "") || '').toLowerCase().indexOf(meta[3].toLowerCase()) >= 0;\r
diff --git a/share/nitdoc/scripts/Nitdoc.QuickSearch.js b/share/nitdoc/scripts/Nitdoc.QuickSearch.js
deleted file mode 100644 (file)
index 20dcf60..0000000
+++ /dev/null
@@ -1,408 +0,0 @@
-/* This file is part of NIT ( http://www.nitlanguage.org ).
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-   you may not use this file except in compliance with the License.
-   You may obtain a copy of the License at
-
-   http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-
-   Documentation generator for the nit language.
-   Generate API documentation in HTML format from nit source code.
-*/
-
-var Nitdoc = Nitdoc || {};
-
-/*
- * Nitdoc QuickSearch module
- *
- */
-
-Nitdoc.QuickSearch = function() {
-       var rawList = nitdocQuickSearchRawList; // List of raw resulsts generated by nitdoc tool
-       var searchField = null; // <input:text> search field
-       var currentTable = null; // current search results <table>
-       var currentIndex = -1; // current cursor position into search results table
-
-       // Enable QuickSearch plugin
-       var enableQuickSearch = function(containerSelector) {
-               searchField = $(document.createElement("input"))
-               .attr({
-                       id: "nitdoc-qs-field",
-                       type: "text",
-                       autocomplete: "off",
-                       value: "quick search..."
-               })
-               .addClass("nitdoc-qs-field-notused")
-               .keydown(function(event) {
-                       return Nitdoc.QuickSearch.doKeyDownAction(event.keyCode);
-               })
-               .keyup(function(event) {
-                       Nitdoc.QuickSearch.doKeyUpAction(event.keyCode);
-               })
-               .focusout(function() {
-                       if($(this).val() == "") {
-                               $(this).addClass("nitdoc-qs-field-notused");
-                               $(this).val("quick search...");
-                       }
-               })
-               .focusin(function() {
-                       if($(this).val() == "quick search...") {
-                               $(this).removeClass("nitdoc-qs-field-notused");
-                               $(this).val("");
-                       }
-               });
-
-               $(containerSelector).append(
-                       $(document.createElement("li"))
-                       .attr("id", "nitdoc-qs-li")
-                       .append(searchField)
-               );
-
-               // Close quicksearch list on click
-               $(document).click(function(e) {
-                       Nitdoc.QuickSearch.closeResultsTable();
-               });
-       }
-
-       var doKeyDownAction = function(key) {
-               switch(key) {
-                       case 38: // Up
-                               selectPrevResult();
-                               return false;
-                       case 40: // Down
-                               selectNextResult();
-                               return false;
-                       default:
-                               return true;
-                }
-       }
-
-       var doKeyUpAction = function(key) {
-               switch(key) {
-                       case 38: // Up
-                       case 40: // Down
-                       break;
-
-                       case 13: // Enter
-                               goToResult();
-                               return false;
-                       break;
-
-                       case 27: // Escape
-                               $(this).blur();
-                               closeResultsTable();
-                       break;
-
-                       default: // Other keys
-                               var query = searchField.val();
-                               if(!query) {
-                                       return false;
-                               }
-                               var results = getResults(query);
-                               displayResultsTable(query, results);
-                       break;
-               }
-       }
-
-       // Get results corresponding to search query
-       var getResults = function(query) {
-               var results = {};
-               results.matches = new Array();
-               for(var entry in rawList) {
-                       if(!entry.startsWith(query, true)) {
-                               continue;
-                       }
-                       var cat = new Object();
-                       cat.name = entry;
-                       cat.entries = rawList[entry];
-                       results.matches[results.matches.length] = cat;
-
-                       if(entry == query) {
-                               cat.rank = 3;
-                       } else if(entry.toUpperCase() == query.toUpperCase()) {
-                               cat.rank = 2;
-                       } else {
-                               cat.rank = 1 + query.dice(entry);
-                       }
-               }
-               results.matches.sort(rankSorter);
-               results.partials = new Array();
-               if(results.matches.length == 0) {
-                       for(var entry in rawList) {
-                               var cat = new Object();
-                               cat.name = entry;
-                               cat.entries = rawList[entry];
-                               cat.rank = query.dice(entry);
-                               if(cat.rank > 0) {
-                                       results.partials[results.partials.length] = cat;
-                               }
-                       }
-                       results.partials.sort(rankSorter);
-               }
-               return results;
-       }
-
-       // Sort an array of results by rank
-       var rankSorter = function(a, b){
-               if(a.rank < b.rank) {
-                       return 1;
-               } else if(a.rank > b.rank) {
-                       return -1;
-               }
-               return 0;
-       }
-
-       // Display results in a popup table
-       var displayResultsTable = function(query, results) {
-               // Clear results table
-               if(currentTable) currentTable.remove();
-
-               // Build results table
-               currentIndex = -1;
-               currentTable = $(document.createElement("table"));
-               currentTable.attr("id", "nitdoc-qs-table");
-               currentTable.css("position", "absolute");
-               currentTable.width(searchField.outerWidth());
-
-               var maxSize = 10;
-               var count = 0;
-               var resultSet;
-               if(results.matches.length == 0) {
-                       resultSet = results.partials
-               } else {
-                       resultSet = results.matches
-               }
-               for(var i in resultSet) {
-                       var cat = resultSet[i];
-                       var result = cat.entries[0];
-
-                       addResultRow(count, cat.name, result.txt, result.url, "nitdoc-qs-cat")
-                       if(count >= maxSize) {
-                               currentTable.find("tbody").children().last().hide();
-                       }
-                       count++;
-
-                       for(var j = 1; j < cat.entries.length; j++) {
-                               var result = cat.entries[j];
-                               addResultRow(count, cat.name, result.txt, result.url, "nitdoc-qs-sub")
-                               if(count >= maxSize) {
-                                       currentTable.find("tr.nitdoc-qs-row").last().hide();
-                               }
-                               count++;
-                       }
-               }
-               if(count >= maxSize) {
-                       currentTable.prepend(
-                               $(document.createElement("tr"))
-                               .addClass("nitdoc-qs-overflow-up")
-                               .addClass("nitdoc-qs-overflow-inactive")
-                               .append(
-                                       $(document.createElement("td"))
-                                       .attr("colspan", 2)
-                                       .html("&#x25B2;")
-                               )
-                               .click( function(e) {
-                                       e.stopPropagation();
-                                       selectPrevResult();
-                               })
-                       );
-                       currentTable.append(
-                               $(document.createElement("tr"))
-                               .addClass("nitdoc-qs-overflow-down")
-                               .addClass(count >= maxSize ? "nitdoc-qs-overflow-active" : "nitdoc-qs-overflow-inactive")
-                               .append(
-                                       $(document.createElement("td"))
-                                       .attr("colspan", 2)
-                                       .html("&#x25BC;")
-                               )
-                               .click( function(e) {
-                                       e.stopPropagation();
-                                       console.log("nest");
-                                       selectNextResult();
-                               })
-                       );
-               }
-               if(results.matches.length == 0) {
-                       currentTable.prepend(
-                               $("<tr class='nitdoc-qs-noresult'>")
-                               .append(
-                                       $("<td colspan='2'>")
-                                       .html("Sorry, there is no match, best results are:")
-                               )
-                       );
-               }
-
-               // Initialize table
-               $("body").append(currentTable);
-               resizeResultsTable();
-               if(currentTable.find("tr").length > 0) {
-                       setIndex(0);
-               }
-       }
-
-       // adds a result row to the current result table
-       var addResultRow = function(index, name, txt, url, cls) {
-               currentTable.append(
-                       $(document.createElement("tr"))
-                       .addClass("nitdoc-qs-row")
-                       .data("searchDetails", {name: name, url: url})
-                       .data("index", index)
-                       .append(
-                               $(document.createElement("td")).html(name)
-                               .addClass(cls)
-                       )
-                       .append(
-                               $(document.createElement("td"))
-                                       .addClass("nitdoc-qs-info")
-                                       .html(txt + "&nbsp;&raquo;")
-                       )
-                       .mouseover( function() {
-                               setIndex($(this).data("index"));
-                       })
-                       .mouseout( function() {
-                               $(this).removeClass("nitdoc-qs-active");
-                        })
-                       .click( function() {
-                               window.location = $(this).data("searchDetails")["url"];
-                       })
-               );
-       }
-
-       // adapts result table to content
-       var resizeResultsTable = function() {
-               currentTable.offset({
-                       left: searchField.offset().left + (searchField.outerWidth() - currentTable.outerWidth()),
-                       top: searchField.offset().top + searchField.outerHeight()
-               });
-       }
-
-       // select row at index
-       var setIndex = function(index) {
-               $(currentTable.find("tr.nitdoc-qs-row")[currentIndex]).removeClass("nitdoc-qs-active");
-               currentIndex = index;
-               var currentRow = $(currentTable.find("tr.nitdoc-qs-row")[currentIndex]);
-               currentRow.addClass("nitdoc-qs-active");
-               //searchField.val(currentRow.data("searchDetails").name);
-       }
-
-       var hasPrev = function(index) {
-               return index - 1 >= 0;
-       }
-
-       var hasNext = function(index) {
-               return index + 1 < currentTable.find("tr.nitdoc-qs-row").length;
-       }
-
-       var selectPrevResult = function() {
-               if(hasPrev(currentIndex)) {
-                       setIndex(currentIndex - 1);
-                       if(!$(currentTable.find("tr.nitdoc-qs-row")[currentIndex]).is(":visible")) {
-                               currentTable.find("tr.nitdoc-qs-row:visible").last().hide();
-                               currentTable.find("tr.nitdoc-qs-overflow-down").addClass("nitdoc-qs-overflow-active");
-                               $(currentTable.find("tr.nitdoc-qs-row")[currentIndex]).show();
-                               if(!hasPrev(currentIndex)) {
-                                       currentTable.find("tr.nitdoc-qs-overflow-up").removeClass("nitdoc-qs-overflow-active");
-                               }
-                               resizeResultsTable();
-                       }
-               }
-       }
-
-       var selectNextResult = function() {
-               if(hasNext(currentIndex)) {
-                       setIndex(currentIndex + 1);
-                       if(!$(currentTable.find("tr.nitdoc-qs-row")[currentIndex]).is(":visible")) {
-                               currentTable.find("tr.nitdoc-qs-row:visible").first().hide();
-                               currentTable.find("tr.nitdoc-qs-overflow-up").addClass("nitdoc-qs-overflow-active");
-                               $(currentTable.find("tr.nitdoc-qs-row")[currentIndex]).show();
-                               if(!hasNext(currentIndex)) {
-                                       currentTable.find("tr.nitdoc-qs-overflow-down").removeClass("nitdoc-qs-overflow-active");
-                               }
-                               resizeResultsTable();
-                       }
-               }
-       }
-
-       // Load selected search result page
-       var goToResult = function() {
-               if(currentIndex > -1) {
-                       window.location = $(currentTable.find("tr.nitdoc-qs-row")[currentIndex]).data("searchDetails").url;
-                       return;
-               }
-
-               if(searchField.val().length == 0) { return; }
-
-               window.location = "search.html#q=" + searchField.val();
-               if(window.location.href.indexOf("search.html") > -1) {
-                       location.reload();
-               }
-       }
-
-       // Close the results table
-       closeResultsTable = function(target) {
-               if(target != searchField && target != currentTable) {
-                       if(currentTable != null) {
-                               currentTable.remove();
-                               currentTable = null;
-                       }
-               }
-       }
-
-       // Public interface
-       var quicksearch = {
-               enableQuickSearch: enableQuickSearch,
-               doKeyUpAction: doKeyUpAction,
-               doKeyDownAction: doKeyDownAction,
-               closeResultsTable: closeResultsTable
-       };
-
-       return quicksearch;
-}();
-
-$(document).ready(function() {
-       Nitdoc.QuickSearch.enableQuickSearch("nav.main ul");
-});
-
-/*
- * Utils
- */
-
-String.prototype.startsWith = function(prefix, caseSensitive) {
-       if(caseSensitive) {
-               return this.toUpperCase().indexOf(prefix.toUpperCase()) === 0;
-       }
-    return this.indexOf(prefix) === 0;
-}
-
-// Compare two strings using Sorensen-Dice Coefficient
-// see: http://en.wikipedia.org/wiki/S%C3%B8rensen%E2%80%93Dice_coefficient
-String.prototype.dice = function(other) {
-       var length1 = this.length - 1;
-       var length2 = other.length - 1;
-       if(length1 < 1 || length2 < 1) return 0;
-
-       var bigrams2 = [];
-       for(var i = 0; i < length2; i++) {
-               bigrams2.push(other.substr(i, 2));
-       }
-
-       var intersection = 0;
-       for(var i = 0; i < length1; i++) {
-               var bigram1 = this.substr(i, 2);
-               for(var j = 0; j < length2; j++) {
-                       if(bigram1 == bigrams2[j]) {
-                               intersection++;
-                               bigrams2[j] = null;
-                               break;
-                       }
-               }
-       }
-       return (2.0 * intersection) / (length1 + length2);
-}
-