Permalink
Browse files

Merge pull request #2314 from adobe/nj/issue-2095

INITIAL REVIEW: Move Find dialog out of editor
  • Loading branch information...
2 parents cc7e4c9 + 62a4da0 commit 99c76056d06d0011c793dd519f0e719e3c9f3298 @gruehle gruehle committed Dec 12, 2012
@@ -992,8 +992,13 @@ define(function (require, exports, module) {
/**
* Re-renders the editor UI
*/
- Editor.prototype.refresh = function () {
+ Editor.prototype.refresh = function (handleResize) {
this._codeMirror.refresh();
+ if (handleResize) {
+ // If the editor has been resized, the position of inline widgets relative to the
+ // browser window might have changed.
+ this._fireWidgetOffsetTopChanged(0);
+ }
};
/**
@@ -370,7 +370,7 @@ define(function (require, exports, module) {
if (_currentEditor) {
$(_currentEditor.getScrollerElement()).height(editorAreaHt);
if (!skipRefresh) {
- _currentEditor.refresh();
+ _currentEditor.refresh(true);
}
}
}
View
@@ -29,9 +29,6 @@
<!-- CSS/LESS -->
- <!-- CSS for CodeMirror search support, currently for debugging only -->
- <link rel="stylesheet" href="thirdparty/CodeMirror2/lib/util/dialog.css">
-
<!-- Temporary CSS for unobtrusive scrollbars. This can't live in LESS because it uses
nonstandard WebKit-specific syntax. -->
<link rel="stylesheet" href="styles/quiet-scrollbars.css">
@@ -78,9 +75,7 @@
<script src="thirdparty/CodeMirror2/lib/codemirror.js"></script>
<!-- JS for CodeMirror search support -->
- <script src="thirdparty/CodeMirror2/lib/util/dialog.js"></script>
<script src="thirdparty/CodeMirror2/lib/util/searchcursor.js"></script>
- <script src="thirdparty/CodeMirror2/lib/util/search.js"></script>
<script src="thirdparty/CodeMirror2/lib/util/closetag.js"></script>
</head>
@@ -53,7 +53,8 @@ define(function (require, exports, module) {
FileIndexManager = require("project/FileIndexManager"),
KeyEvent = require("utils/KeyEvent"),
AppInit = require("utils/AppInit"),
- StatusBar = require("widgets/StatusBar");
+ StatusBar = require("widgets/StatusBar"),
+ ModalBar = require("widgets/ModalBar").ModalBar;
var searchResults = [];
@@ -62,8 +63,9 @@ define(function (require, exports, module) {
function _getQueryRegExp(query) {
// Clear any pending RegEx error message
- $(".CodeMirror-dialog .alert-message").remove();
-
+ $(".modal-bar .message").css("display", "inline-block");
+ $(".modal-bar .error").css("display", "none");
+
// If query is a regular expression, use it directly
var isRE = query.match(/^\/(.*)\/(g|i)*$/);
if (isRE) {
@@ -75,7 +77,10 @@ define(function (require, exports, module) {
try {
return new RegExp(isRE[1], flags);
} catch (e) {
- $(".CodeMirror-dialog div").append("<div class='alert-message' style='margin-bottom: 0'>" + e.message + "</div>");
+ $(".modal-bar .message").css("display", "none");
+ $(".modal-bar .error")
+ .css("display", "inline-block")
+ .html("<div class='alert-message' style='margin-bottom: 0'>" + e.message + "</div>");
return null;
}
}
@@ -116,16 +121,6 @@ define(function (require, exports, module) {
}
/**
- * Creates a dialog div floating on top of the current code mirror editor
- */
- FindInFilesDialog.prototype._createDialogDiv = function (template) {
- this.dialog = $("<div />")
- .attr("class", "CodeMirror-dialog")
- .html("<div>" + template + "</div>")
- .prependTo($("#editor-holder"));
- };
-
- /**
* Closes the search dialog and resolves the promise that showDialog returned
*/
FindInFilesDialog.prototype._close = function (value) {
@@ -134,7 +129,7 @@ define(function (require, exports, module) {
}
this.closed = true;
- this.dialog.remove();
+ this.modalBar.close();
EditorManager.focusEditor();
this.result.resolve(value);
};
@@ -149,9 +144,9 @@ define(function (require, exports, module) {
// Note the prefix label is a simple "Find:" - the "in ..." part comes after the text field
var dialogHTML = Strings.CMD_FIND +
": <input type='text' id='findInFilesInput' style='width: 10em'> <span id='findInFilesScope'></span> &nbsp;" +
- "<span style='color: #888'>(" + Strings.SEARCH_REGEXP_INFO + ")</span>";
+ "<div class='message'><span style='color: #888'>(" + Strings.SEARCH_REGEXP_INFO + ")</span></div><div class='error'></div>";
this.result = new $.Deferred();
- this._createDialogDiv(dialogHTML);
+ this.modalBar = new ModalBar(dialogHTML, false);
var $searchField = $("input#findInFilesInput");
var that = this;
@@ -29,23 +29,16 @@
* Adds Find and Replace commands
*
* Originally based on the code in CodeMirror2/lib/util/search.js.
- *
- * Define search commands. Depends on dialog.js or another
- * implementation of the openDialog method.
- *
- * Replace works a little oddly -- it will do the replace on the next findNext press.
- * You prevent a replace by making sure the match is no longer selected when hitting
- * findNext.
- *
*/
define(function (require, exports, module) {
"use strict";
var CommandManager = require("command/CommandManager"),
Commands = require("command/Commands"),
Strings = require("strings"),
- EditorManager = require("editor/EditorManager");
-
+ EditorManager = require("editor/EditorManager"),
+ ModalBar = require("widgets/ModalBar").ModalBar;
+
function SearchState() {
this.posFrom = this.posTo = this.query = null;
this.marked = [];
@@ -62,34 +55,22 @@ define(function (require, exports, module) {
// Heuristic: if the query string is all lowercase, do a case insensitive search.
return cm.getSearchCursor(query, pos, typeof query === "string" && query === query.toLowerCase());
}
-
- function dialog(cm, text, shortText, f) {
- if (cm.openDialog) {
- cm.openDialog(text, f);
- } else {
- f(prompt(shortText, ""));
- }
- }
-
- function confirmDialog(cm, text, shortText, fs) {
- if (cm.openConfirm) {
- cm.openConfirm(text, fs);
- } else if (confirm(shortText)) {
- fs[0]();
- }
- }
- function getDialogTextField() {
- return $(".CodeMirror-dialog input[type='text']");
+ function getDialogTextField(modalBar) {
+ return $("input[type='text']", modalBar.getRoot());
}
function parseQuery(query) {
var isRE = query.match(/^\/(.*)\/([a-z]*)$/);
- $(".CodeMirror-dialog .alert-message").remove();
+ $(".modal-bar .message").css("display", "inline-block");
+ $(".modal-bar .error").css("display", "none");
try {
return isRE ? new RegExp(isRE[1], isRE[2].indexOf("i") === -1 ? "" : "i") : query;
} catch (e) {
- $(".CodeMirror-dialog div").append("<div class='alert-message' style='margin-bottom: 0'>" + e.message + "</div>");
+ $(".modal-bar .message").css("display", "none");
+ $(".modal-bar .error")
+ .css("display", "inline-block")
+ .html("<div class='alert-message' style='margin-bottom: 0'>" + e.message + "</div>");
return "";
}
}
@@ -136,8 +117,8 @@ define(function (require, exports, module) {
}
var queryDialog = Strings.CMD_FIND +
- ': <input type="text" style="width: 10em"/> <span style="color: #888">(' +
- Strings.SEARCH_REGEXP_INFO + ')</span>';
+ ': <input type="text" style="width: 10em"/> <div class="message"><span style="color: #888">(' +
+ Strings.SEARCH_REGEXP_INFO + ')</span></div><div class="error"></div>';
/**
* If no search pending, opens the search dialog. If search is already open, moves to
@@ -157,7 +138,7 @@ define(function (require, exports, module) {
// Called each time the search query changes while being typed. Jumps to the first matching
// result, starting from the original cursor position
- function findFirst(query) {
+ function findFirst(query, modalBar) {
cm.operation(function () {
if (!query) {
return;
@@ -180,55 +161,61 @@ define(function (require, exports, module) {
state.posFrom = state.posTo = searchStartPos;
var foundAny = findNext(cm, rev);
- getDialogTextField().toggleClass("no-results", !foundAny);
+ getDialogTextField(modalBar).toggleClass("no-results", !foundAny);
});
}
- dialog(cm, queryDialog, Strings.CMD_FIND, function (query) {
+ var modalBar = new ModalBar(queryDialog, true);
+ $(modalBar).on("closeOk", function (e, query) {
if (!state.findNextCalled) {
// If findNextCalled is false, this means the user has *not*
// entered any search text *or* pressed Cmd-G/F3 to find the
// next occurrence. In this case we want to start searching
// *after* the current selection so we find the next occurrence.
searchStartPos = cm.getCursor(false);
- findFirst(query);
+ findFirst(query, modalBar);
}
});
+ var $input = getDialogTextField(modalBar);
+ $input.on("input", function () {
+ findFirst($input.attr("value"), modalBar);
+ });
+
// Prepopulate the search field with the current selection, if any.
if (initialQuery !== undefined) {
- getDialogTextField()
+ $input
.attr("value", initialQuery)
.get(0).select();
- findFirst(initialQuery);
+ findFirst(initialQuery, modalBar);
// Clear the "findNextCalled" flag here so we have a clean start
state.findNextCalled = false;
}
-
- getDialogTextField().on("input", function () {
- findFirst(getDialogTextField().attr("value"));
- });
}
var replaceQueryDialog = Strings.CMD_REPLACE +
- ': <input type="text" style="width: 10em"/> <span style="color: #888">(' +
- Strings.SEARCH_REGEXP_INFO + ')</span>';
+ ': <input type="text" style="width: 10em"/> <div class="message"><span style="color: #888">(' +
+ Strings.SEARCH_REGEXP_INFO + ')</span></div><div class="error"></div>';
var replacementQueryDialog = Strings.WITH +
': <input type="text" style="width: 10em"/>';
// style buttons to match height/margins/border-radius of text input boxes
var style = ' style="padding:5px 15px;border:1px #999 solid;border-radius:3px;margin:2px 2px 5px;"';
var doReplaceConfirm = Strings.CMD_REPLACE +
- '? <button' + style + '>' + Strings.BUTTON_YES +
- '</button> <button' + style + '>' + Strings.BUTTON_NO +
+ '? <button id="replace-yes"' + style + '>' + Strings.BUTTON_YES +
+ '</button> <button id="replace-no"' + style + '>' + Strings.BUTTON_NO +
'</button> <button' + style + '>' + Strings.BUTTON_STOP + '</button>';
function replace(cm, all) {
- dialog(cm, replaceQueryDialog, Strings.CMD_REPLACE, function (query) {
+ var modalBar = new ModalBar(replaceQueryDialog, true);
+ $(modalBar).on("closeOk", function (e, query) {
if (!query) {
return;
}
+
query = parseQuery(query);
- dialog(cm, replacementQueryDialog, Strings.WITH, function (text) {
+ modalBar = new ModalBar(replacementQueryDialog, true);
+ $(modalBar).on("closeOk", function (e, text) {
+ text = text || "";
var match,
fnMatch = function (w, i) { return match[i]; };
if (all) {
@@ -260,8 +247,15 @@ define(function (require, exports, module) {
}
}
cm.setSelection(cursor.from(), cursor.to());
- confirmDialog(cm, doReplaceConfirm, Strings.CMD_REPLACE + "?",
- [function () { doReplace(match); }, advance]);
+ modalBar = new ModalBar(doReplaceConfirm, true);
+ modalBar.getRoot().on("click", function (e) {
+ modalBar.close();
+ if (e.target.id === "replace-yes") {
+ doReplace(match);
+ } else if (e.target.id === "replace-no") {
+ advance();
+ }
+ });
};
var doReplace = function (match) {
cursor.replace(typeof query === "string" ? text :
@@ -273,8 +267,8 @@ define(function (require, exports, module) {
});
});
- // Prepopulate the replace field with the current selection, if any.
- getDialogTextField()
+ // Prepopulate the replace field with the current selection, if any
+ getDialogTextField(modalBar)
.attr("value", cm.getSelection())
.get(0).select();
}
@@ -47,7 +47,8 @@ define(function (require, exports, module) {
StringUtils = require("utils/StringUtils"),
Commands = require("command/Commands"),
ProjectManager = require("project/ProjectManager"),
- KeyEvent = require("utils/KeyEvent");
+ KeyEvent = require("utils/KeyEvent"),
+ ModalBar = require("widgets/ModalBar").ModalBar;
/** @type Array.<QuickOpenPlugin> */
@@ -170,16 +171,6 @@ define(function (require, exports, module) {
this._resultsFormatterCallback = this._resultsFormatterCallback.bind(this);
}
- /**
- * Creates a dialog div floating on top of the current code mirror editor
- */
- QuickNavigateDialog.prototype._createDialogDiv = function (template) {
- this.dialog = $("<div />")
- .attr("class", "CodeMirror-dialog")
- .html("<div align='right'>" + template + "</div>")
- .prependTo($("#editor-holder"));
- };
-
function _filenameFromPath(path, includeExtension) {
var end;
if (includeExtension) {
@@ -423,12 +414,10 @@ define(function (require, exports, module) {
// Closing the dialog is a little tricky (see #1384): some Smart Autocomplete code may run later (e.g.
// (because it's a later handler of the event that just triggered _close()), and that code expects to
// find metadata that it stuffed onto the DOM node earlier. But $.remove() strips that metadata.
- // So, to hide the dialog immediately it's only safe to remove using raw DOM APIs:
- this.dialog[0].parentNode.removeChild(this.dialog[0]);
+ // So we wait until after this call chain is complete before actually closing the dialog.
var self = this;
setTimeout(function () {
- // Now that it's safe, call the real jQuery API to clear the metadata & prevent a memory leak
- self.dialog.remove();
+ self.modalBar.close();
}, 0);
$(".smart_autocomplete_container").remove();
@@ -898,7 +887,7 @@ define(function (require, exports, module) {
* where the popup closes that we want the dialog to remain open (e.g. deleting search term via backspace).
*/
QuickNavigateDialog.prototype._handleDocumentMouseDown = function (e) {
- if ($(this.dialog).find(e.target).length === 0 && $(".smart_autocomplete_container").find(e.target).length === 0) {
+ if (this.modalBar.getRoot().find(e.target).length === 0 && $(".smart_autocomplete_container").find(e.target).length === 0) {
this._close();
} else {
// Allow clicks in the search field to propagate. Clicks in the menu should be
@@ -944,8 +933,8 @@ define(function (require, exports, module) {
}
// 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);
+ var dialogHTML = "<div align='right'><span class='find-dialog-label'></span>: <input type='text' autocomplete='off' id='quickOpenSearch' style='width: 30em'></div>";
+ this.modalBar = new ModalBar(dialogHTML, false);
this.$searchField = $("input#quickOpenSearch");
this.$searchField.smartAutoComplete({
Oops, something went wrong.

0 comments on commit 99c7605

Please sign in to comment.