From f1c4c42c290ffb3b60d739a7d787149e70702be5 Mon Sep 17 00:00:00 2001 From: Alexandre Terrasa Date: Wed, 12 Feb 2014 22:25:01 -0500 Subject: [PATCH] nitdoc: migrate quicksearch to jQuery.UI widget Signed-off-by: Alexandre Terrasa --- share/nitdoc/js/plugins/quicksearch.js | 489 +++++++++++++++------------- share/nitdoc/styles/Nitdoc.QuickSearch.css | 7 +- 2 files changed, 264 insertions(+), 232 deletions(-) diff --git a/share/nitdoc/js/plugins/quicksearch.js b/share/nitdoc/js/plugins/quicksearch.js index a3b29c1..db7d693 100644 --- a/share/nitdoc/js/plugins/quicksearch.js +++ b/share/nitdoc/js/plugins/quicksearch.js @@ -17,112 +17,120 @@ */ /* - * 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, // search field - currentTable: null, // current search results - 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 = $("
") + .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) { @@ -133,25 +141,25 @@ define([ 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) { @@ -160,202 +168,229 @@ define([ 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( - $("") - .append( - $("") + .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) + $("") + .addClass(this.options.rowOverflowClass) + .append( + $("") + .addClass(this.options.rowOverflowClass) + .addClass(this.options.rowOverflowActive) + .append( + $("") + .addClass(this.options.rowNoResultClass) + .append( + $("
") - .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 = $("
") + .html(name) + .addClass(cls) ) .append( - $(document.createElement("td")) - .addClass("nitdoc-qs-info") + $("") .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( + $("
") + .attr("colspan", 2) + .html(this.options.overflowUpHtml) + ) + .click($.proxy(this._clickPrev, this)) + ); + }, + + addOverflowDown: function() { + this._table.append( + $("
") + .attr("colspan", 2) + .html(this.options.overflowDownHtml) + ) + .click($.proxy(this._clickNext, this)) + ); + }, + + addNoResultRow: function() { + this._table.prepend( + $("
") + .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 = $("") + .addClass("nitdoc-qs-field-notused") + .attr({ + id: "nitdoc-qs-field", + type: "text", + }) + + $("nav.main ul").append( + $("
  • ") + .attr("id", "nitdoc-qs-li") + .append(searchField) + ); + + searchField.quicksearch({ + list: this.nitdocQuickSearchRawList + }); }); diff --git a/share/nitdoc/styles/Nitdoc.QuickSearch.css b/share/nitdoc/styles/Nitdoc.QuickSearch.css index b0a434c..42b3925 100644 --- a/share/nitdoc/styles/Nitdoc.QuickSearch.css +++ b/share/nitdoc/styles/Nitdoc.QuickSearch.css @@ -55,7 +55,6 @@ overflow: hidden; line-height: 22px; padding: 2px; - width: 25%; } #nitdoc-qs-table td.nitdoc-qs-sub { @@ -65,8 +64,7 @@ #nitdoc-qs-table td.nitdoc-qs-info { color: #0D8921; - font-size: small; - width: 75%; + font-size: smaller; text-align: right; } @@ -76,8 +74,7 @@ line-height: 15px; } -#nitdoc-qs-table tr.nitdoc-qs-overflow-up td, -#nitdoc-qs-table tr.nitdoc-qs-overflow-down td { +#nitdoc-qs-table tr.nitdoc-qs-overflow td { text-align: center; font-size: x-small; line-height: 10px; -- 1.7.9.5