*/
/*
- * Nitdoc QuickSearch module
+ * Nitdoc QuickSearch widget
*/
define([
"jquery",
+ "jQueryUI",
"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",
+], function($, ui, utils) {
+ $.widget("nitdoc.quicksearch", {
+
+ options: {
+ list: {}, // List of raw results generated by nitdoc tool
+ fieldNotUsedClass: "nitdoc-qs-field-notused",
+ fieldAttrs: {
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)
- );
+ },
+ 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
+ },
- // Close quicksearch list on click
- $(document).click(function(e) {
- QuickSearch.closeResultsTable();
- });
+ _create: function() {
+ this.element
+ .attr(this.options.fieldAttrs)
+ .addClass(this.options.fieldNotUsedClass)
+ .keydown($.proxy(this._doKeyDown, this))
+ .keyup($.proxy(this._doKeyUp, this))
+ .focusout($.proxy(this._doFocusOut, this))
+ .focusin($.proxy(this._doFocusIn, this));
+
+ this._table = $("<table/>")
+ .attr("id", this.options.tableID)
+ .css(this.options.tableCSS)
+ .css("min-width", this.element.outerWidth());
+ $("body").append(this._table);
+
+ $(document).click($.proxy(this.closeTable, this));
},
- doKeyDownAction: function(key) {
- switch(key) {
+ /* events */
+
+ _doKeyDown: function(event) {
+ switch(event.keyCode) {
case 38: // Up
- this.selectPrevResult();
+ this._selectPrev();
return false;
case 40: // Down
- this.selectNextResult();
+ this._selectNext();
return false;
default:
return true;
}
},
- doKeyUpAction: function(key) {
- switch(key) {
+ _doKeyUp: function(event) {
+ switch(event.keyCode) {
case 38: // Up
case 40: // Down
- break;
-
+ break;
case 13: // Enter
- this.goToResult();
- return false;
- break;
-
+ this._loadResult();
+ break;
case 27: // Escape
- $(this).blur();
- this.closeResultsTable();
- break;
-
+ this.element.blur();
+ this.closeTable();
+ break;
default: // Other keys
- var query = this.searchField.val();
- if(!query) {
- return false;
- }
- var results = QuickSearch.getResults(query);
- this.displayResultsTable(query, results);
- break;
+ this.search();
+ break;
}
},
- // Get results corresponding to search query
- getResults: function(query) {
+ _doFocusOut: function() {
+ if(this.element.val() == "") {
+ this.element.addClass(this.options.fieldNotUsedClass);
+ this.element.val(this.options.fieldAttrs.value);
+ }
+ },
+
+ _doFocusIn: function() {
+ if(this.element.val() == this.options.fieldAttrs.value) {
+ this.element.removeClass(this.options.fieldNotUsedClass);
+ this.element.val("");
+ }
+ },
+
+ /* Result lookup */
+
+ _getResults: function(query) {
var results = {};
- results.matches = new Array();
- for(var entry in this.rawList) {
+ results.matches = [];
+ for(var entry in this.options.list) {
if(!entry.startsWith(query, true)) {
continue;
}
- var cat = new Object();
- cat.name = entry;
- cat.entries = this.rawList[entry];
+ var cat = {
+ name: entry,
+ entries: this.options.list[entry]
+ };
results.matches[results.matches.length] = cat;
if(entry == query) {
cat.rank = 1 + query.dice(entry);
}
}
- results.matches.sort(this.rankSorter);
+ 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];
+ 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);
+ results.partials.sort(this._rankSorter);
}
return results;
},
- // Sort an array of results by rank
- rankSorter: function(a, b){
+ _rankSorter: function(a, b){
if(a.rank < b.rank) {
return 1;
} else if(a.rank > b.rank) {
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) {
+ /* Results table */
+
+ search: function() {
+ var query = this.element.val();
+ if(query) {
+ var results = this._getResults(query);
+ this.openTable(query, results);
+ }
+ },
+
+ openTable: function(query, results) {
+ this._table.empty();
+ this._rows = [];
+ this._index = -1;
+
+ var resultSet = results.matches;
+ if(resultSet.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++;
-
+ 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.addResultRow(count, cat.name, result.txt, result.url, "nitdoc-qs-sub")
- if(count >= maxSize) {
- this.currentTable.find("tr.nitdoc-qs-row").last().hide();
- }
- count++;
+ this.addRow(cat.name, result.txt, result.url, this.options.rowSubClass)
}
}
- 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(this._rows.length >= this.options.maxSize) {
+ this.addOverflowUp();
+ this.addOverflowDown();
}
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:")
- )
- );
+ this.addNoResultRow();
}
- // Initialize table
- $("body").append(this.currentTable);
- this.resizeResultsTable();
- if(this.currentTable.find("tr").length > 0) {
- this.setIndex(0);
+ if(resultSet.length > 0) {
+ this._setIndex(0);
}
+ this._table.show();
+ this._autosizeTable();
},
- // 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")
+ 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", index)
+ .data("index", this._rows.length)
.append(
- $(document.createElement("td")).html(name)
- .addClass(cls)
+ $("<td/>")
+ .html(name)
+ .addClass(cls)
)
.append(
- $(document.createElement("td"))
- .addClass("nitdoc-qs-info")
+ $("<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(
+ $("<td/>")
+ .attr("colspan", 2)
+ .html(this.options.overflowDownHtml)
+ )
+ .click($.proxy(this._clickNext, this))
+ );
+ },
+
+ addNoResultRow: function() {
+ this._table.prepend(
+ $("<tr/>")
+ .addClass(this.options.rowNoResultClass)
+ .append(
+ $("<td/>")
+ .attr("colspan", "2")
+ .text(this.options.noresultText)
)
- .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()
+ _autosizeTable: function() {
+ this._table.position({
+ my: "right top",
+ at: "right bottom",
+ of: this.element
});
},
- // 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);
+ _hasIndex: function(index) {
+ return index >= 0 && index < this._rows.length;
},
- hasPrev: function(index) {
+ _hasPrev: function(index) {
return index - 1 >= 0;
},
- hasNext: function(index) {
- return index + 1 < this.currentTable.find("tr.nitdoc-qs-row").length;
+ _hasNext: function(index) {
+ return index + 1 < this._rows.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");
+ _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.resizeResultsTable();
+ 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");
+ _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.resizeResultsTable();
+ 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;
+ _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 = "search.html#q=" + this.searchField.val();
- if(window.location.href.indexOf("search.html") > -1) {
+ window.location = this.options.gotoPage + "#q=" + this.element.val();
+ if(window.location.href.indexOf(this.options.gotoPage) > -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;
- }
- }
- }
- };
+ /* table events */
- QuickSearch.enableQuickSearch("nav.main ul");
+ _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"));
+ }
+ });
+
+ var searchField = $("<input/>")
+ .addClass("nitdoc-qs-field-notused")
+ .attr({
+ id: "nitdoc-qs-field",
+ type: "text",
+ })
+
+ $("nav.main ul").append(
+ $("<li/>")
+ .attr("id", "nitdoc-qs-li")
+ .append(searchField)
+ );
+
+ searchField.quicksearch({
+ list: this.nitdocQuickSearchRawList
+ });
});