diff --git a/src/editor/CSSInlineEditor.js b/src/editor/CSSInlineEditor.js index bc8411da2fb..e1548aa1e73 100644 --- a/src/editor/CSSInlineEditor.js +++ b/src/editor/CSSInlineEditor.js @@ -75,21 +75,21 @@ define(function (require, exports, module) { // class="error-dialog modal hide" // and the insertion point is inside "modal", we want ".modal" var attributeValue = tagInfo.attr.value; - var startIndex = attributeValue.substr(0, tagInfo.position.offset).lastIndexOf(" "); - var endIndex = attributeValue.indexOf(" ", tagInfo.position.offset); - selectorName = "." + - attributeValue.substring( - startIndex === -1 ? 0 : startIndex + 1, - endIndex === -1 ? attributeValue.length : endIndex - ); - - // If the insertion point is surrounded by space, selectorName is "." - // Check for that here - if (selectorName === ".") { - selectorName = ""; - } - - if (selectorName === "") { + if (attributeValue.trim()) { + var startIndex = attributeValue.substr(0, tagInfo.position.offset).lastIndexOf(" "); + var endIndex = attributeValue.indexOf(" ", tagInfo.position.offset); + selectorName = "." + + attributeValue.substring( + startIndex === -1 ? 0 : startIndex + 1, + endIndex === -1 ? attributeValue.length : endIndex + ); + + // If the insertion point is surrounded by space between two classnames, selectorName is "." + if (selectorName === ".") { + selectorName = ""; + reason = Strings.ERROR_CSSQUICKEDIT_BETWEENCLASSES; + } + } else { reason = Strings.ERROR_CSSQUICKEDIT_CLASSNOTFOUND; } } else if (tagInfo.attr.name === "id") { @@ -160,9 +160,9 @@ define(function (require, exports, module) { * * @param {!Editor} editor * @param {!{line:Number, ch:Number}} pos - * @return {?$.Promise} synchronously resolved with an InlineWidget, or - * {string} if pos is in tag but not in tag name, class attr, or id attr, or - * null if we're not going to provide anything. + * @return {?$.Promise} synchronously resolved with an InlineWidget; or error + * {string} if pos is in tag but not in tag name, class attr, or id attr; or null if the + * selection isn't even close to a context where we could provide anything. */ function htmlToCSSProvider(hostEditor, pos) { diff --git a/src/editor/EditorManager.js b/src/editor/EditorManager.js index 4723e28dcac..b47d1b32ddc 100644 --- a/src/editor/EditorManager.js +++ b/src/editor/EditorManager.js @@ -164,7 +164,7 @@ define(function (require, exports, module) { * @param {!Editor} editor The host editor * @param {Array.<{priority:number, provider:function(...)}>} providers * prioritized list of providers - * @param {string=} defaultErrorMsg Default error message to display if no initial provider found + * @param {string=} defaultErrorMsg Default message to display if no providers return non-null * @return {$.Promise} a promise that will be resolved when an InlineWidget * is created or rejected if no inline providers have offered one. */ @@ -279,10 +279,10 @@ define(function (require, exports, module) { * An optional priority parameter is used to give providers with higher priority an opportunity * to provide an inline editor before providers with lower priority. * - * @param {function(!Editor, !{line:number, ch:number}):?$.Promise} provider + * @param {function(!Editor, !{line:number, ch:number}):?($.Promise|string)} provider * @param {number=} priority - * The provider returns a promise that will be resolved with an InlineWidget, or returns null - * to indicate the provider doesn't want to respond to this case. + * The provider returns a promise that will be resolved with an InlineWidget, or returns a string + * indicating why the provider cannot respond to this case (or returns null to indicate no reason). */ function registerInlineEditProvider(provider, priority) { if (priority === undefined) { @@ -297,10 +297,10 @@ define(function (require, exports, module) { * An optional priority parameter is used to give providers with higher priority an opportunity * to provide an inline editor before providers with lower priority. * - * @param {function(!Editor, !{line:number, ch:number}):?$.Promise} provider + * @param {function(!Editor, !{line:number, ch:number}):?($.Promise|string)} provider * @param {number=} priority - * The provider returns a promise that will be resolved with an InlineWidget, or returns null - * to indicate the provider doesn't want to respond to this case. + * The provider returns a promise that will be resolved with an InlineWidget, or returns a string + * indicating why the provider cannot respond to this case (or returns null to indicate no reason). */ function registerInlineDocsProvider(provider, priority) { if (priority === undefined) { @@ -946,7 +946,7 @@ define(function (require, exports, module) { * * @param {Array.<{priority:number, provider:function(...)}>} providers * prioritized list of providers - * @param {string=} errorMsg Error message to display if no initial provider found + * @param {string=} errorMsg Default message to display if no providers return non-null * @return {!Promise} A promise resolved with true if an inline widget is opened or false * when closed. Rejected if there is neither an existing widget to close nor a provider * willing to create a widget (or if no editor is open). diff --git a/src/extensions/default/JavaScriptQuickEdit/main.js b/src/extensions/default/JavaScriptQuickEdit/main.js index f93bd45e0dd..5b0303ea08f 100644 --- a/src/extensions/default/JavaScriptQuickEdit/main.js +++ b/src/extensions/default/JavaScriptQuickEdit/main.js @@ -41,8 +41,8 @@ define(function (require, exports, module) { * Return the token string that is at the specified position. * * @param hostEditor {!Editor} editor - * @param {!{line:Number, ch:Number}} pos - * @return {functionName: {string}, reason: {string}} + * @param {!{line:number, ch:number}} pos + * @return {functionName: string, reason: string} */ function _getFunctionName(hostEditor, pos) { var token = hostEditor._codeMirror.getTokenAt(pos, true); @@ -109,7 +109,7 @@ define(function (require, exports, module) { * @param {!string} functionName * @return {?$.Promise} synchronously resolved with an InlineWidget, or * {string} if js other than function is detected at pos, or - * null if we're not going to provide anything. + * null if we're not ready to provide anything. */ function _createInlineEditor(hostEditor, functionName) { // Use Tern jump-to-definition helper, if it's available, to find InlineEditor target. @@ -186,9 +186,9 @@ define(function (require, exports, module) { * and shows (one/all of them) in an inline editor. * * @param {!Editor} editor - * @param {!{line:Number, ch:Number}} pos + * @param {!{line:number, ch:number}} pos * @return {$.Promise} a promise that will be resolved with an InlineWidget - * or null if we're not going to provide anything. + * or null if we're not ready to provide anything. */ function javaScriptFunctionProvider(hostEditor, pos) { // Only provide a JavaScript editor when cursor is in JavaScript content diff --git a/src/nls/root/strings.js b/src/nls/root/strings.js index 8e76da3f0ac..7c19bff8b81 100644 --- a/src/nls/root/strings.js +++ b/src/nls/root/strings.js @@ -180,15 +180,16 @@ define({ "FILE_FILTER_CLIPPED_SUFFIX" : "and {0} more", // Quick Edit - "ERROR_QUICK_EDIT_PROVIDER_NOT_FOUND" : "No Quick Edit provider found for current cursor position", - "ERROR_CSSQUICKEDIT_CLASSNOTFOUND" : "CSS Quick Edit: place cursor in class name", - "ERROR_CSSQUICKEDIT_IDNOTFOUND" : "CSS Quick Edit: place cursor in id name", - "ERROR_CSSQUICKEDIT_UNSUPPORTEDATTR" : "CSS Quick Edit: place cursor in tag name, class name, or id name", + "ERROR_QUICK_EDIT_PROVIDER_NOT_FOUND" : "No Quick Edit available for current cursor position", + "ERROR_CSSQUICKEDIT_BETWEENCLASSES" : "CSS Quick Edit: place cursor on a single class name", + "ERROR_CSSQUICKEDIT_CLASSNOTFOUND" : "CSS Quick Edit: incomplete class attribute", + "ERROR_CSSQUICKEDIT_IDNOTFOUND" : "CSS Quick Edit: incomplete id attribute", + "ERROR_CSSQUICKEDIT_UNSUPPORTEDATTR" : "CSS Quick Edit: place cursor in tag, class, or id", "ERROR_TIMINGQUICKEDIT_INVALIDSYNTAX" : "CSS Timing Function Quick Edit: invalid syntax", "ERROR_JSQUICKEDIT_FUNCTIONNOTFOUND" : "JS Quick Edit: place cursor in function name", // Quick Docs - "ERROR_QUICK_DOCS_PROVIDER_NOT_FOUND" : "No Quick Docs provider found for current cursor position", + "ERROR_QUICK_DOCS_PROVIDER_NOT_FOUND" : "No Quick Docs available for current cursor position", /** * ProjectManager diff --git a/src/project/FileSyncManager.js b/src/project/FileSyncManager.js index cb60ec412d1..6a29fcd3e80 100644 --- a/src/project/FileSyncManager.js +++ b/src/project/FileSyncManager.js @@ -29,9 +29,12 @@ * FileSyncManager is a set of utilities to help track external modifications to the files and folders * in the currently open project. * - * Currently, we look for external changes purely by checking file timestamps against the last-sync - * timestamp recorded on Document. Later, we will use actual native directory-watching callbacks - * instead. + * Currently, we detect external changes purely by checking file timestamps against the last-sync + * timestamp recorded on Document. Brackets triggers this check whenever an external change was detected + * by our native file watchers, and on window focus. We recheck all open Documents, but with file caching + * the timestamp check is a fast no-op for everything other than files where a watcher change was just + * notified. If watchers/caching are disabled, we'll essentially check only on window focus, and we'll hit + * the disk to check every open Document's timestamp every time. * * FUTURE: Whenever we have a 'project file tree model,' we should manipulate that instead of notifying * DocumentManager directly. DocumentManager, the tree UI, etc. then all listen to that model for changes.