diff --git a/src/LiveDevelopment/LiveDevelopment.js b/src/LiveDevelopment/LiveDevelopment.js
index 05195267bcb..72eb05ea64b 100644
--- a/src/LiveDevelopment/LiveDevelopment.js
+++ b/src/LiveDevelopment/LiveDevelopment.js
@@ -568,7 +568,7 @@ define(function LiveDevelopment(require, exports, module) {
// After (1) the interstitial page loads, (2) then browser navigation
// to the base URL is completed, and (3) the agents finish loading
// gather related documents and finally set status to STATUS_ACTIVE.
- var doc = _getCurrentDocument(); // TODO: probably wrong...
+ var doc = _liveDocument.doc;
if (doc) {
var status = STATUS_ACTIVE,
diff --git a/src/editor/Editor.js b/src/editor/Editor.js
index b0822549922..1776c954567 100644
--- a/src/editor/Editor.js
+++ b/src/editor/Editor.js
@@ -140,10 +140,18 @@ define(function (require, exports, module) {
if (indentAuto) {
var currentLength = line.length;
CodeMirror.commands.indentAuto(instance);
- // If the amount of whitespace didn't change, insert another tab
+
+ // If the amount of whitespace and the cursor position didn't change, we must have
+ // already been at the correct indentation level as far as CM is concerned, so insert
+ // another tab.
if (instance.getLine(from.line).length === currentLength) {
- insertTab = true;
- to.ch = 0;
+ var newFrom = instance.getCursor(true),
+ newTo = instance.getCursor(false);
+ if (newFrom.line === from.line && newFrom.ch === from.ch &&
+ newTo.line === to.line && newTo.ch === to.ch) {
+ insertTab = true;
+ to.ch = 0;
+ }
}
} else if (instance.somethingSelected() && from.line !== to.line) {
CodeMirror.commands.indentMore(instance);
@@ -978,21 +986,10 @@ define(function (require, exports, module) {
return;
}
- // Handle hiding a single blank line at the end specially by moving the "from" backwards
- // to include the last newline. Otherwise CodeMirror doesn't hide anything in this case.
- var hideFrom, inclusiveLeft = true;
- if (from === to - 1 && from === this._codeMirror.lineCount() - 1 && this._codeMirror.getLine(from).length === 0) {
- hideFrom = {line: from - 1, ch: this._codeMirror.getLine(from - 1).length};
- // Allow the cursor to be set immediately before the hidden newline.
- inclusiveLeft = false;
- } else {
- hideFrom = {line: from, ch: 0};
- }
-
var value = this._codeMirror.markText(
- hideFrom,
+ {line: from, ch: 0},
{line: to - 1, ch: this._codeMirror.getLine(to - 1).length},
- {collapsed: true, inclusiveLeft: inclusiveLeft, inclusiveRight: true}
+ {collapsed: true, inclusiveLeft: true, inclusiveRight: true}
);
return value;
diff --git a/src/editor/ImageViewer.js b/src/editor/ImageViewer.js
index a32fff31c45..39954c2db4b 100644
--- a/src/editor/ImageViewer.js
+++ b/src/editor/ImageViewer.js
@@ -98,12 +98,12 @@ define(function (require, exports, module) {
$("#img-preview").on("load", function () {
// add dimensions and size
_naturalWidth = this.naturalWidth;
- var dimensionString = _naturalWidth + " x " + this.naturalHeight + " " + Strings.UNIT_PIXELS;
+ var dimensionString = _naturalWidth + " × " + this.naturalHeight + " " + Strings.UNIT_PIXELS;
// get image size
var file = FileSystem.getFileForPath(fullPath);
file.stat(function (err, stat) {
if (err) {
- $("#img-data").text(dimensionString);
+ $("#img-data").html(dimensionString);
} else {
var sizeString = "";
if (stat.size) {
diff --git a/src/extensions/default/QuickView/main.js b/src/extensions/default/QuickView/main.js
index 36a6d219a81..7deef06e46c 100644
--- a/src/extensions/default/QuickView/main.js
+++ b/src/extensions/default/QuickView/main.js
@@ -450,7 +450,7 @@ define(function (require, exports, module) {
$previewContainer.find(".image-preview > img").on("load", function () {
$previewContent
.append("
" +
- this.naturalWidth + " x " + this.naturalHeight + " " + Strings.UNIT_PIXELS +
+ this.naturalWidth + " × " + this.naturalHeight + " " + Strings.UNIT_PIXELS +
"
"
);
$previewContainer.show();
diff --git a/src/extensions/default/UrlCodeHints/main.js b/src/extensions/default/UrlCodeHints/main.js
index ec88e0d178e..af33eba7be5 100644
--- a/src/extensions/default/UrlCodeHints/main.js
+++ b/src/extensions/default/UrlCodeHints/main.js
@@ -139,9 +139,10 @@ define(function (require, exports, module) {
// convert to doc relative path
var entryStr = entry.fullPath.replace(docDir, "");
- // code hints show the same strings that are inserted into text,
- // so strings in list will be encoded. wysiwyg, baby!
- unfiltered.push(encodeURI(entryStr));
+ // code hints show the unencoded string so the
+ // choices are easier to read. The encoded string
+ // will still be inserted into the editor.
+ unfiltered.push(entryStr);
}
});
@@ -225,7 +226,7 @@ define(function (require, exports, module) {
};
/**
- * Determines whether font hints are available in the current editor
+ * Determines whether url hints are available in the current editor
* context.
*
* @param {Editor} editor
@@ -361,7 +362,7 @@ define(function (require, exports, module) {
};
/**
- * Returns a list of availble font hints, if possible, for the current
+ * Returns a list of available url hints, if possible, for the current
* editor context.
*
* @return {jQuery.Deferred|{
@@ -504,6 +505,10 @@ define(function (require, exports, module) {
*/
UrlCodeHints.prototype.insertHint = function (completion) {
var mode = this.editor.getModeForSelection();
+
+ // Encode the string just prior to inserting the hint into the editor
+ completion = encodeURI(completion);
+
if (mode === "html") {
return this.insertHtmlHint(completion);
} else if (mode === "css") {
@@ -754,4 +759,11 @@ define(function (require, exports, module) {
// For unit testing
exports.hintProvider = urlHints;
});
+
+ $(ProjectManager).on("projectFilesChange", function (event, projectRoot) {
+ // Cache may or may not be stale. Main benefit of cache is to limit async lookups
+ // during typing. File tree updates cannot happen during typing, so it's probably
+ // not worth determining whether cache may still be valid. Just delete it.
+ exports.hintProvider.cachedHints = null;
+ });
});
diff --git a/src/extensions/default/WebPlatformDocs/WebPlatformDocs.less b/src/extensions/default/WebPlatformDocs/WebPlatformDocs.less
index 29c6c67e9d9..b7ef4e1df93 100644
--- a/src/extensions/default/WebPlatformDocs/WebPlatformDocs.less
+++ b/src/extensions/default/WebPlatformDocs/WebPlatformDocs.less
@@ -62,7 +62,7 @@
float: left;
padding-left: 20px;
width: 35%;
- word-break: break-all;
+ word-wrap: break-word;
-webkit-hyphens: auto;
hyphens: auto;
diff --git a/src/filesystem/FileSystem.js b/src/filesystem/FileSystem.js
index 76b4a371fb1..c2e9288d439 100644
--- a/src/filesystem/FileSystem.js
+++ b/src/filesystem/FileSystem.js
@@ -693,6 +693,7 @@ define(function (require, exports, module) {
this._watchEntry(entry, watchedRoot, function (err) {
if (err) {
console.warn("Failed to watch root: ", entry.fullPath, err);
+ callback(err);
return;
}
diff --git a/src/filesystem/FileSystemEntry.js b/src/filesystem/FileSystemEntry.js
index 0c7864ddb9e..9a8a8ee6cf5 100644
--- a/src/filesystem/FileSystemEntry.js
+++ b/src/filesystem/FileSystemEntry.js
@@ -28,6 +28,11 @@
define(function (require, exports, module) {
"use strict";
+ var FileSystemError = require("filesystem/FileSystemError");
+
+ var VISIT_DEFAULT_MAX_DEPTH = 10,
+ VISIT_DEFAULT_MAX_ENTRIES = 30000;
+
/* Counter to give every entry a unique id */
var nextId = 0;
@@ -231,39 +236,36 @@ define(function (require, exports, module) {
};
/**
- * Visit this entry and its descendents with the supplied visitor function.
+ * Private helper function for FileSystemEntry.visit that requires sanitized options.
*
+ * @private
* @param {function(FileSystemEntry): boolean} visitor - A visitor function, which is
* applied to descendent FileSystemEntry objects. If the function returns false for
* a particular Directory entry, that directory's descendents will not be visited.
- * @param {{failFast: boolean=, maxDepth: number=}=} options - An optional set of options.
+ * @param {{failFast: boolean, maxDepth: number, maxEntriesCounter: {value: number}}} options
* @param {function(?string)=} callback Callback with single "error" parameter.
*/
- FileSystemEntry.prototype.visit = function (visitor, options, callback) {
- var DEFAULT_MAX_DEPTH = 100;
+ FileSystemEntry.prototype._visitHelper = function (visitor, options, callback) {
+ var failFast = options.failFast,
+ maxDepth = options.maxDepth,
+ maxEntriesCounter = options.maxEntriesCounter;
- if (typeof options === "function") {
- callback = options;
- options = {};
- } else if (options === undefined) {
- options = {};
+ if (maxEntriesCounter.value-- <= 0 || maxDepth-- < 0) {
+ callback(failFast ? FileSystemError.TOO_MANY_ENTRIES : null);
+ return;
}
- callback = callback || function () {};
-
- var maxDepth = typeof options.maxDepth === "number" ? options.maxDepth : DEFAULT_MAX_DEPTH,
- continueTraversal = visitor(this) && maxDepth-- > 0;
-
- if (this.isFile || !continueTraversal) {
+ if (!visitor(this) || this.isFile) {
callback(null);
return;
}
this.getContents(function (err, entries) {
var counter = entries ? entries.length : 0,
- newOptions = {
+ nextOptions = {
+ failFast: failFast,
maxDepth: maxDepth,
- failFast: options.maxDepth
+ maxEntriesCounter: maxEntriesCounter
};
if (err || counter === 0) {
@@ -272,21 +274,69 @@ define(function (require, exports, module) {
}
entries.forEach(function (entry) {
- entry.visit(visitor, newOptions, function (err) {
- if (err && options.failFast) {
+ entry._visitHelper(visitor, nextOptions, function (err) {
+ if (err && failFast) {
counter = 0;
callback(err);
return;
}
if (--counter === 0) {
- callback(options.failFast ? err : null);
+ callback(failFast ? err : null);
}
});
});
}.bind(this));
};
+ /**
+ * Visit this entry and its descendents with the supplied visitor function.
+ *
+ * @param {function(FileSystemEntry): boolean} visitor - A visitor function, which is
+ * applied to descendent FileSystemEntry objects. If the function returns false for
+ * a particular Directory entry, that directory's descendents will not be visited.
+ * @param {{failFast: boolean=, maxDepth: number=, maxEntries: number=}=} options - An optional set of options.
+ * @param {function(?string)=} callback Callback with single "error" parameter.
+ */
+ FileSystemEntry.prototype.visit = function (visitor, options, callback) {
+ if (typeof options === "function") {
+ callback = options;
+ options = {};
+ } else if (options === undefined) {
+ options = {};
+ }
+
+ if (options.failFast === undefined) {
+ options.failFast = false;
+ }
+
+ if (options.maxDepth === undefined) {
+ options.maxDepth = VISIT_DEFAULT_MAX_DEPTH;
+ }
+
+ if (options.maxEntries === undefined) {
+ options.maxEntries = VISIT_DEFAULT_MAX_ENTRIES;
+ }
+
+ options.maxEntriesCounter = { value: options.maxEntries };
+
+ this._visitHelper(visitor, options, function (err) {
+ if (callback) {
+ if (err) {
+ callback(err);
+ return;
+ }
+
+ if (options.maxEntriesCounter.value < 0) {
+ callback(FileSystemError.TOO_MANY_ENTRIES);
+ return;
+ }
+
+ callback(null);
+ }
+ });
+ };
+
// Export this class
module.exports = FileSystemEntry;
});
diff --git a/src/filesystem/FileSystemError.js b/src/filesystem/FileSystemError.js
index ed896ef5761..d54130b21b3 100644
--- a/src/filesystem/FileSystemError.js
+++ b/src/filesystem/FileSystemError.js
@@ -41,6 +41,7 @@ define(function (require, exports, module) {
NOT_READABLE : "NotReadable",
NOT_WRITABLE : "NotWritable",
OUT_OF_SPACE : "OutOfSpace",
+ TOO_MANY_ENTRIES : "TooManyEntries",
ALREADY_EXISTS : "AlreadyExists"
// FUTURE: Add remote connection errors: timeout, not logged in, connection err, etc.
};
diff --git a/src/htmlContent/contributors-list.html b/src/htmlContent/contributors-list.html
index ae5d1eb7ab0..50559e72cfc 100644
--- a/src/htmlContent/contributors-list.html
+++ b/src/htmlContent/contributors-list.html
@@ -1,5 +1 @@
-{{#.}}
-
-
-
-{{/.}}
\ No newline at end of file
+{{#.}}{{/.}}
diff --git a/src/language/languages.json b/src/language/languages.json
index b242c8d8038..c0c0253d40f 100644
--- a/src/language/languages.json
+++ b/src/language/languages.json
@@ -21,7 +21,7 @@
"css": {
"name": "CSS",
"mode": "css",
- "fileExtensions": ["css"],
+ "fileExtensions": ["css", "css.erb"],
"blockComment": ["/*", "*/"]
},
@@ -43,17 +43,10 @@
"ejs": {
"name": "EJS",
"mode": ["htmlembedded", "application/x-ejs"],
- "fileExtensions": ["ejs"],
+ "fileExtensions": ["ejs", "dust"],
"blockComment": [""]
},
- "dust": {
- "name": "Dust.js",
- "mode": ["htmlembedded", "application/x-ejs"],
- "fileExtensions": ["dust"],
- "blockComment": [""]
- },
-
"erb_html": {
"name": "Embedded Ruby",
"mode": ["htmlembedded", "application/x-erb"],
@@ -122,7 +115,7 @@
"csharp": {
"name": "C#",
"mode": ["clike", "text/x-csharp"],
- "fileExtensions": ["cs", "cshtml", "asax", "ashx"],
+ "fileExtensions": ["cs", "asax", "ashx"],
"blockComment": ["/*", "*/"],
"lineComment": ["//"]
},
diff --git a/src/nls/fa-ir/strings.js b/src/nls/fa-ir/strings.js
index c7bd7ef95f7..860688c8861 100644
--- a/src/nls/fa-ir/strings.js
+++ b/src/nls/fa-ir/strings.js
@@ -200,7 +200,6 @@ define({
"CMD_FILE_SAVE_ALL" : "ذخیره همه",
"CMD_FILE_SAVE_AS" : "ذخیره همه\u2026",
"CMD_LIVE_FILE_PREVIEW" : "پیش نمایش زنده",
- "CMD_LIVE_HIGHLIGHT" : "نشانه گذاری پیش نمایش",
"CMD_PROJECT_SETTINGS" : "تنظیمات پروژه\u2026",
"CMD_FILE_RENAME" : "تغییر نام",
"CMD_FILE_DELETE" : "حذف",
@@ -226,9 +225,9 @@ define({
"CMD_FIND_NEXT" : "بعدی",
"CMD_FIND_PREVIOUS" : "قبلی",
"CMD_REPLACE" : "جستجو و جایگزینی",
- "CMD_INDENT" : "برجسته سازی",
- "CMD_UNINDENT" : "حذف برجستگی",
- "CMD_DUPLICATE" : "دو نسخه کردن",
+ "CMD_INDENT" : "یک فاصله از چپ",
+ "CMD_UNINDENT" : "حذف یک فاصله از جپ",
+ "CMD_DUPLICATE" : "دونسخه کردن خط",
"CMD_DELETE_LINES" : "حذف خط",
"CMD_COMMENT" : "تعویض خط به نظر",
"CMD_BLOCK_COMMENT" : "تعویض نظر به خط",
@@ -251,6 +250,8 @@ define({
"CMD_TOGGLE_LINE_NUMBERS" : "شماره گذاری خط ها",
"CMD_TOGGLE_ACTIVE_LINE" : "نشانه گذاری خط فعال",
"CMD_TOGGLE_WORD_WRAP" : "شکستن عبارات طولانی",
+ "CMD_LIVE_HIGHLIGHT" : "نشانه گذاری پیش نمایش",
+ "CMD_VIEW_TOGGLE_INSPECTION" : "نشانه گذاری فایل های تغییر یافته برای ذخیره سازی",
"CMD_SORT_WORKINGSET_BY_ADDED" : "مرتب سازی بر اساس ترتیب افزودن",
"CMD_SORT_WORKINGSET_BY_NAME" : "مرتب سازی بر اساس نام",
"CMD_SORT_WORKINGSET_BY_TYPE" : "مرتب سازی بر اساس نوع",
@@ -409,7 +410,7 @@ define({
"CMD_REFRESH_WINDOW" : "بارگذاری مجدد براکتس",
"CMD_NEW_BRACKETS_WINDOW" : "یک پنجره جدید از براکتس باز کنید",
"CMD_SWITCH_LANGUAGE" : "انتخاب زبان",
- "CMD_RUN_UNIT_TESTS" : "اجرای test",
+ "CMD_RUN_UNIT_TESTS" : "برسی برای اجرا",
"CMD_SHOW_PERF_DATA" : "نمایش داده های عملکردی",
"CMD_ENABLE_NODE_DEBUGGER" : "فعال سازی اشکال زدای گرهی",
"CMD_LOG_NODE_STATE" : "ورود گره به حالت کنسول",
@@ -433,7 +434,7 @@ define({
"LOCALE_IT" : "Italian",
"LOCALE_JA" : "Japanese",
"LOCALE_NB" : "Norwegian",
- "LOCALE_fa_ir" : "Persian-پارسی",
+ "LOCALE_FA_IR" : "Persian-پارسی",
"LOCALE_PL" : "Polish",
"LOCALE_PT_BR" : "Portuguese, Brazil",
"LOCALE_PT_PT" : "Portuguese",
diff --git a/src/nls/fr/strings.js b/src/nls/fr/strings.js
index 6b2daa83ba5..533686dd894 100644
--- a/src/nls/fr/strings.js
+++ b/src/nls/fr/strings.js
@@ -455,6 +455,7 @@ define({
"LOCALE_IT": "Italien",
"LOCALE_JA": "Japonais",
"LOCALE_NB": "Norvégien",
+ "LOCALE_FA_IR": "Persan/Farsi",
"LOCALE_PL": "Polonais",
"LOCALE_PT_BR": "Portugais (Brésil)",
"LOCALE_PT_PT": "Portugais",
diff --git a/src/nls/ja/strings.js b/src/nls/ja/strings.js
index df32ce8f0f8..905fc35b219 100644
--- a/src/nls/ja/strings.js
+++ b/src/nls/ja/strings.js
@@ -455,6 +455,7 @@ define({
"LOCALE_IT": "イタリア語",
"LOCALE_JA": "日本語",
"LOCALE_NB": "ノルウェー語",
+ "LOCALE_FA_IR": "ペルシャ語-ファルシ語",
"LOCALE_PL": "ポーランド語",
"LOCALE_PT_BR": "ポルトガル語 (ブラジル)",
"LOCALE_PT_PT": "ポルトガル語",
diff --git a/src/nls/root/strings.js b/src/nls/root/strings.js
index 62b78fd74d7..f86cf620aa6 100644
--- a/src/nls/root/strings.js
+++ b/src/nls/root/strings.js
@@ -67,6 +67,10 @@ define({
// Application error strings
"ERROR_IN_BROWSER_TITLE" : "Oops! {APP_NAME} doesn't run in browsers yet.",
"ERROR_IN_BROWSER" : "{APP_NAME} is built in HTML, but right now it runs as a desktop app so you can use it to edit local files. Please use the application shell in the github.com/adobe/brackets-shell repo to run {APP_NAME}.",
+
+ // ProjectManager max files error string
+ "ERROR_MAX_FILES_TITLE" : "Error Indexing Files",
+ "ERROR_MAX_FILES" : "The maximum number of files have been indexed. Actions that look up files in the index may function incorrectly.",
// Live Development error strings
"ERROR_LAUNCHING_BROWSER_TITLE" : "Error launching browser",
@@ -451,7 +455,7 @@ define({
"LOCALE_IT" : "Italian",
"LOCALE_JA" : "Japanese",
"LOCALE_NB" : "Norwegian",
- "LOCALE_FA_IR" : "Persian",
+ "LOCALE_FA_IR" : "Persian-Farsi",
"LOCALE_PL" : "Polish",
"LOCALE_PT_BR" : "Portuguese, Brazil",
"LOCALE_PT_PT" : "Portuguese",
diff --git a/src/project/ProjectManager.js b/src/project/ProjectManager.js
index 6ac0db31352..12d70a98ce1 100644
--- a/src/project/ProjectManager.js
+++ b/src/project/ProjectManager.js
@@ -876,12 +876,26 @@ define(function (require, exports, module) {
return updateWelcomeProjectPath(_prefs.getValue("projectPath"));
}
+ /**
+ * Error dialog when max files in index is hit
+ * @return {Dialog}
+ */
+ function _showMaxFilesDialog() {
+ return Dialogs.showModalDialog(
+ DefaultDialogs.DIALOG_ID_ERROR,
+ Strings.ERROR_MAX_FILES_TITLE,
+ Strings.ERROR_MAX_FILES
+ );
+ }
+
function _watchProjectRoot(rootPath) {
FileSystem.on("change", _fileSystemChange);
FileSystem.on("rename", _fileSystemRename);
FileSystem.watch(FileSystem.getDirectoryForPath(rootPath), _shouldShowName, function (err) {
- if (err) {
+ if (err === FileSystemError.TOO_MANY_ENTRIES) {
+ _showMaxFilesDialog();
+ } else if (err) {
console.error("Error watching project root: ", rootPath, err);
}
});
diff --git a/src/search/FindInFiles.js b/src/search/FindInFiles.js
index 2e8811d2a71..e2eebf4275e 100644
--- a/src/search/FindInFiles.js
+++ b/src/search/FindInFiles.js
@@ -817,6 +817,13 @@ define(function (require, exports, module) {
var currentEditor = EditorManager.getActiveEditor(),
initialString = currentEditor && currentEditor.getSelectedText();
+ if (dialog && !dialog.closed && dialog.hasOwnProperty("modalBar") && dialog.modalBar) {
+ // The modalBar was already up. When creating the new modalBar, copy the
+ // current query instead of using the passed-in selected text.
+ initialString = dialog.getDialogTextField().val();
+ dialog.modalBar.close(true, false);
+ }
+
dialog = new FindInFilesDialog();
searchResults = {};
currentStart = 0;
diff --git a/src/styles/brackets.less b/src/styles/brackets.less
index 2699b52c98e..7423d536f5e 100644
--- a/src/styles/brackets.less
+++ b/src/styles/brackets.less
@@ -297,9 +297,10 @@ a, img {
left: 5px;
width: 40px;
text-align: center;
- background-color: rgba(0,0,0,0.8);
- color: white;
- border-radius: 4px;
+ background-color: rgba(0, 0, 0, 0.8);
+ color: #fff;
+ border-radius: 3px;
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
}
}
diff --git a/src/styles/brackets_theme_default.less b/src/styles/brackets_theme_default.less
index d69ef05e4bf..590c2ff9685 100644
--- a/src/styles/brackets_theme_default.less
+++ b/src/styles/brackets_theme_default.less
@@ -115,7 +115,7 @@
/* selection colors */
@selection-color-focused: #abdffa;
-@selection-color-unfocused: #e9e9e9;
+@selection-color-unfocused: #d5dee3;
/* background color of the line that has the cursor */
@activeline-bgcolor: #ebefef;
diff --git a/test/spec/FileSystem-test.js b/test/spec/FileSystem-test.js
index 59c9fbe70dd..daa909ff3dc 100644
--- a/test/spec/FileSystem-test.js
+++ b/test/spec/FileSystem-test.js
@@ -502,6 +502,154 @@ define(function (require, exports, module) {
});
});
+ describe("FileSystemEntry.visit", function () {
+ function getContentsCallback() {
+ var callback = function (err, contents) {
+ callback.error = err;
+ callback.contents = contents;
+ callback.wasCalled = true;
+ };
+ return callback;
+ }
+
+ beforeEach(function () {
+ function initEntry(entry, command, args) {
+ var cb = getContentsCallback();
+
+ args.push(cb);
+ runs(function () {
+ entry[command].apply(entry, args);
+ });
+ waitsFor(function () { return cb.wasCalled; });
+ runs(function () {
+ expect(cb.error).toBeFalsy();
+ });
+ }
+
+ function initDir(path) {
+ initEntry(fileSystem.getDirectoryForPath(path), "create", []);
+ }
+
+ function initFile(path) {
+ initEntry(fileSystem.getFileForPath(path), "write", ["abc"]);
+ }
+
+ initDir("/visit/");
+ initFile("/visit/file.txt");
+ initDir("/visit/subdir1/");
+ initDir("/visit/subdir2/");
+ initFile("/visit/subdir1/subfile11.txt");
+ initFile("/visit/subdir1/subfile12.txt");
+ initFile("/visit/subdir2/subfile21.txt");
+ initFile("/visit/subdir2/subfile22.txt");
+ });
+
+ it("should visit all entries by default", function () {
+ var directory = fileSystem.getDirectoryForPath("/visit/"),
+ results = {},
+ visitor = function (entry) {
+ results[entry.fullPath] = entry;
+ return true;
+ };
+
+ var cb = getContentsCallback();
+ runs(function () {
+ directory.visit(visitor, cb);
+ });
+ waitsFor(function () { return cb.wasCalled; });
+ runs(function () {
+ expect(cb.error).toBeFalsy();
+ expect(Object.keys(results).length).toBe(8);
+ expect(results["/visit/"]).toBeTruthy();
+ expect(results["/visit/file.txt"]).toBeTruthy();
+ expect(results["/visit/subdir1/"]).toBeTruthy();
+ expect(results["/visit/subdir2/"]).toBeTruthy();
+ expect(results["/visit/subdir1/subfile11.txt"]).toBeTruthy();
+ expect(results["/visit/subdir1/subfile12.txt"]).toBeTruthy();
+ expect(results["/visit/subdir2/subfile21.txt"]).toBeTruthy();
+ expect(results["/visit/subdir2/subfile21.txt"]).toBeTruthy();
+ expect(results["/"]).not.toBeTruthy();
+ });
+ });
+
+ it("should visit with a specified maximum depth", function () {
+ var directory = fileSystem.getDirectoryForPath("/visit/"),
+ results = {},
+ visitor = function (entry) {
+ results[entry.fullPath] = entry;
+ return true;
+ };
+
+ var cb = getContentsCallback();
+ runs(function () {
+ directory.visit(visitor, {maxDepth: 1}, cb);
+ });
+ waitsFor(function () { return cb.wasCalled; });
+ runs(function () {
+ expect(cb.error).toBeFalsy();
+ expect(Object.keys(results).length).toBe(4);
+ expect(results["/visit/"]).toBeTruthy();
+ expect(results["/visit/file.txt"]).toBeTruthy();
+ expect(results["/visit/subdir1/"]).toBeTruthy();
+ expect(results["/visit/subdir2/"]).toBeTruthy();
+ expect(results["/visit/subdir1/subfile11.txt"]).not.toBeTruthy();
+ expect(results["/visit/subdir1/subfile12.txt"]).not.toBeTruthy();
+ expect(results["/visit/subdir2/subfile21.txt"]).not.toBeTruthy();
+ expect(results["/visit/subdir2/subfile21.txt"]).not.toBeTruthy();
+ expect(results["/"]).not.toBeTruthy();
+ });
+ });
+
+ it("should visit with a specified maximum number of entries", function () {
+ var directory = fileSystem.getDirectoryForPath("/visit/"),
+ results = {},
+ visitor = function (entry) {
+ results[entry.fullPath] = entry;
+ return true;
+ };
+
+ var cb = getContentsCallback();
+ runs(function () {
+ directory.visit(visitor, {maxEntries: 4}, cb);
+ });
+ waitsFor(function () { return cb.wasCalled; });
+ runs(function () {
+ expect(cb.error).toBe(FileSystemError.TOO_MANY_ENTRIES);
+ expect(Object.keys(results).length).toBe(4);
+ expect(results["/visit/"]).toBeTruthy();
+ expect(results["/visit/file.txt"]).toBeTruthy();
+ expect(results["/"]).not.toBeTruthy();
+ });
+ });
+
+ it("should visit only children of directories admitted by the filter", function () {
+ var directory = fileSystem.getDirectoryForPath("/visit/"),
+ results = {},
+ visitor = function (entry) {
+ results[entry.fullPath] = entry;
+ return entry.name === "visit" || /1$/.test(entry.name);
+ };
+
+ var cb = getContentsCallback();
+ runs(function () {
+ directory.visit(visitor, cb);
+ });
+ waitsFor(function () { return cb.wasCalled; });
+ runs(function () {
+ expect(cb.error).toBeFalsy();
+ expect(Object.keys(results).length).toBe(6);
+ expect(results["/visit/"]).toBeTruthy();
+ expect(results["/visit/file.txt"]).toBeTruthy();
+ expect(results["/visit/subdir1/"]).toBeTruthy();
+ expect(results["/visit/subdir2/"]).toBeTruthy();
+ expect(results["/visit/subdir1/subfile11.txt"]).toBeTruthy();
+ expect(results["/visit/subdir1/subfile12.txt"]).toBeTruthy();
+ expect(results["/visit/subdir2/subfile21.txt"]).not.toBeTruthy();
+ expect(results["/visit/subdir2/subfile21.txt"]).not.toBeTruthy();
+ expect(results["/"]).not.toBeTruthy();
+ });
+ });
+ });
describe("Event timing", function () {
diff --git a/test/spec/LanguageManager-test.js b/test/spec/LanguageManager-test.js
index 9bde071a5cd..4b484b66e04 100644
--- a/test/spec/LanguageManager-test.js
+++ b/test/spec/LanguageManager-test.js
@@ -36,7 +36,6 @@ define(function (require, exports, module) {
FileSystem = require("filesystem/FileSystem");
describe("LanguageManager", function () {
- this.category = "integration";
beforeEach(function () {
waitsForDone(LanguageManager.ready, "LanguageManager ready", 10000);
@@ -403,6 +402,7 @@ define(function (require, exports, module) {
});
describe("rename file extension", function () {
+ this.category = "integration";
it("should update the document's language when a file is renamed", function () {
var tempDir = SpecRunnerUtils.getTempDirectory(),
@@ -475,7 +475,6 @@ define(function (require, exports, module) {
});
waitsForDone(renameDeferred.promise(), "old file rename");
- var unlinkDeferred = $.Deferred();
runs(function () {
html = LanguageManager.getLanguage("html");
@@ -490,16 +489,7 @@ define(function (require, exports, module) {
// cleanup
doc.releaseRef();
-
- oldFile.unlink(function (err) {
- if (err) {
- unlinkDeferred.reject(err);
- } else {
- unlinkDeferred.resolve();
- }
- });
});
- waitsForDone(unlinkDeferred.promise(), "new file unlink");
SpecRunnerUtils.closeTestWindow();
diff --git a/test/spec/MockFileSystemImpl.js b/test/spec/MockFileSystemImpl.js
index 8549142604a..69070e25029 100644
--- a/test/spec/MockFileSystemImpl.js
+++ b/test/spec/MockFileSystemImpl.js
@@ -272,18 +272,21 @@ define(function (require, exports, module) {
options = null;
}
- var cb = _getCallback("writeFile", path, callback),
- notify = _getNotification("writeFile", path, _sendWatcherNotification);
-
- if (!_data[path]) {
- _data[path] = {
- isFile: true
- };
- }
- _data[path].contents = data;
- _data[path].mtime = Date.now();
- cb(null);
- notify(path);
+ exists(path, function (exists) {
+ var cb = _getCallback("writeFile", path, callback),
+ notification = exists ? _sendWatcherNotification : _sendDirectoryWatcherNotification,
+ notify = _getNotification("writeFile", path, notification);
+
+ if (!_data[path]) {
+ _data[path] = {
+ isFile: true
+ };
+ }
+ _data[path].contents = data;
+ _data[path].mtime = Date.now();
+ cb(null);
+ notify(path);
+ });
}
function unlink(path, callback) {