*/
/*
- * Nitdoc QuickSearch module
+ * Nitdoc QuickSearch widget
*/
-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();
- });
- },
+$.widget("nitdoc.quicksearch", {
- doKeyDownAction: function(key) {
- switch(key) {
- case 38: // Up
- this.selectPrevResult();
- return false;
- case 40: // Down
- this.selectNextResult();
- return false;
- default:
- return true;
- }
+ options: {
+ list: {}, // List of raw results generated by nitdoc tool
+ fieldAttrs: {
+ autocomplete: "off",
},
-
- doKeyUpAction: function(key) {
- switch(key) {
- case 38: // Up
- case 40: // Down
+ tableID: "nitdoc-qs-table",
+ tableCSS: {
+ "position": "absolute"
+ },
+ rowClass: "nitdoc-qs-row",
+ rowCatClass: "nitdoc-qs-cat",
+ rowSubClass: "nitdoc-qs-sub",
+ rowActiveClass: "nitdoc-qs-active",
+ rowOverflowClass: "nitdoc-qs-overflow",
+ rowOverflowActive: "nitdoc-qs-overflow-active",
+ rowNoResultClass: "nitdoc-qs-noresult",
+ overflowUpHtml: "▲",
+ overflowDownHtml: "▼",
+ noresultText: "Sorry, there is no match, best results are:",
+ infoClass: "nitdoc-qs-info",
+ gotoPage: "search.html",
+ maxSize: 10
+ },
+
+ _create: function() {
+ // set widget options
+ this.element.attr(this.options.fieldAttrs);
+ // event dispatch
+ this._on(this.element, {
+ "keydown": this._doKeyDown,
+ "keyup": this._doKeyUp,
+ "input": this._doInput
+ });
+ // add result table element once
+ this._table = $("<table/>")
+ .attr("id", this.options.tableID)
+ .css(this.options.tableCSS)
+ .css("min-width", this.element.outerWidth());
+ $("body").append(this._table);
+ // make table disappear when a click occurs outside
+ $(document).click($.proxy(this.closeTable, this));
+ },
+
+ /* events */
+
+ _doKeyDown: function(event) {
+ switch(event.keyCode) {
+ case 38: // Up
+ this._selectPrev();
+ return false;
+ case 40: // Down
+ this._selectNext();
+ return false;
+ default:
+ return true;
+ }
+ },
+
+ _doKeyUp: function(event) {
+ switch(event.keyCode) {
+ case 38: // Up
+ case 40: // Down
break;
+ case 13: // Enter
+ this._loadResult();
+ return false;
+ case 27: // Escape
+ this.element.blur();
+ this.closeTable();
+ return true;
+ default: // Other keys
+ return true;
+ }
+ },
- case 13: // Enter
- this.goToResult();
- return false;
- break;
+ _doInput: function(event) {
+ Utils.delayEvent($.proxy(this.search, this));
+ },
- case 27: // Escape
- $(this).blur();
- this.closeResultsTable();
- break;
+ /* Result lookup */
- default: // Other keys
- var query = this.searchField.val();
- if(!query) {
- return false;
- }
- var results = QuickSearch.getResults(query);
- this.displayResultsTable(query, results);
- break;
+ _getResults: function(query) {
+ var results = {};
+ results.matches = [];
+ for(var entry in this.options.list) {
+ if(!entry.startsWith(query, true)) {
+ continue;
}
- },
-
- // 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);
- }
+ var cat = {
+ name: entry,
+ entries: this.options.list[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.matches.sort(this._rankSorter);
+ results.partials = new Array();
+ if(results.matches.length == 0) {
+ for(var entry in this.options.list) {
+ var cat = {
+ name: entry,
+ entries: this.options.list[entry]
+ }
+ cat.rank = query.dice(entry);
+ if(cat.rank > 0) {
+ results.partials[results.partials.length] = cat;
}
- results.partials.sort(this.rankSorter);
}
- return results;
- },
+ results.partials.sort(this._rankSorter);
+ }
+ return results;
+ },
+
+ _rankSorter: function(a, b){
+ if(a.rank < b.rank) {
+ return 1;
+ } else if(a.rank > b.rank) {
+ return -1;
+ }
+ return 0;
+ },
- // 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;
- },
+ /* Results table */
- // 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];
+ search: function() {
+ var query = this.element.val();
+ if(query) {
+ var results = this._getResults(query);
+ this.openTable(query, results);
+ }
+ },
- 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("▲")
- )
- .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("▼")
- )
- .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:")
- )
- );
- }
+ openTable: function(query, results) {
+ this._table.empty();
+ this._rows = [];
+ this._index = -1;
- // Initialize table
- $("body").append(this.currentTable);
- this.resizeResultsTable();
- if(this.currentTable.find("tr").length > 0) {
- this.setIndex(0);
+ var resultSet = results.matches;
+ if(resultSet.length == 0) {
+ resultSet = results.partials
+ }
+
+ for(var i in resultSet) {
+ var cat = resultSet[i];
+ var result = cat.entries[0];
+ this.addRow(cat.name, result.txt, result.url, this.options.rowCatClass)
+ for(var j = 1; j < cat.entries.length; j++) {
+ var result = cat.entries[j];
+ this.addRow(cat.name, result.txt, result.url, this.options.rowSubClass)
}
- },
+ }
- // 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)
+ if(this._rows.length >= this.options.maxSize) {
+ this.addOverflowUp();
+ this.addOverflowDown();
+ }
+ if(results.matches.length == 0) {
+ this.addNoResultRow();
+ }
+
+ if(resultSet.length > 0) {
+ this._setIndex(0);
+ }
+ this._table.show();
+ this._autosizeTable();
+ },
+
+ closeTable: function(target) {
+ if(target != this.element && target != this._table) {
+ this._table.hide();
+ }
+ },
+
+ addRow: function(name, txt, url, cls) {
+ var row = $("<tr/>")
+ .addClass(this.options.rowClass)
+ .data("searchDetails", {name: name, url: url})
+ .data("index", this._rows.length)
+ .append(
+ $("<td/>")
+ .html(name)
.addClass(cls)
+ )
+ .append(
+ $("<td/>")
+ .html(txt + " »")
+ .addClass(this.options.infoClass)
+ )
+ .mouseover($.proxy(this._mouseOverRow, this))
+ .click($.proxy(this._clickRow, this))
+ this._rows.push(row);
+ if(this._rows.length >= this.options.maxSize) {
+ row.hide();
+ }
+ this._table.append(row);
+ },
+
+ addOverflowUp: function() {
+ this._table.prepend(
+ $("<tr/>")
+ .addClass(this.options.rowOverflowClass)
+ .append(
+ $("<td/>")
+ .attr("colspan", 2)
+ .html(this.options.overflowUpHtml)
)
+ .click($.proxy(this._clickPrev, this))
+ );
+ },
+
+ addOverflowDown: function() {
+ this._table.append(
+ $("<tr/>")
+ .addClass(this.options.rowOverflowClass)
+ .addClass(this.options.rowOverflowActive)
.append(
- $(document.createElement("td"))
- .addClass("nitdoc-qs-info")
- .html(txt + " »")
+ $("<td/>")
+ .attr("colspan", 2)
+ .html(this.options.overflowDownHtml)
)
- .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();
+ .click($.proxy(this._clickNext, this))
+ );
+ },
+
+ addNoResultRow: function() {
+ this._table.prepend(
+ $("<tr/>")
+ .addClass(this.options.rowNoResultClass)
+ .append(
+ $("<td/>")
+ .attr("colspan", "2")
+ .text(this.options.noresultText)
+ )
+ );
+ },
+
+ _autosizeTable: function() {
+ this._table.position({
+ my: "right top",
+ at: "right bottom",
+ of: this.element
+ });
+ },
+
+ _hasIndex: function(index) {
+ return index >= 0 && index < this._rows.length;
+ },
+
+ _hasPrev: function(index) {
+ return index - 1 >= 0;
+ },
+
+ _hasNext: function(index) {
+ return index + 1 < this._rows.length;
+ },
+
+ _setIndex: function(index) {
+ if(this._hasIndex(this._index)) {
+ this._rows[this._index].removeClass(this.options.rowActiveClass);
+ }
+ this._index = index;
+ if(this._hasIndex(this._index)) {
+ this._rows[this._index].addClass(this.options.rowActiveClass);
+ }
+ },
+
+ _selectPrev: function() {
+ if(this._hasPrev(this._index)) {
+ this._setIndex(this._index - 1);
+ if(!this._rows[this._index].is(":visible")) {
+ this._table.find("tr." + this.options.rowClass + ":visible").last().hide();
+ this._table.find("tr." + this.options.rowOverflowClass).addClass(this.options.rowOverflowActive);
+ this._rows[this._index].show();
+ if(!this._hasPrev(this._index)) {
+ this._table.find("tr." + this.options.rowOverflowClass).removeClass(this.options.rowOverflowActive);
}
+ this._autosizeTable();
}
- },
-
- 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();
+ }
+ },
+
+ _selectNext: function() {
+ if(this._hasNext(this._index)) {
+ this._setIndex(this._index + 1);
+ if(!this._rows[this._index].is(":visible")) {
+ this._table.find("tr." + this.options.rowClass + ":visible").first().hide();
+ this._table.find("tr." + this.options.rowOverflowClass).addClass(this.options.rowOverflowActive);
+ this._rows[this._index].show();
+ if(!this._hasNext(this._index)) {
+ this._table.find("tr." + this.options.rowOverflowClass).removeClass(this.options.rowOverflowActive);
}
+ this._autosizeTable();
}
- },
+ }
+ },
- // 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;
- }
+ // Load selected search result page
+ _loadResult: function() {
+ if(this._index > -1) {
+ window.location = this._rows[this._index].data("searchDetails").url;
+ return;
+ }
+ if(this.element.val().length == 0) { return; }
- if(this.searchField.val().length == 0) { return; }
+ window.location = this.options.gotoPage + "#q=" + this.element.val();
+ if(window.location.href.indexOf(this.options.gotoPage) > -1) {
+ location.reload();
+ }
+ },
- window.location = "search.html#q=" + this.searchField.val();
- if(window.location.href.indexOf("search.html") > -1) {
- location.reload();
- }
- },
+ /* table events */
- // Close the results table
- closeResultsTable: function(target) {
- if(target != this.searchField && target != this.currentTable) {
- if(this.currentTable != null) {
- this.currentTable.remove();
- this.currentTable = null;
- }
- }
- }
- };
+ _clickNext: function(event) {
+ event.stopPropagation();
+ this._selectNext();
+ },
+
+ _clickPrev: function(event) {
+ event.stopPropagation();
+ this._selectPrev();
+ },
+
+ _clickRow: function(event) {
+ window.location = $(event.currentTarget).data("searchDetails")["url"];
+ },
+
+ _mouseOverRow: function(event) {
+ this._setIndex($(event.currentTarget).data("index"));
+ }
+});
- QuickSearch.enableQuickSearch("nav.main ul");
+var searchField = $("<input/>")
+.addClass("form-control input-sm")
+.attr({
+ id: "nitdoc-qs-field",
+ type: "text",
+ placeholder: "Search..."
+})
+
+$("#topmenu-collapse").append(
+ $("<div>")
+ .addClass("navbar-form navbar-right")
+ .append(
+ $("<div>")
+ .addClass("form-group")
+ .append(searchField)
+ )
+);
+
+searchField.quicksearch({
+ list: this.nitdocQuickSearchRawList
});