Skip to content
This repository has been archived by the owner on Sep 6, 2021. It is now read-only.

Commit

Permalink
Merge pull request #2298 from adobe/nj/issue-1705
Browse files Browse the repository at this point in the history
Change dialog label for Quick Open based on mode
  • Loading branch information
jasonsanjose committed Dec 11, 2012
2 parents 7ba8722 + 59993eb commit 0164820
Showing 1 changed file with 109 additions and 49 deletions.
158 changes: 109 additions & 49 deletions src/search/QuickOpen.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,11 @@ define(function (require, exports, module) {

/** @type {boolean} */
var dialogOpen = false;

/**
* The currently open quick open dialog.
*/
var _curDialog;

/** Object representing a search result with associated metadata (added as extra ad hoc fields) */
function SearchResult(label) {
Expand All @@ -88,8 +93,7 @@ define(function (require, exports, module) {
/**
* Defines API for new QuickOpen plug-ins
*/
function QuickOpenPlugin(name, fileTypes, done, search, match, itemFocus, itemSelect, resultsFormatter) {

function QuickOpenPlugin(name, fileTypes, done, search, match, itemFocus, itemSelect, resultsFormatter) {
this.name = name;
this.fileTypes = fileTypes;
this.done = done;
Expand Down Expand Up @@ -151,6 +155,19 @@ define(function (require, exports, module) {
*/
function QuickNavigateDialog() {
this.$searchField = undefined; // defined when showDialog() is called

// Bind event handlers
this._handleItemSelect = this._handleItemSelect.bind(this);
this._handleItemFocus = this._handleItemFocus.bind(this);
this._handleKeyUp = this._handleKeyUp.bind(this);
this._handleKeyDown = this._handleKeyDown.bind(this);
this._handleResultsReady = this._handleResultsReady.bind(this);
this._handleBlur = this._handleBlur.bind(this);
this._handleDocumentMouseDown = this._handleDocumentMouseDown.bind(this);

// Bind callbacks from smart-autocomplete
this._filterCallback = this._filterCallback.bind(this);
this._resultsFormatterCallback = this._resultsFormatterCallback.bind(this);
}

/**
Expand Down Expand Up @@ -211,10 +228,10 @@ define(function (require, exports, module) {
}

// Smart Autocomplete uses this assumption internally: index of DOM node in results list container
// exactly matches index of search result in list returned by _handleFilter()
// exactly matches index of search result in list returned by _filterCallback()
var index = $(domItem).index();

// This is just the last return value of _handleFilter(), which smart autocomplete helpfully caches
// This is just the last return value of _filterCallback(), which smart autocomplete helpfully caches
var lastFilterResult = $("input#quickOpenSearch").data("smart-autocomplete").rawResults;
return lastFilterResult[index];
}
Expand All @@ -227,7 +244,7 @@ define(function (require, exports, module) {
* that may have not matched anything in in the list, but may have information
* for carrying out an action (e.g. go to line).
*/
QuickNavigateDialog.prototype._handleItemSelect = function (selectedDOMItem) {
QuickNavigateDialog.prototype._handleItemSelect = function (e, selectedDOMItem) {

// This is a work-around to select first item when a selection event occurs
// (usually from pressing the enter key) and no item is selected in the list.
Expand Down Expand Up @@ -274,7 +291,7 @@ define(function (require, exports, module) {
* Opens the file specified by selected item if there is no current plug-in, otherwise defers handling
* to the currentPlugin
*/
QuickNavigateDialog.prototype._handleItemFocus = function (selectedDOMItem) {
QuickNavigateDialog.prototype._handleItemFocus = function (e, selectedDOMItem) {
var selectedItem = domItemToSearchResult(selectedDOMItem);

if (currentPlugin) {
Expand Down Expand Up @@ -373,7 +390,7 @@ define(function (require, exports, module) {
/**
* Give visual clue when there are no results
*/
QuickNavigateDialog.prototype._handleResultsReady = function (results) {
QuickNavigateDialog.prototype._handleResultsReady = function (e, results) {
var isNoResults = (results.length === 0 && !this._isValidLineNumberQuery(this.$searchField.val()));
this.$searchField.toggleClass("no-results", isNoResults);
};
Expand All @@ -383,7 +400,6 @@ define(function (require, exports, module) {
* searching is done.
*/
QuickNavigateDialog.prototype._close = function () {

if (!dialogOpen) {
return;
}
Expand Down Expand Up @@ -417,7 +433,7 @@ define(function (require, exports, module) {

$(".smart_autocomplete_container").remove();

$(window.document).off("mousedown", this.handleDocumentMouseDown);
$(window.document).off("mousedown", this._handleDocumentMouseDown);
};

/**
Expand Down Expand Up @@ -717,7 +733,14 @@ define(function (require, exports, module) {
return filteredList;
}

function _handleFilter(query) {
/**
* Handles changes to the current query in the search field.
* @param {string} query The new query.
* @return {Array} The filtered list of results.
*/
QuickNavigateDialog.prototype._filterCallback = function (query) {
this._updateDialogLabel(query);

var curDoc = DocumentManager.getCurrentDocument();
if (curDoc) {
var filename = _filenameFromPath(curDoc.file.fullPath, true);
Expand All @@ -737,8 +760,7 @@ define(function (require, exports, module) {
// No plugin: use default file search mode
currentPlugin = null;
return searchFileList(query);
}

};

/**
* Formats item's label as properly escaped HTML text, highlighting sections that match 'query'.
Expand Down Expand Up @@ -804,8 +826,13 @@ define(function (require, exports, module) {
return "<li>" + displayName + "<br /><span class='quick-open-path'>" + displayPath + "</span></li>";
}

function _handleResultsFormatter(item) {
var query = $("input#quickOpenSearch").val();
/**
* Formats the entry for the given item to be displayed in the dropdown.
* @param {Object} item The item to be displayed.
* @return {string} The HTML to be displayed.
*/
QuickNavigateDialog.prototype._resultsFormatterCallback = function (item) {
var query = this.$searchField.val();

var formatter;

Expand All @@ -817,30 +844,60 @@ define(function (require, exports, module) {
formatter = _filenameResultsFormatter;
}
return formatter(item, query);
}
};

function setSearchFieldValue(prefix, initialString) {
/**
* Sets the value in the search field, updating the current mode and label based on the
* given prefix.
* @param {string} prefix The prefix that determines which mode we're in: must be empty (for file search),
* "@" for go to definition, or ":" for go to line.
* @param {string} initialString The query string to search for (without the prefix).
*/
QuickNavigateDialog.prototype.setSearchFieldValue = function (prefix, initialString) {
prefix = prefix || "";
initialString = initialString || "";
initialString = prefix + initialString;

var $field = $("input#quickOpenSearch");
if ($field) {
$field.val(initialString);
$field.get(0).setSelectionRange(prefix.length, initialString.length);

// Kick smart-autocomplete to update (it only listens for keyboard events)
// (due to #1855, this will only pop up results list; it won't auto-"focus" the first result)
$field.trigger("keyIn", [initialString]);
var $field = this.$searchField;
$field.val(initialString);
$field.get(0).setSelectionRange(prefix.length, initialString.length);

// Kick smart-autocomplete to update (it only listens for keyboard events)
// (due to #1855, this will only pop up results list; it won't auto-"focus" the first result)
$field.trigger("keyIn", [initialString]);

this._updateDialogLabel(initialString);
};

/**
* Sets the dialog label based on the type of the given query.
* @param {string} query The user's current query.
*/
QuickNavigateDialog.prototype._updateDialogLabel = function (query) {
var prefix = (query.length > 0 ? query.charAt(0) : "");

// Update the dialog label based on the current prefix.
var dialogLabel = "";
switch (prefix) {
case ":":
dialogLabel = Strings.CMD_GOTO_LINE;
break;
case "@":
dialogLabel = Strings.CMD_GOTO_DEFINITION;
break;
default:
dialogLabel = Strings.CMD_QUICK_OPEN;
break;
}
}
$(".find-dialog-label", this.dialog).text(dialogLabel);
};

/**
* Close the dialog when the user clicks outside of it. Smart-autocomplete listens for this and automatically closes its popup,
* but we want to close the whole search "dialog." (And we can't just piggyback on the popup closing event, since there are cases
* where the popup closes that we want the dialog to remain open (e.g. deleting search term via backspace).
*/
QuickNavigateDialog.prototype.handleDocumentMouseDown = function (e) {
QuickNavigateDialog.prototype._handleDocumentMouseDown = function (e) {
if ($(this.dialog).find(e.target).length === 0 && $(".smart_autocomplete_container").find(e.target).length === 0) {
this._close();
} else {
Expand All @@ -852,21 +909,25 @@ define(function (require, exports, module) {
}
}
};

/**
* Close the dialog when it loses focus.
*/
QuickNavigateDialog.prototype._handleBlur = function (e) {
this._close();
};

/**
* Shows the search dialog and initializes the auto suggestion list with filenames from the current project
*/
QuickNavigateDialog.prototype.showDialog = function (prefix, initialString) {
var that = this;

if (dialogOpen) {
return;
}
dialogOpen = true;

// Global listener to hide search bar & popup
this.handleDocumentMouseDown = this.handleDocumentMouseDown.bind(this);
$(window.document).on("mousedown", this.handleDocumentMouseDown);
$(window.document).on("mousedown", this._handleDocumentMouseDown);


// Ty TODO: disabled for now while file switching is disabled in _handleItemFocus
Expand All @@ -881,37 +942,36 @@ define(function (require, exports, module) {
} else {
origSelection = null;
}

// Show the search bar ("dialog")
var dialogHTML = Strings.CMD_QUICK_OPEN + ": <input type='text' autocomplete='off' id='quickOpenSearch' style='width: 30em'>";
that._createDialogDiv(dialogHTML);
that.$searchField = $("input#quickOpenSearch");

// Show the search bar ("dialog")
var dialogHTML = "<span class='find-dialog-label'></span>: <input type='text' autocomplete='off' id='quickOpenSearch' style='width: 30em'>";
this._createDialogDiv(dialogHTML);
this.$searchField = $("input#quickOpenSearch");

that.$searchField.smartAutoComplete({
this.$searchField.smartAutoComplete({
source: [],
maxResults: 20,
minCharLimit: 0,
autocompleteFocused: true,
forceSelect: false,
typeAhead: false, // won't work right now because smart auto complete
// using internal raw results instead of filtered results for matching
filter: _handleFilter,
resultFormatter: _handleResultsFormatter
filter: this._filterCallback,
resultFormatter: this._resultsFormatterCallback
});

that.$searchField.bind({
resultsReady: function (e, results) { that._handleResultsReady(results); },
itemSelect: function (e, selectedItem) { that._handleItemSelect(selectedItem); },
itemFocus: function (e, selectedItem) { that._handleItemFocus(selectedItem); },
keydown: function (e) { that._handleKeyDown(e); },
keyup: function (e, query) { that._handleKeyUp(e); },
blur: function (e) { that._close(); }
this.$searchField.bind({
resultsReady: this._handleResultsReady,
itemSelect: this._handleItemSelect,
itemFocus: this._handleItemFocus,
keydown: this._handleKeyDown,
keyup: this._handleKeyUp,
blur: this._handleBlur
// Note: lostFocus event DOESN'T work because auto smart complete catches the key up from shift-command-o and immediately
// triggers lostFocus
});

setSearchFieldValue(prefix, initialString);
this.setSearchFieldValue(prefix, initialString);

// Start fetching the file list, which will be needed the first time the user enters an un-prefixed query. If FileIndexManager's
// caches are out of date, this list might take some time to asynchronously build. See searchFileList() for how this is handled.
Expand All @@ -936,10 +996,10 @@ define(function (require, exports, module) {
*/
function beginSearch(prefix, initialString) {
if (dialogOpen) {
setSearchFieldValue(prefix, initialString);
_curDialog.setSearchFieldValue(prefix, initialString);
} else {
var dialog = new QuickNavigateDialog();
dialog.showDialog(prefix, initialString);
_curDialog = new QuickNavigateDialog();
_curDialog.showDialog(prefix, initialString);
}
}

Expand Down

0 comments on commit 0164820

Please sign in to comment.