");
-}, 1000);
\ No newline at end of file
+}, 1000);
diff --git a/src/document/Document.js b/src/document/Document.js
index 13591eb3884..337136b0942 100644
--- a/src/document/Document.js
+++ b/src/document/Document.js
@@ -227,7 +227,7 @@ define(function (require, exports, module) {
*/
Document.prototype._ensureMasterEditor = function () {
if (!this._masterEditor) {
- EditorManager._createFullEditorForDocument(this);
+ EditorManager._createUnattachedMasterEditor(this);
}
};
diff --git a/src/document/DocumentCommandHandlers.js b/src/document/DocumentCommandHandlers.js
index dfc9312ac93..3524682db66 100644
--- a/src/document/DocumentCommandHandlers.js
+++ b/src/document/DocumentCommandHandlers.js
@@ -34,8 +34,10 @@ define(function (require, exports, module) {
var AppInit = require("utils/AppInit"),
CommandManager = require("command/CommandManager"),
Commands = require("command/Commands"),
+ DeprecationWarning = require("utils/DeprecationWarning"),
ProjectManager = require("project/ProjectManager"),
DocumentManager = require("document/DocumentManager"),
+ MainViewManager = require("view/MainViewManager"),
EditorManager = require("editor/EditorManager"),
FileSystem = require("filesystem/FileSystem"),
FileSystemError = require("filesystem/FileSystemError"),
@@ -49,14 +51,13 @@ define(function (require, exports, module) {
Strings = require("strings"),
PopUpManager = require("widgets/PopUpManager"),
PreferencesManager = require("preferences/PreferencesManager"),
- DragAndDrop = require("utils/DragAndDrop"),
PerfUtils = require("utils/PerfUtils"),
KeyEvent = require("utils/KeyEvent"),
- LanguageManager = require("language/LanguageManager"),
Inspector = require("LiveDevelopment/Inspector/Inspector"),
Menus = require("command/Menus"),
UrlParams = require("utils/UrlParams").UrlParams,
- StatusBar = require("widgets/StatusBar");
+ StatusBar = require("widgets/StatusBar"),
+ WorkspaceManager = require("view/WorkspaceManager");
/**
* Handlers for commands related to document handling (opening, saving, etc.)
@@ -126,10 +127,14 @@ define(function (require, exports, module) {
* @type {function}
*/
var handleFileSaveAs;
-
- function updateTitle() {
+
+ /**
+ * Updates the title bar with new file title or dirty indicator
+ * @private
+ */
+ function _updateTitle() {
var currentDoc = DocumentManager.getCurrentDocument(),
- currentlyViewedPath = EditorManager.getCurrentlyViewedPath(),
+ currentlyViewedPath = MainViewManager.getCurrentlyViewedPath(MainViewManager.ACTIVE_PANE),
windowTitle = brackets.config.app_title;
if (!brackets.nativeMenus) {
@@ -161,7 +166,7 @@ define(function (require, exports, module) {
var newToolbarHeight = _$titleContainerToolbar.height();
if (_lastToolbarHeight !== newToolbarHeight) {
_lastToolbarHeight = newToolbarHeight;
- EditorManager.resizeEditor();
+ WorkspaceManager.recomputeLayout();
}
}
@@ -184,7 +189,7 @@ define(function (require, exports, module) {
/**
* Returns a short title for a given document.
*
- * @param {Document} doc
+ * @param {Document} doc - the document to compute the short title for
* @return {string} - a short title for doc.
*/
function _shortTitleForDocument(doc) {
@@ -200,36 +205,36 @@ define(function (require, exports, module) {
}
}
- function updateDocumentTitle() {
- var newDocument = DocumentManager.getCurrentDocument();
-
- // TODO: This timer is causing a "Recursive tests with the same name are not supported"
- // exception. This code should be removed (if not needed), or updated with a unique
- // timer name (if needed).
- // var perfTimerName = PerfUtils.markStart("DocumentCommandHandlers._onCurrentDocumentChange():\t" + (!newDocument || newDocument.file.fullPath));
+ /**
+ * Handles currentFileChange and filenameChanged events and updates the titlebar
+ */
+ function handleCurrentFileChange() {
+ var newFile = MainViewManager.getCurrentlyViewedFile(MainViewManager.ACTIVE_PANE);
- if (newDocument) {
- _currentTitlePath = _shortTitleForDocument(newDocument);
- } else {
- var currentlyViewedFilePath = EditorManager.getCurrentlyViewedPath();
- if (currentlyViewedFilePath) {
- _currentTitlePath = ProjectManager.makeProjectRelativeIfPossible(currentlyViewedFilePath);
+ if (newFile) {
+ var newDocument = DocumentManager.getOpenDocumentForPath(newFile.fullPath);
+
+ if (newDocument) {
+ _currentTitlePath = _shortTitleForDocument(newDocument);
} else {
- _currentTitlePath = null;
+ _currentTitlePath = ProjectManager.makeProjectRelativeIfPossible(newFile.fullPath);
}
+ } else {
+ _currentTitlePath = null;
}
// Update title text & "dirty dot" display
- updateTitle();
-
- // PerfUtils.addMeasurement(perfTimerName);
+ _updateTitle();
}
+ /**
+ * Handles dirtyFlagChange event and updates the title bar if necessary
+ */
function handleDirtyChange(event, changedDoc) {
var currentDoc = DocumentManager.getCurrentDocument();
if (currentDoc && changedDoc.file.fullPath === currentDoc.file.fullPath) {
- updateTitle();
+ _updateTitle();
}
}
@@ -238,83 +243,59 @@ define(function (require, exports, module) {
* Creates a document and displays an editor for the specified file path.
* @param {!string} fullPath
* @param {boolean=} silent If true, don't show error message
+ * @param {string=} paneId, the id oi the pane in which to open the file. Can be undefined, a valid pane id or ACTIVE_PANE.
* @return {$.Promise} a jQuery promise that will either
- * - be resolved with a document for the specified file path or
- * - be resolved without document, i.e. when an image is displayed or
- * - be rejected if the file can not be read.
+ * - be resolved with a file for the specified file path or
+ * - be rejected with FileSystemError if the file can not be read.
+ * If paneId is undefined, the ACTIVE_PANE constant
*/
- function doOpen(fullPath, silent) {
+ function _doOpen(fullPath, silent, paneId) {
var result = new $.Deferred();
// workaround for https://github.com/adobe/brackets/issues/6001
// TODO should be removed once bug is closed.
// if we are already displaying a file do nothing but resolve immediately.
// this fixes timing issues in test cases.
- if (EditorManager.getCurrentlyViewedPath() === fullPath) {
- result.resolve(DocumentManager.getCurrentDocument());
+ if (MainViewManager.getCurrentlyViewedPath(MainViewManager.ACTIVE_PANE) === fullPath) {
+ result.resolve(MainViewManager.getCurrentlyViewedFile(MainViewManager.ACTIVE_PANE));
return result.promise();
}
- function _cleanup(fullFilePath) {
- if (!fullFilePath || EditorManager.showingCustomViewerForPath(fullFilePath)) {
- // We get here only after the user renames a file that makes it no longer belong to a
- // custom viewer but the file is still showing in the current custom viewer. This only
- // occurs on Mac since opening a non-text file always fails on Mac and triggers an error
- // message that in turn calls _cleanup() after the user clicks OK in the message box.
- // So we need to explicitly close the currently viewing image file whose filename is
- // no longer valid. Calling notifyPathDeleted will close the image vieer and then select
- // the previously opened text file or show no-editor if none exists.
- EditorManager.notifyPathDeleted(fullFilePath);
- } else {
- // For performance, we do lazy checking of file existence, so it may be in working set
- DocumentManager.removeFromWorkingSet(FileSystem.getFileForPath(fullFilePath));
- EditorManager.focusEditor();
+ function _cleanup(fileError, fullFilePath) {
+ if (fullFilePath) {
+ // For performance, we do lazy checking of file existence, so it may be in workingset
+ MainViewManager._removeView(paneId, FileSystem.getFileForPath(fullFilePath));
+ MainViewManager.focusActivePane();
}
- result.reject();
+ result.reject(fileError);
}
function _showErrorAndCleanUp(fileError, fullFilePath) {
if (silent) {
- _cleanup(fullFilePath);
+ _cleanup(fileError, fullFilePath);
} else {
FileUtils.showFileOpenError(fileError, fullFilePath).done(function () {
- _cleanup(fullFilePath);
+ _cleanup(fileError, fullFilePath);
});
}
}
if (!fullPath) {
- console.error("doOpen() called without fullPath");
- result.reject();
+ throw new Error("_doOpen() called without fullPath");
} else {
var perfTimerName = PerfUtils.markStart("Open File:\t" + fullPath);
result.always(function () {
PerfUtils.addMeasurement(perfTimerName);
});
- var viewProvider = EditorManager.getCustomViewerForPath(fullPath);
- if (viewProvider) {
- var file = FileSystem.getFileForPath(fullPath);
- file.exists(function (fileError, fileExists) {
- if (fileExists) {
- EditorManager._showCustomViewer(viewProvider, fullPath);
- result.resolve();
- } else {
- fileError = fileError || FileSystemError.NOT_FOUND;
- _showErrorAndCleanUp(fileError);
- }
+ var file = FileSystem.getFileForPath(fullPath);
+ MainViewManager._open(paneId, file)
+ .done(function () {
+ result.resolve(file);
+ })
+ .fail(function (fileError) {
+ _showErrorAndCleanUp(fileError, fullPath);
+ result.reject();
});
-
- } else {
- // Load the file if it was never open before, and then switch to it in the UI
- DocumentManager.getDocumentForPath(fullPath)
- .done(function (doc) {
- DocumentManager.setCurrentDocument(doc);
- result.resolve(doc);
- })
- .fail(function (fileError) {
- _showErrorAndCleanUp(fileError, fullPath);
- });
- }
}
return result.promise();
@@ -328,16 +309,17 @@ define(function (require, exports, module) {
/**
* @private
- * Creates a document and displays an editor for the specified file path.
+ * Opens a file and displays its view (editor, image view, etc...) for the specified path.
* If no path is specified, a file prompt is provided for input.
* @param {?string} fullPath - The path of the file to open; if it's null we'll prompt for it
* @param {boolean=} silent - If true, don't show error message
- * @return {$.Promise} a jQuery promise that will be resolved with a new
- * document for the specified file path or be resolved without document, i.e. when an image is displayed,
- * or rejected if the file can not be read.
+ * @param {string=} paneId - the pane in which to open the file. Can be undefined, a valid pane id or ACTIVE_PANE
+ * @return {$.Promise} a jQuery promise resolved with a Document object or
+ * rejected with an err
*/
- function _doOpenWithOptionalPath(fullPath, silent) {
+ function _doOpenWithOptionalPath(fullPath, silent, paneId) {
var result;
+ paneId = paneId || MainViewManager.ACTIVE_PANE;
if (!fullPath) {
// Create placeholder deferred
result = new $.Deferred();
@@ -350,24 +332,21 @@ define(function (require, exports, module) {
FileSystem.showOpenDialog(true, false, Strings.OPEN_FILE, _defaultOpenDialogFullPath, null, function (err, paths) {
if (!err) {
if (paths.length > 0) {
- // Add all files to the working set without verifying that
+ // Add all files to the workingset without verifying that
// they still exist on disk (for faster opening)
- var filesToOpen = [],
- filteredPaths = DragAndDrop.filterFilesToOpen(paths);
+ var filesToOpen = [];
- filteredPaths.forEach(function (file) {
- filesToOpen.push(FileSystem.getFileForPath(file));
+ paths.forEach(function (path) {
+ filesToOpen.push(FileSystem.getFileForPath(path));
});
- DocumentManager.addListToWorkingSet(filesToOpen);
+ MainViewManager.addListToWorkingSet(paneId, filesToOpen);
- doOpen(filteredPaths[filteredPaths.length - 1], silent)
- .done(function (doc) {
- // doc may be null, i.e. if an image has been opened.
- // Then we do not add the opened file to the working set.
- if (doc) {
- DocumentManager.addToWorkingSet(doc.file);
- }
- _defaultOpenDialogFullPath = FileUtils.getDirectoryPath(EditorManager.getCurrentlyViewedPath());
+ _doOpen(paths[paths.length - 1], silent, paneId)
+ .done(function (file) {
+ _defaultOpenDialogFullPath =
+ FileUtils.getDirectoryPath(
+ MainViewManager.getCurrentlyViewedPath(paneId)
+ );
})
// Send the resulting document that was opened
.then(result.resolve, result.reject);
@@ -378,7 +357,7 @@ define(function (require, exports, module) {
}
});
} else {
- result = doOpen(fullPath, silent);
+ result = _doOpen(fullPath, silent, paneId);
}
return result.promise();
@@ -410,28 +389,54 @@ define(function (require, exports, module) {
}
/**
- * Opens the given file and makes it the current document. Does NOT add it to the working set.
- * @param {!{fullPath:string}} Params for FILE_OPEN command;
- * the fullPath string is of the form "path[:lineNumber[:columnNumber]]"
- * lineNumber and columnNumber are 1-origin: the very first line is line 1, and the very first column is column 1.
+ * @typedef {{fullPath:?string=, silent:boolean=, paneId:string=}} FileCommandData
+ * fullPath: is in the form "path[:lineNumber[:columnNumber]]"
+ * lineNumber and columnNumber are 1-origin: lines and columns are 1-based
+ */
+
+ /**
+ * @typedef {{fullPath:?string=, index:number=, silent:boolean=, forceRedraw:boolean=, paneId:string=}} PaneCommandData
+ * fullPath: is in the form "path[:lineNumber[:columnNumber]]"
+ * lineNumber and columnNumber are 1-origin: lines and columns are 1-based
+ */
+
+ /**
+ * Opens the given file and makes it the current file. Does NOT add it to the workingset.
+ * @param {FileCommandData=} commandData - record with the following properties:
+ * fullPath: File to open;
+ * silent: optional flag to suppress error messages;
+ * paneId: optional PaneId (defaults to active pane)
+ * @return {$.Promise} a jQuery promise that will be resolved with a file object
*/
function handleFileOpen(commandData) {
var fileInfo = _parseDecoratedPath(commandData ? commandData.fullPath : null),
- silent = commandData ? commandData.silent : false;
- return _doOpenWithOptionalPath(fileInfo.path, silent)
- .always(function () {
+ silent = (commandData && commandData.silent) || false,
+ paneId = (commandData && commandData.paneId) || MainViewManager.ACTIVE_PANE,
+ result = new $.Deferred();
+
+ _doOpenWithOptionalPath(fileInfo.path, silent, paneId)
+ .done(function (file) {
+ MainViewManager.setActivePaneId(paneId);
+
// If a line and column number were given, position the editor accordingly.
if (fileInfo.line !== null) {
if (fileInfo.column === null || (fileInfo.column <= 0)) {
fileInfo.column = 1;
}
+
// setCursorPos expects line/column numbers as 0-origin, so we subtract 1
- EditorManager.getCurrentFullEditor().setCursorPos(fileInfo.line - 1, fileInfo.column - 1, true);
+ EditorManager.getCurrentFullEditor().setCursorPos(fileInfo.line - 1,
+ fileInfo.column - 1,
+ true);
}
- // Give the editor focus
- EditorManager.focusEditor();
+ result.resolve(file);
+ })
+ .fail(function (err) {
+ result.reject(err);
});
+
+ return result;
// Testing notes: here are some recommended manual tests for handleFileOpen, on macintosh.
// Do all tests with brackets already running, and also with brackets not already running.
//
@@ -446,22 +451,83 @@ define(function (require, exports, module) {
}
/**
- * Opens the given file, makes it the current document, AND adds it to the working set
- * only if the file does not have a custom viewer.
- * @param {!{fullPath:string, index:number=, forceRedraw:boolean}} commandData File to open; optional position in
- * working set list (defaults to last); optional flag to force working set redraw
+ * Opens the given file, makes it the current file, does NOT add it to the workingset
+ * @param {FileCommandData} commandData
+ * fullPath: File to open;
+ * silent: optional flag to suppress error messages;
+ * paneId: optional PaneId (defaults to active pane)
+ * @return {$.Promise} a jQuery promise that will be resolved with @type {Document}
*/
- function handleFileAddToWorkingSet(commandData) {
- return handleFileOpen(commandData).done(function (doc) {
- // addToWorkingSet is synchronous
- // When opening a file with a custom viewer, we get a null doc.
- // So check it before we add it to the working set.
- if (doc) {
- DocumentManager.addToWorkingSet(doc.file, commandData.index, commandData.forceRedraw);
- }
+ function handleDocumentOpen(commandData) {
+ var result = new $.Deferred();
+ handleFileOpen(commandData)
+ .done(function (file) {
+ // if we succeeded with an open file
+ // then we need to resolve that to a document.
+ // getOpenDocumentForPath will return null if there isn't a
+ // supporting document for that file (e.g. an image)
+ var doc = DocumentManager.getOpenDocumentForPath(file.fullPath);
+ result.resolve(doc);
+ })
+ .fail(function (err) {
+ result.reject(err);
+ });
+
+ return result.promise();
+
+ }
+
+ /**
+ * Opens the given file, makes it the current file, AND adds it to the workingset
+ * @param {!PaneCommandData} commandData - record with the following properties:
+ * fullPath: File to open;
+ * index: optional index to position in workingset (defaults to last);
+ * silent: optional flag to suppress error messages;
+ * forceRedraw: flag to force the working set view redraw;
+ * paneId: optional PaneId (defaults to active pane)
+ * @return {$.Promise} a jQuery promise that will be resolved with a @type {File}
+ */
+ function handleFileAddToWorkingSetAndOpen(commandData) {
+ return handleFileOpen(commandData).done(function (file) {
+ var paneId = (commandData && commandData.paneId) || MainViewManager.ACTIVE_PANE;
+ MainViewManager.addToWorkingSet(paneId, file, commandData.index, commandData.forceRedraw);
});
}
+ /**
+ * @deprecated
+ * Opens the given file, makes it the current document, AND adds it to the workingset
+ * @param {!PaneCommandData} commandData - record with the following properties:
+ * fullPath: File to open;
+ * index: optional index to position in workingset (defaults to last);
+ * silent: optional flag to suppress error messages;
+ * forceRedraw: flag to force the working set view redraw;
+ * paneId: optional PaneId (defaults to active pane)
+ * @return {$.Promise} a jQuery promise that will be resolved with @type {File}
+ */
+ function handleFileAddToWorkingSet(commandData) {
+ // This is a legacy deprecated command that
+ // will use the new command and resolve with a document
+ // as the legacy command would only support.
+ DeprecationWarning.deprecationWarning("Commands.FILE_ADD_TO_WORKING_SET has been deprecated. Use Commands.CMD_ADD_TO_WORKINGSET_AND_OPEN instead.");
+ var result = new $.Deferred();
+
+ handleFileAddToWorkingSetAndOpen(commandData)
+ .done(function (file) {
+ // if we succeeded with an open file
+ // then we need to resolve that to a document.
+ // getOpenDocumentForPath will return null if there isn't a
+ // supporting document for that file (e.g. an image)
+ var doc = DocumentManager.getOpenDocumentForPath(file.fullPath);
+ result.resolve(doc);
+ })
+ .fail(function (err) {
+ result.reject(err);
+ });
+
+ return result.promise();
+ }
+
/**
* @private
* Ensures the suggested file name doesn't already exit.
@@ -507,6 +573,8 @@ define(function (require, exports, module) {
/**
* Bottleneck function for creating new files and folders in the project tree.
+ * @private
+ * @param {boolean} isFolder - true if creating a new folder, false if creating a new file
*/
function _handleNewItemInProject(isFolder) {
if (fileNewInProgress) {
@@ -519,7 +587,7 @@ define(function (require, exports, module) {
// If a file is currently selected in the tree, put it next to it.
// If a directory is currently selected in the tree, put it in it.
// If an Untitled document is selected or nothing is selected in the tree, put it at the root of the project.
- // (Note: 'selected' may be an item that's selected in the working set and not the tree; but in that case
+ // (Note: 'selected' may be an item that's selected in the workingset and not the tree; but in that case
// ProjectManager.createNewItem() ignores the baseDir we give it and falls back to the project root on its own)
var baseDirEntry,
selected = ProjectManager.getSelectedItem();
@@ -545,7 +613,7 @@ define(function (require, exports, module) {
}
/**
- * Create a new untitled document in the working set, and make it the current document.
+ * Create a new untitled document in the workingset, and make it the current document.
* Promise is resolved (synchronously) with the newly-created Document.
*/
function handleFileNew() {
@@ -556,8 +624,7 @@ define(function (require, exports, module) {
var defaultExtension = ""; // disable preference setting for now
var doc = DocumentManager.createUntitledDocument(_nextUntitledIndexToUse++, defaultExtension);
- DocumentManager.setCurrentDocument(doc);
- EditorManager.focusEditor();
+ MainViewManager._edit(MainViewManager.ACTIVE_PANE, doc);
return new $.Deferred().resolve(doc).promise();
}
@@ -669,8 +736,6 @@ define(function (require, exports, module) {
}
if (docToSave.isDirty) {
- var writeError = false;
-
if (docToSave.keepChangesTime) {
// The user has decided to keep conflicting changes in the editor. Check to make sure
// the file hasn't changed since they last decided to do that.
@@ -692,7 +757,7 @@ define(function (require, exports, module) {
result.resolve(file);
}
result.always(function () {
- EditorManager.focusEditor();
+ MainViewManager.focusActivePane();
});
return result.promise();
}
@@ -700,6 +765,7 @@ define(function (require, exports, module) {
/**
* Reverts the Document to the current contents of its file on disk. Discards any unsaved changes
* in the Document.
+ * @private
* @param {Document} doc
* @param {boolean=} suppressError If true, then a failure to read the file will be ignored and the
* resulting promise will be resolved rather than rejected.
@@ -707,7 +773,7 @@ define(function (require, exports, module) {
* rejected with a FileSystemError if the file cannot be read (after showing an error
* dialog to the user).
*/
- function doRevert(doc, suppressError) {
+ function _doRevert(doc, suppressError) {
var result = new $.Deferred();
FileUtils.readAsText(doc.file)
@@ -763,21 +829,23 @@ define(function (require, exports, module) {
result.resolve(newFile);
}
- // Replace old document with new one in open editor & working set
+ // Replace old document with new one in open editor & workingset
function openNewFile() {
var fileOpenPromise;
if (FileViewController.getFileSelectionFocus() === FileViewController.PROJECT_MANAGER) {
- // If selection is in the tree, leave working set unchanged - even if orig file is in the list
+ // If selection is in the tree, leave workingset unchanged - even if orig file is in the list
fileOpenPromise = FileViewController
.openAndSelectDocument(path, FileViewController.PROJECT_MANAGER);
} else {
- // If selection is in working set, replace orig item in place with the new file
- var index = DocumentManager.findInWorkingSet(doc.file.fullPath);
- // Remove old file from working set; no redraw yet since there's a pause before the new file is opened
- DocumentManager.removeFromWorkingSet(doc.file, true);
- // Add new file to working set, and ensure we now redraw (even if index hasn't changed)
- fileOpenPromise = handleFileAddToWorkingSet({fullPath: path, index: index, forceRedraw: true});
+ // If selection is in workingset, replace orig item in place with the new file
+ var info = MainViewManager.findInAllWorkingSets(doc.file.fullPath).shift();
+
+ // Remove old file from workingset; no redraw yet since there's a pause before the new file is opened
+ MainViewManager._removeView(info.paneId, doc.file, true);
+
+ // Add new file to workingset, and ensure we now redraw (even if index hasn't changed)
+ fileOpenPromise = handleFileAddToWorkingSetAndOpen({fullPath: path, paneId: info.paneId, index: info.index, forceRedraw: true});
}
// always configure editor after file is opened
@@ -805,12 +873,12 @@ define(function (require, exports, module) {
.done(function () {
// If there were unsaved changes before Save As, they don't stay with the old
// file anymore - so must revert the old doc to match disk content.
- // Only do this if the doc was dirty: doRevert on a file that is not dirty and
- // not in the working set has the side effect of adding it to the working set.
+ // Only do this if the doc was dirty: _doRevert on a file that is not dirty and
+ // not in the workingset has the side effect of adding it to the workingset.
if (doc.isDirty && !(doc.isUntitled())) {
- // if the file is dirty it must be in the working set
- // doRevert is side effect free in this case
- doRevert(doc).always(openNewFile);
+ // if the file is dirty it must be in the workingset
+ // _doRevert is side effect free in this case
+ _doRevert(doc).always(openNewFile);
} else {
openNewFile();
}
@@ -834,7 +902,11 @@ define(function (require, exports, module) {
// (Issue #4489) if we're saving an untitled document, go ahead and switch to this document
// in the editor, so that if we're, for example, saving several files (ie. Save All),
// then the user can visually tell which document we're currently prompting them to save.
- DocumentManager.setCurrentDocument(doc);
+ var info = MainViewManager.findInAllWorkingSets(origPath).shift();
+
+ if (info) {
+ MainViewManager._open(info.paneId, doc.file);
+ }
// If the document is untitled, default to project root.
saveAsDefaultPath = ProjectManager.getProjectRoot().fullPath;
@@ -931,7 +1003,7 @@ define(function (require, exports, module) {
});
return savePromise;
} else {
- // working set entry that was never actually opened - ignore
+ // workingset entry that was never actually opened - ignore
filesAfterSave.push(file);
return (new $.Deferred()).resolve().promise();
}
@@ -947,7 +1019,7 @@ define(function (require, exports, module) {
* @return {$.Promise}
*/
function saveAll() {
- return _saveFileList(DocumentManager.getWorkingSet());
+ return _saveFileList(MainViewManager.getWorkingSet(MainViewManager.ALL_PANES));
}
/**
@@ -986,7 +1058,7 @@ define(function (require, exports, module) {
}
/**
- * Closes the specified file: removes it from the working set, and closes the main editor if one
+ * Closes the specified file: removes it from the workingset, and closes the main editor if one
* is open. Prompts user about saving changes first, if document is dirty.
*
* @param {?{file: File, promptOnly:boolean}} commandData Optional bag of arguments:
@@ -1002,58 +1074,28 @@ define(function (require, exports, module) {
function handleFileClose(commandData) {
var file,
promptOnly,
- _forceClose;
+ _forceClose,
+ paneId = MainViewManager.ACTIVE_PANE;
if (commandData) {
file = commandData.file;
promptOnly = commandData.promptOnly;
_forceClose = commandData._forceClose;
+ paneId = commandData.paneId || paneId;
}
- // utility function for handleFileClose: closes document & removes from working set
+ // utility function for handleFileClose: closes document & removes from workingset
function doClose(file) {
if (!promptOnly) {
- // This selects a different document if the working set has any other options
- DocumentManager.closeFullEditor(file);
-
- EditorManager.focusEditor();
+ MainViewManager._close(paneId, file);
}
}
var result = new $.Deferred(), promise = result.promise();
- function doCloseCustomViewer() {
- if (!promptOnly) {
- var nextFile = DocumentManager.getNextPrevFile(1);
- if (nextFile) {
- // opening a text file will automatically close the custom viewer.
- // This is done in the currentDocumentChange handler in EditorManager
- doOpen(nextFile.fullPath).always(function () {
- EditorManager.focusEditor();
- result.resolve();
- });
- } else {
- EditorManager._closeCustomViewer();
- result.resolve();
- }
- }
- }
-
- // Close custom viewer if, either
- // - a custom viewer is currently displayed and no file specified in command data
- // - a custom viewer is currently displayed and the file specified in command data
- // is the file in the custom viewer
- if (!DocumentManager.getCurrentDocument()) {
- if ((EditorManager.getCurrentlyViewedPath() && !file) ||
- (file && file.fullPath === EditorManager.getCurrentlyViewedPath())) {
- doCloseCustomViewer();
- return promise;
- }
- }
-
// Default to current document if doc is null
- if (!file && DocumentManager.getCurrentDocument()) {
- file = DocumentManager.getCurrentDocument().file;
+ if (!file) {
+ file = MainViewManager.getCurrentlyViewedFile(MainViewManager.ACTIVE_PANE);
}
// No-op if called when nothing is open; TODO: (issue #273) should command be grayed out instead?
@@ -1123,30 +1165,30 @@ define(function (require, exports, module) {
// we want to ignore errors during the revert, since we don't want a failed revert
// to throw a dialog if the document isn't actually open in the UI.
var suppressError = !DocumentManager.getOpenDocumentForPath(file.fullPath);
- doRevert(doc, suppressError)
+ _doRevert(doc, suppressError)
.then(result.resolve, result.reject);
}
}
});
result.always(function () {
- EditorManager.focusEditor();
+ MainViewManager.focusActivePane();
});
} else {
// File is not open, or IS open but Document not dirty: close immediately
doClose(file);
- EditorManager.focusEditor();
+ MainViewManager.focusActivePane();
result.resolve();
}
return promise;
}
/**
- * @param {!Array.} list
- * @param {boolean} promptOnly
- * @param {boolean} clearCurrentDoc
+ * @param {!Array.} list - the list of files to close
+ * @param {boolean} promptOnly - true to just prompt for saving documents with actually closing them.
* @param {boolean} _forceClose Whether to force all the documents to close even if they have unsaved changes. For unit testing only.
+ * @return {jQuery.Promise} promise that is resolved or rejected when the function finishes.
*/
- function _closeList(list, promptOnly, clearCurrentDoc, _forceClose) {
+ function _closeList(list, promptOnly, _forceClose) {
var result = new $.Deferred(),
unsavedDocs = [];
@@ -1222,7 +1264,7 @@ define(function (require, exports, module) {
result.done(function (listAfterSave) {
listAfterSave = listAfterSave || list;
if (!promptOnly) {
- DocumentManager.removeListFromWorkingSet(listAfterSave, clearCurrentDoc);
+ MainViewManager._closeList(MainViewManager.ALL_PANES, listAfterSave);
}
});
@@ -1230,7 +1272,7 @@ define(function (require, exports, module) {
}
/**
- * Closes all open documents; equivalent to calling handleFileClose() for each document, except
+ * Closes all open files; equivalent to calling handleFileClose() for each document, except
* that unsaved changes are confirmed once, in bulk.
* @param {?{promptOnly: boolean, _forceClose: boolean}}
* If promptOnly is true, only displays the relevant confirmation UI and does NOT
@@ -1241,20 +1283,24 @@ define(function (require, exports, module) {
* @return {$.Promise} a promise that is resolved when all files are closed
*/
function handleFileCloseAll(commandData) {
- return _closeList(DocumentManager.getWorkingSet(),
- (commandData && commandData.promptOnly), true, (commandData && commandData._forceClose)).done(function () {
- if (!DocumentManager.getCurrentDocument()) {
- EditorManager._closeCustomViewer();
- }
- });
+ return _closeList(MainViewManager.getAllOpenFiles(),
+ (commandData && commandData.promptOnly), (commandData && commandData._forceClose));
}
+
+ /**
+ * Closes a list of open files; equivalent to calling handleFileClose() for each document, except
+ * that unsaved changes are confirmed once, in bulk.
+ * @param {?{promptOnly: boolean, _forceClose: boolean}}
+ * If promptOnly is true, only displays the relevant confirmation UI and does NOT
+ * actually close any documents. This is useful when chaining close-all together with
+ * other user prompts that may be cancelable.
+ * If _forceClose is true, forces the files to close with no confirmation even if dirty.
+ * Should only be used for unit test cleanup.
+ * @return {$.Promise} a promise that is resolved when all files are closed
+ */
function handleFileCloseList(commandData) {
- return _closeList(commandData.fileList, false, false).done(function () {
- if (!DocumentManager.getCurrentDocument()) {
- EditorManager._closeCustomViewer();
- }
- });
+ return _closeList(commandData.fileList);
}
/**
@@ -1266,7 +1312,10 @@ define(function (require, exports, module) {
* @private
* Common implementation for close/quit/reload which all mostly
* the same except for the final step
- */
+ * @param {Object} commandData - (not referenced)
+ * @param {!function()} postCloseHandler - called after close
+ * @param {!function()} failHandler - called when the save fails to cancel closing the window
+ */
function _handleWindowGoingAway(commandData, postCloseHandler, failHandler) {
if (_windowGoingAway) {
//if we get called back while we're closing, then just return
@@ -1313,7 +1362,10 @@ define(function (require, exports, module) {
$(PopUpManager).triggerHandler("beforeMenuPopup");
}
- /** Confirms any unsaved changes, then closes the window */
+ /**
+ * Confirms any unsaved changes, then closes the window
+ * @param {Object} command data
+ */
function handleFileCloseWindow(commandData) {
return _handleWindowGoingAway(
commandData,
@@ -1332,9 +1384,8 @@ define(function (require, exports, module) {
// Prefer selected sidebar item (which could be a folder)
var entry = ProjectManager.getSelectedItem();
if (!entry) {
- // Else use current file (not selected in ProjectManager if not visible in tree or working set)
- var doc = DocumentManager.getCurrentDocument();
- entry = doc && doc.file;
+ // Else use current file (not selected in ProjectManager if not visible in tree or workingset)
+ entry = MainViewManager.getCurrentlyViewedFile();
}
if (entry) {
ProjectManager.renameItemInline(entry);
@@ -1368,8 +1419,7 @@ define(function (require, exports, module) {
*/
function detectDocumentNavEnd(event) {
if (event.keyCode === KeyEvent.DOM_VK_CONTROL) { // Ctrl key
- DocumentManager.finalizeDocumentNavigation();
-
+ MainViewManager.endTraversal();
_addedNavKeyHandler = false;
$(window.document.body).off("keyup", detectDocumentNavEnd);
}
@@ -1377,10 +1427,14 @@ define(function (require, exports, module) {
/** Navigate to the next/previous (MRU) document. Don't update MRU order yet */
function goNextPrevDoc(inc) {
- var file = DocumentManager.getNextPrevFile(inc);
- if (file) {
- DocumentManager.beginDocumentNavigation();
- CommandManager.execute(Commands.FILE_OPEN, { fullPath: file.fullPath });
+ var result = MainViewManager.traverseToNextViewByMRU(inc);
+ if (result) {
+ var file = result.file,
+ paneId = result.paneId;
+
+ MainViewManager.beginTraversal();
+ CommandManager.execute(Commands.FILE_OPEN, {fullPath: file.fullPath,
+ paneId: paneId });
// Listen for ending of Ctrl+Tab sequence
if (!_addedNavKeyHandler) {
@@ -1390,17 +1444,22 @@ define(function (require, exports, module) {
}
}
+ /** Next Doc command handler **/
function handleGoNextDoc() {
goNextPrevDoc(+1);
+
}
+ /** Previous Doc command handler **/
function handleGoPrevDoc() {
goNextPrevDoc(-1);
}
+ /** Show in File Tree command handler **/
function handleShowInTree() {
- ProjectManager.showInTree(DocumentManager.getCurrentDocument().file);
+ ProjectManager.showInTree(MainViewManager.getCurrentlyViewedFile(MainViewManager.ACTIVE_PANE));
}
+ /** Delete file command handler **/
function handleFileDelete() {
var entry = ProjectManager.getSelectedItem();
if (entry.isDirectory) {
@@ -1434,7 +1493,7 @@ define(function (require, exports, module) {
}
}
- /** Show the selected sidebar (tree or working set) item in Finder/Explorer */
+ /** Show the selected sidebar (tree or workingset) item in Finder/Explorer */
function handleShowInOS() {
var entry = ProjectManager.getSelectedItem();
if (entry) {
@@ -1522,16 +1581,27 @@ define(function (require, exports, module) {
_isReloading = false;
});
}
-
- function handleReload() {
+
+ /**
+ * Restarts brackets Handler
+ * @param {boolean=} loadWithoutExtensions - true to restart without extensions,
+ * otherwise extensions are loadeed as it is durning a typical boot
+ */
+ function handleReload(loadWithoutExtensions) {
var href = window.location.href,
params = new UrlParams();
// Make sure the Reload Without User Extensions parameter is removed
params.parse();
- if (params.get("reloadWithoutUserExts")) {
- params.remove("reloadWithoutUserExts");
+ if (loadWithoutExtensions) {
+ if (!params.get("reloadWithoutUserExts")) {
+ params.put("reloadWithoutUserExts", true);
+ }
+ } else {
+ if (params.get("reloadWithoutUserExts")) {
+ params.remove("reloadWithoutUserExts");
+ }
}
if (href.indexOf("?") !== -1) {
@@ -1549,29 +1619,11 @@ define(function (require, exports, module) {
}, 100);
}
- function handleReloadWithoutExts() {
- var href = window.location.href,
- params = new UrlParams();
-
- params.parse();
-
- if (!params.get("reloadWithoutUserExts")) {
- params.put("reloadWithoutUserExts", true);
- }
-
- if (href.indexOf("?") !== -1) {
- href = href.substring(0, href.indexOf("?"));
- }
-
- href += "?" + params.toString();
-
- // Give Mac native menus extra time to update shortcut highlighting.
- // Prevents the menu highlighting from getting messed up after reload.
- window.setTimeout(function () {
- browserReload(href);
- }, 100);
- }
+ /** Reload Without Extensions commnad handler **/
+ var handleReloadWithoutExts = _.partial(handleReload, true);
+
+ /** Do some initialization when the DOM is ready **/
AppInit.htmlReady(function () {
// If in Reload Without User Extensions mode, update UI and log console message
var params = new UrlParams(),
@@ -1607,27 +1659,37 @@ define(function (require, exports, module) {
showInOS = Strings.CMD_SHOW_IN_FINDER;
}
- // Register global commands
- CommandManager.register(Strings.CMD_FILE_OPEN, Commands.FILE_OPEN, handleFileOpen);
- CommandManager.register(Strings.CMD_ADD_TO_WORKING_SET, Commands.FILE_ADD_TO_WORKING_SET, handleFileAddToWorkingSet);
- CommandManager.register(Strings.CMD_FILE_NEW_UNTITLED, Commands.FILE_NEW_UNTITLED, handleFileNew);
- CommandManager.register(Strings.CMD_FILE_NEW, Commands.FILE_NEW, handleFileNewInProject);
- CommandManager.register(Strings.CMD_FILE_NEW_FOLDER, Commands.FILE_NEW_FOLDER, handleNewFolderInProject);
- CommandManager.register(Strings.CMD_FILE_SAVE, Commands.FILE_SAVE, handleFileSave);
- CommandManager.register(Strings.CMD_FILE_SAVE_ALL, Commands.FILE_SAVE_ALL, handleFileSaveAll);
- CommandManager.register(Strings.CMD_FILE_SAVE_AS, Commands.FILE_SAVE_AS, handleFileSaveAs);
- CommandManager.register(Strings.CMD_FILE_RENAME, Commands.FILE_RENAME, handleFileRename);
- CommandManager.register(Strings.CMD_FILE_DELETE, Commands.FILE_DELETE, handleFileDelete);
-
- CommandManager.register(Strings.CMD_FILE_CLOSE, Commands.FILE_CLOSE, handleFileClose);
- CommandManager.register(Strings.CMD_FILE_CLOSE_ALL, Commands.FILE_CLOSE_ALL, handleFileCloseAll);
- CommandManager.register(Strings.CMD_FILE_CLOSE_LIST, Commands.FILE_CLOSE_LIST, handleFileCloseList);
- CommandManager.register(quitString, Commands.FILE_QUIT, handleFileQuit);
-
- CommandManager.register(Strings.CMD_NEXT_DOC, Commands.NAVIGATE_NEXT_DOC, handleGoNextDoc);
- CommandManager.register(Strings.CMD_PREV_DOC, Commands.NAVIGATE_PREV_DOC, handleGoPrevDoc);
- CommandManager.register(Strings.CMD_SHOW_IN_TREE, Commands.NAVIGATE_SHOW_IN_FILE_TREE, handleShowInTree);
- CommandManager.register(showInOS, Commands.NAVIGATE_SHOW_IN_OS, handleShowInOS);
+ // Deprecated commands
+ CommandManager.register(Strings.CMD_ADD_TO_WORKING_SET, Commands.FILE_ADD_TO_WORKING_SET, handleFileAddToWorkingSet);
+ CommandManager.register(Strings.CMD_FILE_OPEN, Commands.FILE_OPEN, handleDocumentOpen);
+
+ // New commands
+ CommandManager.register(Strings.CMD_ADD_TO_WORKING_SET, Commands.CMD_ADD_TO_WORKINGSET_AND_OPEN, handleFileAddToWorkingSetAndOpen);
+ CommandManager.register(Strings.CMD_FILE_OPEN, Commands.CMD_OPEN, handleFileOpen);
+
+ // File Commands
+ CommandManager.register(Strings.CMD_FILE_NEW_UNTITLED, Commands.FILE_NEW_UNTITLED, handleFileNew);
+ CommandManager.register(Strings.CMD_FILE_NEW, Commands.FILE_NEW, handleFileNewInProject);
+ CommandManager.register(Strings.CMD_FILE_NEW_FOLDER, Commands.FILE_NEW_FOLDER, handleNewFolderInProject);
+ CommandManager.register(Strings.CMD_FILE_SAVE, Commands.FILE_SAVE, handleFileSave);
+ CommandManager.register(Strings.CMD_FILE_SAVE_ALL, Commands.FILE_SAVE_ALL, handleFileSaveAll);
+ CommandManager.register(Strings.CMD_FILE_SAVE_AS, Commands.FILE_SAVE_AS, handleFileSaveAs);
+ CommandManager.register(Strings.CMD_FILE_RENAME, Commands.FILE_RENAME, handleFileRename);
+ CommandManager.register(Strings.CMD_FILE_DELETE, Commands.FILE_DELETE, handleFileDelete);
+
+ // Close Commands
+ CommandManager.register(Strings.CMD_FILE_CLOSE, Commands.FILE_CLOSE, handleFileClose);
+ CommandManager.register(Strings.CMD_FILE_CLOSE_ALL, Commands.FILE_CLOSE_ALL, handleFileCloseAll);
+ CommandManager.register(Strings.CMD_FILE_CLOSE_LIST, Commands.FILE_CLOSE_LIST, handleFileCloseList);
+
+ // Traversal
+ CommandManager.register(Strings.CMD_NEXT_DOC, Commands.NAVIGATE_NEXT_DOC, handleGoNextDoc);
+ CommandManager.register(Strings.CMD_PREV_DOC, Commands.NAVIGATE_PREV_DOC, handleGoPrevDoc);
+
+ // Special Commands
+ CommandManager.register(showInOS, Commands.NAVIGATE_SHOW_IN_OS, handleShowInOS);
+ CommandManager.register(quitString, Commands.FILE_QUIT, handleFileQuit);
+ CommandManager.register(Strings.CMD_SHOW_IN_TREE, Commands.NAVIGATE_SHOW_IN_FILE_TREE, handleShowInTree);
// These commands have no UI representation and are only used internally
CommandManager.registerInternal(Commands.APP_ABORT_QUIT, handleAbortQuit);
@@ -1638,8 +1700,8 @@ define(function (require, exports, module) {
// Listen for changes that require updating the editor titlebar
$(DocumentManager).on("dirtyFlagChange", handleDirtyChange);
- $(DocumentManager).on("fileNameChange", updateDocumentTitle);
- $(EditorManager).on("currentlyViewedFileChange", updateDocumentTitle);
+ $(DocumentManager).on("fileNameChange", handleCurrentFileChange);
+ $(MainViewManager).on("currentFileChange", handleCurrentFileChange);
// Reset the untitled document counter before changing projects
$(ProjectManager).on("beforeProjectClose", function () { _nextUntitledIndexToUse = 1; });
diff --git a/src/document/DocumentManager.js b/src/document/DocumentManager.js
index ca4ecedd354..af108ccab92 100644
--- a/src/document/DocumentManager.js
+++ b/src/document/DocumentManager.js
@@ -26,8 +26,8 @@
/*global define, $ */
/**
- * DocumentManager maintains a list of currently 'open' Documents. It also owns the list of files in
- * the working set, and the notion of which Document is currently shown in the main editor UI area.
+ * DocumentManager maintains a list of currently 'open' Documents. The DocumentManager is responsible
+ * for coordinating document operations and dispatching certain document events.
*
* Document is the model for a file's contents; it dispatches events whenever those contents change.
* To transiently inspect a file's content, simply get a Document and call getText() on it. However,
@@ -40,9 +40,7 @@
* Secretly, a Document may use an Editor instance to act as the model for its internal state. (This
* is unavoidable because CodeMirror does not separate its model from its UI). Documents are not
* modifiable until they have a backing 'master Editor'. Creation of the backing Editor is owned by
- * EditorManager. A Document only gets a backing Editor if it becomes the currentDocument, or if edits
- * occur in any Editor (inline or full-sized) bound to the Document; there is currently no other way
- * to ensure a Document is modifiable.
+ * EditorManager. A Document only gets a backing Editor if it opened in an editor.
*
* A non-modifiable Document may still dispatch change notifications, if the Document was changed
* externally on disk.
@@ -59,26 +57,19 @@
* - documentRefreshed -- When a Document's contents have been reloaded from disk. The 2nd arg to the
* listener is the Document that has been refreshed.
*
- * - currentDocumentChange -- When the value of getCurrentDocument() changes. 2nd argument to the listener
- * is the current document and 3rd argument is the previous document.
+ * NOTE: WorkingSet APIs have been deprecated and have moved to MainViewManager as WorkingSet APIs
+ * Some WorkingSet APIs that have been identified as being used by 3rd party extensions will
+ * emit deprecation warnings and call the WorkingSet APIS to maintain backwards compatibility
*
- * To listen for working set changes, you must listen to *all* of these events:
- * - workingSetAdd -- When a file is added to the working set (see getWorkingSet()). The 2nd arg
- * to the listener is the added File, and the 3rd arg is the index it was inserted at.
- * - workingSetAddList -- When multiple files are added to the working set (e.g. project open, multiple file open).
- * The 2nd arg to the listener is the array of added File objects.
- * - workingSetRemove -- When a file is removed from the working set (see getWorkingSet()). The
- * 2nd arg to the listener is the removed File.
- * - workingSetRemoveList -- When multiple files are removed from the working set (e.g. project close).
- * The 2nd arg to the listener is the array of removed File objects.
- * - workingSetSort -- When the workingSet array is reordered without additions or removals.
- * Listener receives no arguments.
- *
- * - workingSetDisableAutoSorting -- Dispatched in addition to workingSetSort when the reorder was caused
- * by manual dragging and dropping. Listener receives no arguments.
+ * - currentDocumentChange -- Deprecated: use EditorManager activeEditorChange (which covers all editors,
+ * not just full-sized editors) or MainViewManager currentFileChange (which covers full-sized views
+ * only, but is also triggered for non-editor views e.g. image files).
*
* - fileNameChange -- When the name of a file or folder has changed. The 2nd arg is the old name.
- * The 3rd arg is the new name.
+ * The 3rd arg is the new name. Generally, however, file objects have already been changed by the
+ * time this event is dispatched so code that relies on matching the filename to a file object
+ * will need to compare the newname.
+ *
* - pathDeleted -- When a file or folder has been deleted. The 2nd arg is the path that was deleted.
*
* These are jQuery events, so to listen for them you do something like this:
@@ -91,37 +82,23 @@ define(function (require, exports, module) {
var _ = require("thirdparty/lodash");
- var DocumentModule = require("document/Document"),
- ProjectManager = require("project/ProjectManager"),
- EditorManager = require("editor/EditorManager"),
+ var AppInit = require("utils/AppInit"),
+ DocumentModule = require("document/Document"),
+ DeprecationWarning = require("utils/DeprecationWarning"),
+ MainViewManager = require("view/MainViewManager"),
+ MainViewFactory = require("view/MainViewFactory"),
FileSyncManager = require("project/FileSyncManager"),
FileSystem = require("filesystem/FileSystem"),
PreferencesManager = require("preferences/PreferencesManager"),
FileUtils = require("file/FileUtils"),
InMemoryFile = require("document/InMemoryFile"),
CommandManager = require("command/CommandManager"),
- Async = require("utils/Async"),
- PerfUtils = require("utils/PerfUtils"),
Commands = require("command/Commands"),
+ PerfUtils = require("utils/PerfUtils"),
LanguageManager = require("language/LanguageManager"),
Strings = require("strings");
- /**
- * @private
- * @see DocumentManager.getCurrentDocument()
- */
- var _currentDocument = null;
-
- /**
- * Returns the Document that is currently open in the editor UI. May be null.
- * When this changes, DocumentManager dispatches a "currentDocumentChange" event. The current
- * document always has a backing Editor (Document._masterEditor != null) and is thus modifiable.
- * @return {?Document}
- */
- function getCurrentDocument() {
- return _currentDocument;
- }
-
+
/**
* @private
* Random path prefix for untitled documents
@@ -129,81 +106,75 @@ define(function (require, exports, module) {
var _untitledDocumentPath = "/_brackets_" + _.random(10000000, 99999999);
/**
+ * All documents with refCount > 0. Maps Document.file.id -> Document.
* @private
- * @type {Array.}
- * @see DocumentManager.getWorkingSet()
- */
- var _workingSet = [];
-
- /**
- * @private
- * Contains the same set of items as _workingSet, but ordered by how recently they were _currentDocument (0 = most recent).
- * @type {Array.}
- */
- var _workingSetMRUOrder = [];
-
- /**
- * @private
- * Contains the same set of items as _workingSet, but ordered in the way they where added to _workingSet (0 = last added).
- * @type {Array.}
+ * @type {Object.}
*/
- var _workingSetAddedOrder = [];
-
+ var _openDocuments = {};
+
/**
- * While true, the MRU order is frozen
- * @type {boolean}
+ * Returns the existing open Document for the given file, or null if the file is not open ('open'
+ * means referenced by the UI somewhere). If you will hang onto the Document, you must addRef()
+ * it; see {@link getDocumentForPath()} for details.
+ * @param {!string} fullPath
+ * @return {?Document}
*/
- var _documentNavPending = false;
+ function getOpenDocumentForPath(fullPath) {
+ var id;
+
+ // Need to walk all open documents and check for matching path. We can't
+ // use getFileForPath(fullPath).id since the file it returns won't match
+ // an Untitled document's InMemoryFile.
+ for (id in _openDocuments) {
+ if (_openDocuments.hasOwnProperty(id)) {
+ if (_openDocuments[id].file.fullPath === fullPath) {
+ return _openDocuments[id];
+ }
+ }
+ }
+ return null;
+ }
/**
- * All documents with refCount > 0. Maps Document.file.id -> Document.
- * @private
- * @type {Object.}
+ * Returns the Document that is currently open in the editor UI. May be null.
+ * @return {?Document}
*/
- var _openDocuments = {};
+ function getCurrentDocument() {
+ var file = MainViewManager.getCurrentlyViewedFile(MainViewManager.ACTIVE_PANE);
+
+ if (file) {
+ return getOpenDocumentForPath(file.fullPath);
+ }
+
+ return null;
+ }
+
/**
* Returns a list of items in the working set in UI list order. May be 0-length, but never null.
- *
- * When a file is added this list, DocumentManager dispatches a "workingSetAdd" event.
- * When a file is removed from list, DocumentManager dispatches a "workingSetRemove" event.
- * To listen for ALL changes to this list, you must listen for both events.
- *
- * Which items belong in the working set is managed entirely by DocumentManager. Callers cannot
- * (yet) change this collection on their own.
- *
+ * @deprecated Use MainViewManager.getWorkingSet() instead
* @return {Array.}
*/
function getWorkingSet() {
- return _.clone(_workingSet);
+ DeprecationWarning.deprecationWarning("Use MainViewManager.getViews() instead of DocumentManager.getWorkingSet()", true);
+ return MainViewManager.getWorkingSet(MainViewManager.ALL_PANES)
+ .filter(function (file) {
+ // Legacy didn't allow for files with custom viewers
+ return !MainViewFactory.findSuitableFactoryForPath(file.fullPath);
+ });
}
/**
* Returns the index of the file matching fullPath in the working set.
- * Returns -1 if not found.
+ * @deprecated Use MainViewManager.findInWorkingSet() instead
* @param {!string} fullPath
- * @param {Array.=} list Pass this arg to search a different array of files. Internal
- * use only.
- * @return {number} index
+ * @return {number} index, -1 if not found
*/
- function findInWorkingSet(fullPath, list) {
- list = list || _workingSet;
-
- return _.findIndex(list, function (file, i) {
- return file.fullPath === fullPath;
- });
+ function findInWorkingSet(fullPath) {
+ DeprecationWarning.deprecationWarning("Use MainViewManager.findInWorkingSet() instead of DocumentManager.findInWorkingSet()", true);
+ return MainViewManager.findInWorkingSet(MainViewManager.ACTIVE_PANE, fullPath);
}
- /**
- * Returns the index of the file matching fullPath in _workingSetAddedOrder.
- * Returns -1 if not found.
- * @param {!string} fullPath
- * @return {number} index
- */
- function findInWorkingSetAddedOrder(fullPath) {
- return findInWorkingSet(fullPath, _workingSetAddedOrder);
- }
-
/**
* Returns all Documents that are 'open' in the UI somewhere (for now, this means open in an
* inline editor and/or a full-size editor). Only these Documents can be modified, and only
@@ -223,60 +194,20 @@ define(function (require, exports, module) {
/**
- * Adds the given file to the end of the working set list, if it is not already in the list
- * and it does not have a custom viewer.
- * Does not change which document is currently open in the editor. Completes synchronously.
+ * Adds the given file to the end of the working set list.
+ * @deprecated Use MainViewManager.addToWorkingSet() instead
* @param {!File} file
* @param {number=} index Position to add to list (defaults to last); -1 is ignored
* @param {boolean=} forceRedraw If true, a working set change notification is always sent
* (useful if suppressRedraw was used with removeFromWorkingSet() earlier)
*/
function addToWorkingSet(file, index, forceRedraw) {
- var indexRequested = (index !== undefined && index !== null && index !== -1);
-
- // If the file has a custom viewer, then don't add it to the working set.
- if (EditorManager.getCustomViewerForPath(file.fullPath)) {
- return;
- }
-
- // If doc is already in working set, don't add it again
- var curIndex = findInWorkingSet(file.fullPath);
- if (curIndex !== -1) {
- // File is in working set, but not at the specifically requested index - only need to reorder
- if (forceRedraw || (indexRequested && curIndex !== index)) {
- var entry = _workingSet.splice(curIndex, 1)[0];
- _workingSet.splice(index, 0, entry);
- $(exports).triggerHandler("workingSetSort");
- }
- return;
- }
-
- if (!indexRequested) {
- // If no index is specified, just add the file to the end of the working set.
- _workingSet.push(file);
- } else {
- // If specified, insert into the working set list at this 0-based index
- _workingSet.splice(index, 0, file);
- }
-
- // Add to MRU order: either first or last, depending on whether it's already the current doc or not
- if (_currentDocument && _currentDocument.file.fullPath === file.fullPath) {
- _workingSetMRUOrder.unshift(file);
- } else {
- _workingSetMRUOrder.push(file);
- }
-
- // Add first to Added order
- _workingSetAddedOrder.unshift(file);
-
- // Dispatch event
- if (!indexRequested) {
- index = _workingSet.length - 1;
- }
- $(exports).triggerHandler("workingSetAdd", [file, index]);
+ DeprecationWarning.deprecationWarning("Use MainViewManager.addToWorkingSet() instead of DocumentManager.addToWorkingSet()", true);
+ MainViewManager.addToWorkingSet(MainViewManager.ACTIVE_PANE, file, index, forceRedraw);
}
/**
+ * @deprecated Use MainViewManager.addListToWorkingSet() instead
* Adds the given file list to the end of the working set list.
* If a file in the list has its own custom viewer, then it
* is not added into the working set.
@@ -286,330 +217,80 @@ define(function (require, exports, module) {
* @param {!Array.} fileList
*/
function addListToWorkingSet(fileList) {
- var uniqueFileList = [];
-
- // Process only files not already in working set
- fileList.forEach(function (file, index) {
- // If doc has a custom viewer, then don't add it to the working set.
- // Or if doc is already in working set, don't add it again.
- if (!EditorManager.getCustomViewerForPath(file.fullPath) &&
- findInWorkingSet(file.fullPath) === -1) {
- uniqueFileList.push(file);
-
- // Add
- _workingSet.push(file);
-
- // Add to MRU order: either first or last, depending on whether it's already the current doc or not
- if (_currentDocument && _currentDocument.file.fullPath === file.fullPath) {
- _workingSetMRUOrder.unshift(file);
- } else {
- _workingSetMRUOrder.push(file);
- }
-
- // Add first to Added order
- _workingSetAddedOrder.splice(index, 1, file);
- }
- });
-
-
- // Dispatch event
- $(exports).triggerHandler("workingSetAddList", [uniqueFileList]);
+ DeprecationWarning.deprecationWarning("Use MainViewManager.addListToWorkingSet() instead of DocumentManager.addListToWorkingSet()", true);
+ MainViewManager.addListToWorkingSet(MainViewManager.ACTIVE_PANE, fileList);
}
+
/**
- * Warning: low level API - use FILE_CLOSE command in most cases.
- * Removes the given file from the working set list, if it was in the list. Does not change
- * the current editor even if it's for this file. Does not prompt for unsaved changes.
- * @param {!File} file
- * @param {boolean=} true to suppress redraw after removal
*/
- function removeFromWorkingSet(file, suppressRedraw) {
- // If doc isn't in working set, do nothing
- var index = findInWorkingSet(file.fullPath);
- if (index === -1) {
- return;
- }
-
- // Remove
- _workingSet.splice(index, 1);
- _workingSetMRUOrder.splice(findInWorkingSet(file.fullPath, _workingSetMRUOrder), 1);
- _workingSetAddedOrder.splice(findInWorkingSet(file.fullPath, _workingSetAddedOrder), 1);
-
- // Dispatch event
- $(exports).triggerHandler("workingSetRemove", [file, suppressRedraw]);
+ function removeListFromWorkingSet(list) {
+ throw new Error("removeListFromWorkingSet() has been deprecated. Use Command.FILE_CLOSE_LIST instead.");
}
-
+
/**
- * Removes all files from the working set list.
+ * closes all open files
+ * @deprecated Use MainViewManager._closeAll() instead
+ * Calling this discards any unsaved changes, so the UI should confirm with the user before calling this.
*/
- function _removeAllFromWorkingSet() {
- var fileList = _workingSet;
-
- // Remove all
- _workingSet = [];
- _workingSetMRUOrder = [];
- _workingSetAddedOrder = [];
-
- // Dispatch event
- $(exports).triggerHandler("workingSetRemoveList", [fileList]);
+ function closeAll() {
+ DeprecationWarning.deprecationWarning("Use MainViewManager._closeAll() instead of DocumentManager.closeAll()", true);
+ CommandManager.execute(Commands.FILE_CLOSE_ALL, {PaneId: MainViewManager.ALL_PANES});
}
/**
- * Moves document to the front of the MRU list, IF it's in the working set; no-op otherwise.
- * @param {!Document}
- */
- function _markMostRecent(doc) {
- var mruI = findInWorkingSet(doc.file.fullPath, _workingSetMRUOrder);
- if (mruI !== -1) {
- _workingSetMRUOrder.splice(mruI, 1);
- _workingSetMRUOrder.unshift(doc.file);
- }
- }
-
-
- /**
- * Mutually exchanges the files at the indexes passed by parameters.
- * @param {number} index Old file index
- * @param {number} index New file index
+ * closes the specified file file
+ * @deprecated use MainViewManager._close() instead
+ * @param {!File} file
*/
- function swapWorkingSetIndexes(index1, index2) {
- var length = _workingSet.length - 1;
- var temp;
-
- if (index1 >= 0 && index2 <= length && index1 >= 0 && index2 <= length) {
- temp = _workingSet[index1];
- _workingSet[index1] = _workingSet[index2];
- _workingSet[index2] = temp;
-
- $(exports).triggerHandler("workingSetSort");
- $(exports).triggerHandler("workingSetDisableAutoSorting");
- }
+ function closeFullEditor(file) {
+ DeprecationWarning.deprecationWarning("Use MainViewManager._close() instead of DocumentManager.closeFullEditor()", true);
+ CommandManager.execute(Commands.FILE_CLOSE, {File: file});
}
/**
- * Sorts _workingSet using the compare function
- * @param {function(File, File): number} compareFn The function that will be used inside JavaScript's
- * sort function. The return a value should be >0 (sort a to a lower index than b), =0 (leaves a and b
- * unchanged with respect to each other) or <0 (sort b to a lower index than a) and must always returns
- * the same value when given a specific pair of elements a and b as its two arguments.
- * Documentation: https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/sort
+ * opens the specified document for editing in the currently active pane
+ * @deprecated use MainViewManager._edit() instead
+ * @param {!Document} document The Document to make current.
*/
- function sortWorkingSet(compareFn) {
- _workingSet.sort(compareFn);
- $(exports).triggerHandler("workingSetSort");
+ function setCurrentDocument(doc) {
+ DeprecationWarning.deprecationWarning("Use CommandManager.execute(Commands.CMD_OPEN) instead of DocumentManager.setCurrentDocument()", true);
+ CommandManager.execute(Commands.CMD_OPEN, {fullPath: doc.file.fullPath});
}
-
+
/**
- * Indicate that changes to currentDocument are temporary for now, and should not update the MRU
- * ordering of the working set. Useful for next/previous keyboard navigation (until Ctrl is released)
- * or for incremental-search style document preview like Quick Open will eventually have.
- * Can be called any number of times, and ended by a single finalizeDocumentNavigation() call.
+ * freezes the Working Set MRU list
+ * @deprecated use MainViewManager.beginTraversal() instead
*/
function beginDocumentNavigation() {
- _documentNavPending = true;
+ DeprecationWarning.deprecationWarning("Use MainViewManager.beginTraversal() instead of DocumentManager.beginDocumentNavigation()", true);
+ MainViewManager.beginTraversal();
}
/**
- * Un-freezes the MRU list after one or more beginDocumentNavigation() calls. Whatever document is
- * current is bumped to the front of the MRU list.
+ * ends document navigation and moves the current file to the front of the MRU list in the Working Set
+ * @deprecated use MainViewManager.endTraversal() instead
*/
function finalizeDocumentNavigation() {
- if (_documentNavPending) {
- _documentNavPending = false;
-
- _markMostRecent(_currentDocument);
- }
+ DeprecationWarning.deprecationWarning("Use MainViewManager.endTraversal() instead of DocumentManager.finalizeDocumentNavigation()", true);
+ MainViewManager.endTraversal();
}
-
/**
* Get the next or previous file in the working set, in MRU order (relative to currentDocument). May
* return currentDocument itself if working set is length 1.
- * @param {number} inc -1 for previous, +1 for next; no other values allowed
- * @return {?File} null if working set empty
+ * @deprecated use MainViewManager.traverseToNextViewByMRU() instead
*/
function getNextPrevFile(inc) {
- if (inc !== -1 && inc !== +1) {
- console.error("Illegal argument: inc = " + inc);
- return null;
+ DeprecationWarning.deprecationWarning("Use MainViewManager.traverseToNextViewByMRU() instead of DocumentManager.getNextPrevFile()", true);
+ var result = MainViewManager.traverseToNextViewByMRU(inc);
+ if (result) {
+ return result.file;
}
-
- if (EditorManager.getCurrentlyViewedPath()) {
- var mruI = findInWorkingSet(EditorManager.getCurrentlyViewedPath(), _workingSetMRUOrder);
- if (mruI === -1) {
- // If doc not in working set, return most recent working set item
- if (_workingSetMRUOrder.length > 0) {
- return _workingSetMRUOrder[0];
- }
- } else {
- // If doc is in working set, return next/prev item with wrap-around
- var newI = mruI + inc;
- if (newI >= _workingSetMRUOrder.length) {
- newI = 0;
- } else if (newI < 0) {
- newI = _workingSetMRUOrder.length - 1;
- }
-
- return _workingSetMRUOrder[newI];
- }
- }
-
- // If no doc open or working set empty, there is no "next" file
return null;
}
-
- /**
- * Changes currentDocument to the given Document, firing currentDocumentChange, which in turn
- * causes this Document's main editor UI to be shown in the editor pane, updates the selection
- * in the file tree / working set UI, etc. This call may also add the item to the working set.
- *
- * @param {!Document} document The Document to make current. May or may not already be in the
- * working set.
- */
- function setCurrentDocument(doc) {
-
- // If this doc is already current, do nothing
- if (_currentDocument === doc) {
- return;
- }
-
- var perfTimerName = PerfUtils.markStart("setCurrentDocument:\t" + doc.file.fullPath);
-
- if (_currentDocument) {
- $(_currentDocument).off("languageChanged.DocumentManager");
- }
-
- // If file is untitled or otherwise not within project tree, add it to
- // working set right now (don't wait for it to become dirty)
- if (doc.isUntitled() || !ProjectManager.isWithinProject(doc.file.fullPath)) {
- addToWorkingSet(doc.file);
- }
-
- // Adjust MRU working set ordering (except while in the middle of a Ctrl+Tab sequence)
- if (!_documentNavPending) {
- _markMostRecent(doc);
- }
-
- // Make it the current document
- var previousDocument = _currentDocument;
- _currentDocument = doc;
-
- // Proxy this doc's languageChange events as long as it's current
- $(_currentDocument).on("languageChanged.DocumentManager", function (data) {
- $(exports).trigger("currentDocumentLanguageChanged", data);
- });
-
- $(exports).triggerHandler("currentDocumentChange", [_currentDocument, previousDocument]);
- // (this event triggers EditorManager to actually switch editors in the UI)
-
- PerfUtils.addMeasurement(perfTimerName);
- }
-
-
- /** Changes currentDocument to null, causing no full Editor to be shown in the UI */
- function _clearCurrentDocument() {
- // If editor already blank, do nothing
- if (!_currentDocument) {
- return;
- } else {
- // Change model & dispatch event
- var previousDocument = _currentDocument;
- _currentDocument = null;
- // (this event triggers EditorManager to actually clear the editor UI)
- $(exports).triggerHandler("currentDocumentChange", [_currentDocument, previousDocument]);
- }
- }
-
-
-
- /**
- * Warning: low level API - use FILE_CLOSE command in most cases.
- * Closes the full editor for the given file (if there is one), and removes it from the working
- * set. Any other editors for this Document remain open. Discards any unsaved changes without prompting.
- *
- * Changes currentDocument if this file was the current document (may change to null).
- *
- * This is a subset of notifyFileDeleted(). Use this for the user-facing Close command.
- *
- * @param {!File} file
- * @param {boolean} skipAutoSelect - if true, don't automatically open and select the next document
- */
- function closeFullEditor(file, skipAutoSelect) {
- // If this was the current document shown in the editor UI, we're going to switch to a
- // different document (or none if working set has no other options)
- if (_currentDocument && _currentDocument.file.fullPath === file.fullPath) {
- // Get next most recent doc in the MRU order
- var nextFile = getNextPrevFile(1);
- if (nextFile && nextFile.fullPath === _currentDocument.file.fullPath) {
- // getNextPrevFile() might return the file we're about to close if it's the only one open (due to wraparound)
- nextFile = null;
- }
-
- // Switch editor to next document (or blank it out)
- if (nextFile && !skipAutoSelect) {
- CommandManager.execute(Commands.FILE_OPEN, { fullPath: nextFile.fullPath })
- .done(function () {
- // (Now we're guaranteed that the current document is not the one we're closing)
- console.assert(!(_currentDocument && _currentDocument.file.fullPath === file.fullPath));
- })
- .fail(function () {
- // File chosen to be switched to could not be opened, and the original file
- // is still in editor. Close it again so code will try to open the next file,
- // or empty the editor if there are no other files.
- closeFullEditor(file);
- });
- } else {
- _clearCurrentDocument();
- }
- }
-
- // Remove closed doc from working set, if it was in there
- // This happens regardless of whether the document being closed was the current one or not
- removeFromWorkingSet(file);
-
- // Note: EditorManager will dispose the closed document's now-unneeded editor either in
- // response to the editor-swap call above, or the removeFromWorkingSet() call, depending on
- // circumstances. See notes in EditorManager for more.
- }
-
- /**
- * Equivalent to calling closeFullEditor() for all Documents. Same caveat: this discards any
- * unsaved changes, so the UI should confirm with the user before calling this.
- */
- function closeAll() {
- _clearCurrentDocument();
- _removeAllFromWorkingSet();
- }
-
- function removeListFromWorkingSet(list, clearCurrentDocument) {
- var fileList = [], index;
-
- if (!list) {
- return;
- }
-
- if (clearCurrentDocument) {
- _clearCurrentDocument();
- }
-
- list.forEach(function (file) {
- index = findInWorkingSet(file.fullPath);
-
- if (index !== -1) {
- fileList.push(_workingSet[index]);
-
- _workingSet.splice(index, 1);
- _workingSetMRUOrder.splice(findInWorkingSet(file.fullPath, _workingSetMRUOrder), 1);
- _workingSetAddedOrder.splice(findInWorkingSet(file.fullPath, _workingSetAddedOrder), 1);
- }
- });
-
- $(exports).triggerHandler("workingSetRemoveList", [fileList]);
- }
-
-
/**
* Cleans up any loose Documents whose only ref is its own master Editor, and that Editor is not
* rooted in the UI anywhere. This can happen if the Editor is auto-created via Document APIs that
@@ -621,33 +302,11 @@ define(function (require, exports, module) {
// Is the only ref to this document its own master Editor?
if (doc._refCount === 1 && doc._masterEditor) {
// Destroy the Editor if it's not being kept alive by the UI
- EditorManager._destroyEditorIfUnneeded(doc);
+ MainViewManager._destroyEditorIfNotNeeded(doc);
}
});
}
- /**
- * Returns the existing open Document for the given file, or null if the file is not open ('open'
- * means referenced by the UI somewhere). If you will hang onto the Document, you must addRef()
- * it; see {@link getDocumentForPath()} for details.
- * @param {!string} fullPath
- * @return {?Document}
- */
- function getOpenDocumentForPath(fullPath) {
- var id;
-
- // Need to walk all open documents and check for matching path. We can't
- // use getFileForPath(fullPath).id since the file it returns won't match
- // an Untitled document's InMemoryFile.
- for (id in _openDocuments) {
- if (_openDocuments.hasOwnProperty(id)) {
- if (_openDocuments[id].file.fullPath === fullPath) {
- return _openDocuments[id];
- }
- }
- }
- return null;
- }
/**
* Gets an existing open Document for the given file, or creates a new one if the Document is
@@ -809,10 +468,9 @@ define(function (require, exports, module) {
* @param {boolean} skipAutoSelect - if true, don't automatically open/select the next document
*/
function notifyFileDeleted(file, skipAutoSelect) {
- // First ensure it's not currentDocument, and remove from working set
- closeFullEditor(file, skipAutoSelect);
-
- // Notify all other editors to close as well
+ // Notify all editors to close as well
+ $(exports).triggerHandler("pathDeleted", file.fullPath);
+
var doc = getOpenDocumentForPath(file.fullPath);
if (doc) {
$(doc).triggerHandler("deleted");
@@ -820,100 +478,22 @@ define(function (require, exports, module) {
// At this point, all those other views SHOULD have released the Doc
if (doc && doc._refCount > 0) {
- console.log("WARNING: deleted Document still has " + doc._refCount + " references. Did someone addRef() without listening for 'deleted'?");
+ console.warn("Deleted " + file.fullPath + " Document still has " + doc._refCount + " references. Did someone addRef() without listening for 'deleted'?");
}
}
-
-
- /**
- * @private
- * Preferences callback. Saves the state of the working set.
- */
- function _savePreferences() {
- // save the working set file paths
- var files = [],
- isActive = false,
- workingSet = getWorkingSet(),
- currentDoc = getCurrentDocument(),
- projectRoot = ProjectManager.getProjectRoot(),
- context = { location : { scope: "user",
- layer: "project",
- layerID: projectRoot.fullPath } };
-
- if (!projectRoot) {
- return;
- }
-
- workingSet.forEach(function (file, index) {
- // Do not persist untitled document paths
- if (!(file instanceof InMemoryFile)) {
- // flag the currently active editor
- isActive = currentDoc && (file.fullPath === currentDoc.file.fullPath);
-
- // save editor UI state for just the working set
- var viewState = EditorManager._getViewState(file.fullPath);
-
- files.push({
- file: file.fullPath,
- active: isActive,
- viewState: viewState
- });
- }
- });
-
- // Writing out working set files using the project layer specified in 'context'.
- PreferencesManager.setViewState("project.files", files, context);
- }
/**
- * @private
- * Initializes the working set.
+ * Called after a file or folder has been deleted. This function is responsible
+ * for updating underlying model data and notifying all views of the change.
+ *
+ * @param {string} path The path of the file/folder that has been deleted
*/
- function _projectOpen(e) {
- // file root is appended for each project
- var projectRoot = ProjectManager.getProjectRoot(),
- files = [],
- context = { location : { scope: "user",
- layer: "project" } };
-
- files = PreferencesManager.getViewState("project.files", context);
-
- console.assert(Object.keys(_openDocuments).length === 0); // no files leftover from prev proj
-
- if (!files) {
- return;
- }
-
- var filesToOpen = [],
- viewStates = {},
- activeFile;
-
- // Add all files to the working set without verifying that
- // they still exist on disk (for faster project switching)
- files.forEach(function (value, index) {
- filesToOpen.push(FileSystem.getFileForPath(value.file));
- if (value.active) {
- activeFile = value.file;
- }
- if (value.viewState) {
- viewStates[value.file] = value.viewState;
- }
- });
- addListToWorkingSet(filesToOpen);
-
- // Allow for restoring saved editor UI state
- EditorManager._resetViewStates(viewStates);
-
- // Initialize the active editor
- if (!activeFile && _workingSet.length > 0) {
- activeFile = _workingSet[0].fullPath;
- }
-
- if (activeFile) {
- var promise = CommandManager.execute(Commands.FILE_OPEN, { fullPath: activeFile });
- // Add this promise to the event's promises to signal that this handler isn't done yet
- e.promises.push(promise);
- }
+ function notifyPathDeleted(path) {
+ /* FileSyncManager.syncOpenDocuments() does all the work of closing files
+ in the working set and notifying the user of any unsaved changes. */
+ FileSyncManager.syncOpenDocuments(Strings.FILE_DELETED_TITLE);
+ // Send a "pathDeleted" event. This will trigger the views to update.
+ $(exports).triggerHandler("pathDeleted", path);
}
/**
@@ -937,20 +517,6 @@ define(function (require, exports, module) {
$(exports).triggerHandler("fileNameChange", [oldName, newName]);
}
- /**
- * Called after a file or folder has been deleted. This function is responsible
- * for updating underlying model data and notifying all views of the change.
- *
- * @param {string} path The path of the file/folder that has been deleted
- */
- function notifyPathDeleted(path) {
- /* FileSyncManager.syncOpenDocuments() does all the work of closing files
- in the working set and notifying the user of any unsaved changes. */
- FileSyncManager.syncOpenDocuments(Strings.FILE_DELETED_TITLE);
-
- // Send a "pathDeleted" event. This will trigger the views to update.
- $(exports).triggerHandler("pathDeleted", path);
- }
/**
* @private
@@ -1007,7 +573,7 @@ define(function (require, exports, module) {
.on("_dirtyFlagChange", function (event, doc) {
$(exports).triggerHandler("dirtyFlagChange", doc);
if (doc.isDirty) {
- addToWorkingSet(doc.file);
+ MainViewManager.addToWorkingSet(MainViewManager.ACTIVE_PANE, doc.file);
}
})
.on("_documentSaved", function (event, doc) {
@@ -1035,6 +601,40 @@ define(function (require, exports, module) {
return null;
}
+ /**
+ * Creates a deprecation warning event handler
+ * @param {!string} eventName - the event being deprecated.
+ * The Event Name doesn't change just which object dispatches it
+ */
+ function _deprecateEvent(eventName) {
+ DeprecationWarning.deprecateEvent(exports,
+ MainViewManager,
+ eventName,
+ eventName,
+ "DocumentManager." + eventName,
+ "MainViewManager." + eventName);
+ }
+
+ /*
+ * Setup an extensionsLoaded handler to register deprecated events.
+ * We do this so these events are added to the end of the event
+ * handler chain which gives the system a chance to process them
+ * before they are dispatched to extensions.
+ *
+ * Extensions that listen to the new MainViewManager working set events
+ * are always added to the end so this effectively puts the legacy events
+ * at the end of the event list. This prevents extensions from
+ * handling the event too soon. (e.g. workingSetListView needs to
+ * process these events before the Extension Highlighter extension)
+ */
+ AppInit.extensionsLoaded(function () {
+ _deprecateEvent("workingSetAdd");
+ _deprecateEvent("workingSetAddList");
+ _deprecateEvent("workingSetRemove");
+ _deprecateEvent("workingSetRemoveList");
+ _deprecateEvent("workingSetSort");
+ });
+
PreferencesManager.convertPreferences(module, {"files_": "user"}, true, _checkPreferencePrefix);
// Handle file saves that may affect preferences
@@ -1042,33 +642,60 @@ define(function (require, exports, module) {
PreferencesManager.fileChanged(doc.file.fullPath);
});
- // For unit tests and internal use only
- exports._clearCurrentDocument = _clearCurrentDocument;
+ $(MainViewManager).on("currentFileChange", function (e, newFile, newPaneId, oldFile, oldPaneId) {
+ var newDoc = null,
+ oldDoc = null;
+
+ if (newFile) {
+ newDoc = getOpenDocumentForPath(newFile.fullPath);
+ }
+
+ if (oldFile) {
+ oldDoc = getOpenDocumentForPath(oldFile.fullPath);
+ }
+
+ if (oldDoc) {
+ $(oldDoc).off("languageChanged.DocumentManager");
+ }
+
+ if (newDoc !== oldDoc) {
+ var count = DeprecationWarning.getEventHandlerCount(exports, "currentDocumentChange");
+ if (count > 0) {
+ DeprecationWarning.deprecationWarning("The Event 'DocumentManager.currentDocumentChange' has been deprecated. Please use 'MainViewManager.currentFileChange' instead.", true);
+ }
+
+ $(exports).triggerHandler("currentDocumentChange", [newDoc, oldDoc]);
+ }
+
+ if (newDoc) {
+ $(newDoc).on("languageChanged.DocumentManager", function (data) {
+ $(exports).trigger("currentDocumentLanguageChanged", data);
+ });
+ }
+
+ });
+
+ // Deprecated APIs
+ exports.getWorkingSet = getWorkingSet;
+ exports.findInWorkingSet = findInWorkingSet;
+ exports.addToWorkingSet = addToWorkingSet;
+ exports.addListToWorkingSet = addListToWorkingSet;
+ exports.removeListFromWorkingSet = removeListFromWorkingSet;
+ exports.getCurrentDocument = getCurrentDocument;
+ exports.beginDocumentNavigation = beginDocumentNavigation;
+ exports.finalizeDocumentNavigation = finalizeDocumentNavigation;
+ exports.getNextPrevFile = getNextPrevFile;
+ exports.setCurrentDocument = setCurrentDocument;
+ exports.closeFullEditor = closeFullEditor;
+ exports.closeAll = closeAll;
// Define public API
exports.Document = DocumentModule.Document;
- exports.getCurrentDocument = getCurrentDocument;
- exports._clearCurrentDocument = _clearCurrentDocument;
exports.getDocumentForPath = getDocumentForPath;
exports.getOpenDocumentForPath = getOpenDocumentForPath;
exports.getDocumentText = getDocumentText;
exports.createUntitledDocument = createUntitledDocument;
- exports.getWorkingSet = getWorkingSet;
- exports.findInWorkingSet = findInWorkingSet;
- exports.findInWorkingSetAddedOrder = findInWorkingSetAddedOrder;
exports.getAllOpenDocuments = getAllOpenDocuments;
- exports.setCurrentDocument = setCurrentDocument;
- exports.addToWorkingSet = addToWorkingSet;
- exports.addListToWorkingSet = addListToWorkingSet;
- exports.removeFromWorkingSet = removeFromWorkingSet;
- exports.removeListFromWorkingSet = removeListFromWorkingSet;
- exports.getNextPrevFile = getNextPrevFile;
- exports.swapWorkingSetIndexes = swapWorkingSetIndexes;
- exports.sortWorkingSet = sortWorkingSet;
- exports.beginDocumentNavigation = beginDocumentNavigation;
- exports.finalizeDocumentNavigation = finalizeDocumentNavigation;
- exports.closeFullEditor = closeFullEditor;
- exports.closeAll = closeAll;
exports.notifyFileDeleted = notifyFileDeleted;
exports.notifyPathNameChanged = notifyPathNameChanged;
exports.notifyPathDeleted = notifyPathDeleted;
@@ -1076,11 +703,6 @@ define(function (require, exports, module) {
// Performance measurements
PerfUtils.createPerfMeasurement("DOCUMENT_MANAGER_GET_DOCUMENT_FOR_PATH", "DocumentManager.getDocumentForPath()");
- // Handle project change events
- var $ProjectManager = $(ProjectManager);
- $ProjectManager.on("projectOpen", _projectOpen);
- $ProjectManager.on("beforeProjectClose beforeAppClose", _savePreferences);
-
// Handle Language change events
$(LanguageManager).on("languageAdded", _handleLanguageAdded);
$(LanguageManager).on("languageModified", _handleLanguageModified);
diff --git a/src/document/InMemoryFile.js b/src/document/InMemoryFile.js
index a62f3a8a763..01eab4876c7 100644
--- a/src/document/InMemoryFile.js
+++ b/src/document/InMemoryFile.js
@@ -23,7 +23,7 @@
/*jslint vars: true, plusplus: true, devel: true, nomen: true, regexp: true, indent: 4, maxerr: 50 */
-/*global define, $ */
+/*global define */
/**
* Represents a file that will never exist on disk - a placeholder backing file for untitled Documents. NO ONE
diff --git a/src/editor/CSSInlineEditor.js b/src/editor/CSSInlineEditor.js
index 542490dacdd..18524091f20 100644
--- a/src/editor/CSSInlineEditor.js
+++ b/src/editor/CSSInlineEditor.js
@@ -23,7 +23,7 @@
/*jslint regexp: true, vars: true, plusplus: true, devel: true, nomen: true, indent: 4, maxerr: 50 */
-/*global define, $, window, Mustache */
+/*global define, $ */
define(function (require, exports, module) {
"use strict";
diff --git a/src/editor/CodeHintList.js b/src/editor/CodeHintList.js
index a1e54edce50..c43e1303058 100644
--- a/src/editor/CodeHintList.js
+++ b/src/editor/CodeHintList.js
@@ -22,7 +22,7 @@
*/
/*jslint vars: true, plusplus: true, devel: true, nomen: true, indent: 4, maxerr: 50 */
-/*global define, $, window, brackets, Mustache */
+/*global define, $, window, Mustache */
define(function (require, exports, module) {
"use strict";
diff --git a/src/editor/CodeHintManager.js b/src/editor/CodeHintManager.js
index 51270da1159..6363ed2306d 100644
--- a/src/editor/CodeHintManager.js
+++ b/src/editor/CodeHintManager.js
@@ -22,7 +22,7 @@
*/
/*jslint vars: true, plusplus: true, devel: true, nomen: true, indent: 4, maxerr: 50 */
-/*global define, $, brackets */
+/*global define, $ */
/*
* __CodeHintManager Overview:__
@@ -318,9 +318,7 @@ define(function (require, exports, module) {
* to all languages.
*/
function _removeHintProvider(provider, targetLanguageId) {
- var languageId,
- languages,
- index,
+ var index,
providers,
targetLanguageIdArr;
diff --git a/src/editor/Editor.js b/src/editor/Editor.js
index 2682195b7a6..c426ed7b450 100644
--- a/src/editor/Editor.js
+++ b/src/editor/Editor.js
@@ -54,6 +54,8 @@
* - optionChange -- Triggered when an option for the editor is changed. The 2nd arg to the listener
* is a string containing the editor option that is changing. The 3rd arg, which can be any
* data type, is the new value for the editor option.
+ * - beforeDestroy - Triggered before the object is about to dispose of all its internal state data
+ * so that listeners can cache things like scroll pos, etc...
*
* The Editor also dispatches "change" events internally, but you should listen for those on
* Documents, not Editors.
@@ -71,7 +73,6 @@ define(function (require, exports, module) {
PerfUtils = require("utils/PerfUtils"),
PopUpManager = require("widgets/PopUpManager"),
PreferencesManager = require("preferences/PreferencesManager"),
- Strings = require("strings"),
TextRange = require("document/TextRange").TextRange,
TokenUtils = require("utils/TokenUtils"),
ValidationUtils = require("utils/ValidationUtils"),
@@ -79,18 +80,19 @@ define(function (require, exports, module) {
_ = require("thirdparty/lodash");
/** Editor preferences */
- var CLOSE_BRACKETS = "closeBrackets",
- CLOSE_TAGS = "closeTags",
- HIGHLIGHT_MATCHES = "highlightMatches",
- SCROLL_PAST_END = "scrollPastEnd",
- SHOW_LINE_NUMBERS = "showLineNumbers",
- SMART_INDENT = "smartIndent",
- SOFT_TABS = "softTabs",
- SPACE_UNITS = "spaceUnits",
- STYLE_ACTIVE_LINE = "styleActiveLine",
- TAB_SIZE = "tabSize",
- WORD_WRAP = "wordWrap",
- USE_TAB_CHAR = "useTabChar";
+ var CLOSE_BRACKETS = "closeBrackets",
+ CLOSE_TAGS = "closeTags",
+ HIGHLIGHT_MATCHES = "highlightMatches",
+ SCROLL_PAST_END = "scrollPastEnd",
+ SHOW_CURSOR_SELECT = "showCursorWhenSelecting",
+ SHOW_LINE_NUMBERS = "showLineNumbers",
+ SMART_INDENT = "smartIndent",
+ SOFT_TABS = "softTabs",
+ SPACE_UNITS = "spaceUnits",
+ STYLE_ACTIVE_LINE = "styleActiveLine",
+ TAB_SIZE = "tabSize",
+ WORD_WRAP = "wordWrap",
+ USE_TAB_CHAR = "useTabChar";
var cmOptions = {};
@@ -110,6 +112,7 @@ define(function (require, exports, module) {
cmOptions[CLOSE_TAGS] = "autoCloseTags";
cmOptions[HIGHLIGHT_MATCHES] = "highlightSelectionMatches";
cmOptions[SCROLL_PAST_END] = "scrollPastEnd";
+ cmOptions[SHOW_CURSOR_SELECT] = "showCursorWhenSelecting";
cmOptions[SHOW_LINE_NUMBERS] = "lineNumbers";
cmOptions[SMART_INDENT] = "smartIndent";
cmOptions[SPACE_UNITS] = "indentUnit";
@@ -118,22 +121,23 @@ define(function (require, exports, module) {
cmOptions[USE_TAB_CHAR] = "indentWithTabs";
cmOptions[WORD_WRAP] = "lineWrapping";
- PreferencesManager.definePreference(CLOSE_BRACKETS, "boolean", false);
- PreferencesManager.definePreference(CLOSE_TAGS, "Object", { whenOpening: true, whenClosing: true, indentTags: [] });
- PreferencesManager.definePreference(HIGHLIGHT_MATCHES, "boolean", false);
- PreferencesManager.definePreference(SCROLL_PAST_END, "boolean", false);
- PreferencesManager.definePreference(SHOW_LINE_NUMBERS, "boolean", true);
- PreferencesManager.definePreference(SMART_INDENT, "boolean", true);
- PreferencesManager.definePreference(SOFT_TABS, "boolean", true);
- PreferencesManager.definePreference(SPACE_UNITS, "number", DEFAULT_SPACE_UNITS, {
+ PreferencesManager.definePreference(CLOSE_BRACKETS, "boolean", false);
+ PreferencesManager.definePreference(CLOSE_TAGS, "Object", { whenOpening: true, whenClosing: true, indentTags: [] });
+ PreferencesManager.definePreference(HIGHLIGHT_MATCHES, "boolean", false);
+ PreferencesManager.definePreference(SCROLL_PAST_END, "boolean", false);
+ PreferencesManager.definePreference(SHOW_CURSOR_SELECT, "boolean", false);
+ PreferencesManager.definePreference(SHOW_LINE_NUMBERS, "boolean", true);
+ PreferencesManager.definePreference(SMART_INDENT, "boolean", true);
+ PreferencesManager.definePreference(SOFT_TABS, "boolean", true);
+ PreferencesManager.definePreference(SPACE_UNITS, "number", DEFAULT_SPACE_UNITS, {
validator: _.partialRight(ValidationUtils.isIntegerInRange, MIN_SPACE_UNITS, MAX_SPACE_UNITS)
});
- PreferencesManager.definePreference(STYLE_ACTIVE_LINE, "boolean", false);
- PreferencesManager.definePreference(TAB_SIZE, "number", DEFAULT_TAB_SIZE, {
+ PreferencesManager.definePreference(STYLE_ACTIVE_LINE, "boolean", false);
+ PreferencesManager.definePreference(TAB_SIZE, "number", DEFAULT_TAB_SIZE, {
validator: _.partialRight(ValidationUtils.isIntegerInRange, MIN_TAB_SIZE, MAX_TAB_SIZE)
});
- PreferencesManager.definePreference(USE_TAB_CHAR, "boolean", false);
- PreferencesManager.definePreference(WORD_WRAP, "boolean", true);
+ PreferencesManager.definePreference(USE_TAB_CHAR, "boolean", false);
+ PreferencesManager.definePreference(WORD_WRAP, "boolean", true);
var editorOptions = Object.keys(cmOptions);
@@ -144,7 +148,7 @@ define(function (require, exports, module) {
* @type {boolean}
*/
var _duringFocus = false;
-
+
/**
* Constant: ignore upper boundary when centering text
* @type {number}
@@ -194,7 +198,7 @@ define(function (require, exports, module) {
* @param {!boolean} makeMasterEditor If true, this Editor will set itself as the (secret) "master"
* Editor for the Document. If false, this Editor will attach to the Document as a "slave"/
* secondary editor.
- * @param {!jQueryObject} container Container to add the editor to.
+ * @param {!jQueryObject|DomNode} container Container to add the editor to.
* @param {{startLine: number, endLine: number}=} range If specified, range of lines within the document
* to display in this editor. Inclusive.
*/
@@ -207,6 +211,13 @@ define(function (require, exports, module) {
this.document = document;
document.addRef();
+ if (container.jquery) {
+ // CodeMirror wants a DOM element, not a jQuery wrapper
+ container = container.get(0);
+ }
+
+ var $container = $(container);
+
if (range) { // attach this first: want range updated before we process a change
this._visibleRange = new TextRange(document, range.startLine, range.endLine);
}
@@ -226,6 +237,7 @@ define(function (require, exports, module) {
this._inlineWidgets = [];
this._inlineWidgetQueues = {};
this._hideMarks = [];
+ this._lastEditorWidth = null;
this._$messagePopover = null;
@@ -253,7 +265,10 @@ define(function (require, exports, module) {
self.removeAllInlineWidgets();
}
},
- "Cmd-Left": "goLineStartSmart"
+ "Home": "goLineLeftSmart",
+ "Cmd-Left": "goLineLeftSmart",
+ "End": "goLineRight",
+ "Cmd-Right": "goLineRight"
};
var currentOptions = this._currentOptions = _.zipObject(
@@ -263,6 +278,13 @@ define(function (require, exports, module) {
})
);
+ // When panes are created *after* the showLineNumbers option has been turned off
+ // we need to apply the show-line-padding class or the text will be juxtaposed
+ // to the edge of the editor which makes it not easy to read. The code below to handle
+ // that the option change only applies the class to panes that have already been created
+ // This line ensures that the class is applied to any editor created after the fact
+ $container.toggleClass("show-line-padding", Boolean(!this._getOption("showLineNumbers")));
+
// Create the CodeMirror instance
// (note: CodeMirror doesn't actually require using 'new', but jslint complains without it)
this._codeMirror = new CodeMirror(container, {
@@ -280,6 +302,7 @@ define(function (require, exports, module) {
lineWrapping : currentOptions[WORD_WRAP],
matchBrackets : { maxScanLineLength: 50000, maxScanLines: 1000 },
matchTags : { bothTags: true },
+ showCursorWhenSelecting : currentOptions[SHOW_CURSOR_SELECT],
scrollPastEnd : !range && currentOptions[SCROLL_PAST_END],
smartIndent : currentOptions[SMART_INDENT],
styleActiveLine : currentOptions[STYLE_ACTIVE_LINE],
@@ -328,6 +351,13 @@ define(function (require, exports, module) {
return this._codeMirror.getScrollInfo().top;
}
});
+
+ // Add an $el getter for Pane Views
+ Object.defineProperty(this, "$el", {
+ get: function () {
+ return $(this.getRootElement());
+ }
+ });
}
/**
@@ -336,6 +366,8 @@ define(function (require, exports, module) {
* a read-only string-backed mode.
*/
Editor.prototype.destroy = function () {
+ $(this).triggerHandler("beforeDestroy", [this]);
+
// CodeMirror docs for getWrapperElement() say all you have to do is "Remove this from your
// tree to delete an editor instance."
$(this.getRootElement()).remove();
@@ -488,7 +520,6 @@ define(function (require, exports, module) {
/**
* @private
* Handle Tab key press.
- * @param {!CodeMirror} instance CodeMirror instance.
*/
Editor.prototype._handleTabKey = function () {
// Tab key handling is done as follows:
@@ -762,8 +793,6 @@ define(function (require, exports, module) {
* the document an editor change that originated with us
*/
Editor.prototype._handleDocumentChange = function (event, doc, changeList) {
- var change;
-
// we're currently syncing to the Document, so don't echo back FROM the Document
if (this._duringSync) {
return;
@@ -886,6 +915,15 @@ define(function (require, exports, module) {
PerfUtils.addMeasurement(perfTimerName);
};
+
+ /**
+ * Gets the file associated with this editor
+ * This is a required Pane-View interface method
+ * @return {!File} the file associated with this editor
+ */
+ Editor.prototype.getFile = function () {
+ return this.document.file;
+ };
/**
* Gets the current cursor position within the editor.
@@ -896,7 +934,7 @@ define(function (require, exports, module) {
* selection that moves when you press shift+arrow), or "anchor" (the
* fixed side of the selection). Omitting the argument is the same as
* passing "head". A {line, ch} object will be returned.)
- * @return !{line:number, ch:number}
+ * @return {!{line:number, ch:number}}
*/
Editor.prototype.getCursorPos = function (expandTabs, which) {
// Translate "start" and "end" to the official CM names (it actually
@@ -997,6 +1035,7 @@ define(function (require, exports, module) {
this._codeMirror.setSize(width, height);
};
+ /** @const */
var CENTERING_MARGIN = 0.15;
/**
@@ -1364,6 +1403,7 @@ define(function (require, exports, module) {
Editor.prototype.getRootElement = function () {
return this._codeMirror.getWrapperElement();
};
+
/**
* Gets the lineSpace element within the editor (the container around the individual lines of code).
@@ -1384,6 +1424,15 @@ define(function (require, exports, module) {
return { x: scrollInfo.left, y: scrollInfo.top };
};
+ /**
+ * Restores and adjusts the current scroll position of the editor.
+ * @param {{x:number, y:number}} scrollPos - The x,y scroll position in pixels
+ * @param {!number} heightDelta - The amount of delta H to apply to the scroll position
+ */
+ Editor.prototype.adjustScrollPos = function (scrollPos, heightDelta) {
+ this._codeMirror.scrollTo(scrollPos.x, scrollPos.y + heightDelta);
+ };
+
/**
* Sets the current scroll position of the editor.
* @param {number} x scrollLeft position in pixels
@@ -1490,8 +1539,6 @@ define(function (require, exports, module) {
}
if (!inlineWidget.closePromise) {
- var lineNum = this._getInlineWidgetLineNumber(inlineWidget);
-
// Remove the inline widget from our internal list immediately, so
// everyone external to us knows it's essentially already gone. We
// don't want to wait until it's done animating closed (but we do want
@@ -1575,7 +1622,7 @@ define(function (require, exports, module) {
inlineWidget.isClosed = true;
}
};
-
+
/**
* Returns a list of all inline widgets currently open in this editor. Each entry contains the
* inline's id, and the data parameter that was passed to addInlineWidget().
@@ -1584,6 +1631,22 @@ define(function (require, exports, module) {
Editor.prototype.getInlineWidgets = function () {
return this._inlineWidgets;
};
+
+ /**
+ * Returns the currently focused inline widget, if any.
+ * @return {?InlineWidget}
+ */
+ Editor.prototype.getFocusedInlineWidget = function () {
+ var result = null;
+
+ this.getInlineWidgets().forEach(function (widget) {
+ if (widget.hasFocus()) {
+ result = widget;
+ }
+ });
+
+ return result;
+ };
/**
* Display temporary popover message at current cursor position. Display message above
@@ -1595,7 +1658,6 @@ define(function (require, exports, module) {
var arrowBelow, cursorPos, cursorCoord, popoverRect,
top, left, clip, arrowCenter, arrowLeft,
self = this,
- $editorHolder = $("#editor-holder"),
POPOVER_MARGIN = 10,
POPOVER_ARROW_HALF_WIDTH = 10,
POPOVER_ARROW_HALF_BASE = POPOVER_ARROW_HALF_WIDTH + 3; // 3 is border radius
@@ -1667,7 +1729,7 @@ define(function (require, exports, module) {
};
// See if popover is clipped on any side
- clip = ViewUtils.getElementClipSize($editorHolder, popoverRect);
+ clip = ViewUtils.getElementClipSize($("#editor-holder"), popoverRect);
// Prevent horizontal clipping
if (clip.left > 0) {
@@ -1821,6 +1883,40 @@ define(function (require, exports, module) {
return this._focused;
};
+ /*
+ * @typedef {scrollPos:{x:number, y:number},Array.<{start:{line:number, ch:number},end:{line:number, ch:number}}>} EditorViewState
+ */
+
+ /*
+ * returns the view state for the editor
+ * @return {!EditorViewState}
+ */
+ Editor.prototype.getViewState = function () {
+ return {
+ selections: this.getSelections(),
+ scrollPos: this.getScrollPos()
+ };
+
+ };
+
+ /*
+ * Restores the view state
+ * @param {!EditorViewState} viewState - the view state object to restore
+ */
+ Editor.prototype.restoreViewState = function (viewState) {
+ if (viewState.selection) {
+ // We no longer write out single-selection, but there might be some view state
+ // from an older version.
+ this.setSelection(viewState.selection.start, viewState.selection.end);
+ }
+ if (viewState.selections) {
+ this.setSelections(viewState.selections);
+ }
+ if (viewState.scrollPos) {
+ this.setScrollPos(viewState.scrollPos.x, viewState.scrollPos.y);
+ }
+ };
+
/**
* Re-renders the editor UI
* @param {boolean=} handleResize true if this is in response to resizing the editor. Default false.
@@ -1859,13 +1955,12 @@ define(function (require, exports, module) {
};
/**
- * Shows or hides the editor within its parent. Does not force its ancestors to
- * become visible.
+ * View API Visibility Change Notification handler. This is also
+ * called by the native "setVisible" API which refresh can be optimized
* @param {boolean} show true to show the editor, false to hide it
* @param {boolean} refresh true (default) to refresh the editor, false to skip refreshing it
*/
- Editor.prototype.setVisible = function (show, refresh) {
- $(this.getRootElement()).css("display", (show ? "" : "none"));
+ Editor.prototype.notifyVisibilityChange = function (show, refresh) {
if (show && (refresh || refresh === undefined)) {
this.refresh();
}
@@ -1876,6 +1971,17 @@ define(function (require, exports, module) {
}
};
+ /**
+ * Shows or hides the editor within its parent. Does not force its ancestors to
+ * become visible.
+ * @param {boolean} show true to show the editor, false to hide it
+ * @param {boolean} refresh true (default) to refresh the editor, false to skip refreshing it
+ */
+ Editor.prototype.setVisible = function (show, refresh) {
+ this.$el.css("display", (show ? "" : "none"));
+ this.notifyVisibilityChange(show, refresh);
+ };
+
/**
* Returns true if the editor is fully visible--i.e., is in the DOM, all ancestors are
* visible, and has a non-zero width/height.
@@ -1896,7 +2002,7 @@ define(function (require, exports, module) {
* the start and end.
* @return {?(Object|string)} Name of syntax-highlighting mode, or object containing a "name" property
* naming the mode along with configuration options required by the mode.
- * See {@link LanguageManager#getLanguageForPath()} and {@link Language#getMode()}.
+ * @see {@link LanguageManager#getLanguageForPath()} and {@link Language#getMode()}.
*/
Editor.prototype.getModeForRange = function (start, end, knownMixed) {
var outerMode = this._codeMirror.getMode(),
@@ -1922,7 +2028,7 @@ define(function (require, exports, module) {
*
* @return {?(Object|string)} Name of syntax-highlighting mode, or object containing a "name" property
* naming the mode along with configuration options required by the mode.
- * See {@link LanguageManager#getLanguageForPath()} and {@link Language#getMode()}.
+ * @see {@link LanguageManager#getLanguageForPath()} and {@link Language#getMode()}.
*/
Editor.prototype.getModeForSelection = function () {
// Check for mixed mode info
@@ -1964,6 +2070,10 @@ define(function (require, exports, module) {
}
};
+ /*
+ * gets the language for the selection. (Javascript selected from an HTML document or CSS selected from an HTML document, etc...)
+ * @return {!Language}
+ */
Editor.prototype.getLanguageForSelection = function () {
return this.document.getLanguage().getLanguageForMode(this.getModeForSelection());
};
@@ -1976,12 +2086,22 @@ define(function (require, exports, module) {
Editor.prototype.getModeForDocument = function () {
return this._codeMirror.getOption("mode");
};
-
+
/**
* The Document we're bound to
* @type {!Document}
*/
Editor.prototype.document = null;
+
+
+ /**
+ * The Editor's last known width.
+ * Used in conjunction with updateLayout to recompute the layout
+ * if the the parent container changes its size since our last layout update.
+ * @type {?number}
+ */
+ Editor.prototype._lastEditorWidth = null;
+
/**
* If true, we're in the middle of syncing to/from the Document. Used to ignore spurious change
@@ -1989,7 +2109,7 @@ define(function (require, exports, module) {
* @type {!boolean}
*/
Editor.prototype._duringSync = false;
-
+
/**
* @private
* NOTE: this is actually "semi-private": EditorManager also accesses this field... as well as
@@ -2088,6 +2208,38 @@ define(function (require, exports, module) {
this._codeMirror.setOption("styleActiveLine", this._currentOptions[STYLE_ACTIVE_LINE]);
}
};
+
+ /**
+ * resizes the editor to fill its parent container
+ * should not be used on inline editors
+ * @param {boolean=} forceRefresh - forces the editor to update its layout
+ * even if it already matches the container's height / width
+ */
+ Editor.prototype.updateLayout = function (forceRefresh) {
+ var curRoot = this.getRootElement(),
+ curWidth = $(curRoot).width(),
+ $editorHolder = this.$el.parent(),
+ editorAreaHt = $editorHolder.height();
+
+ if (!curRoot.style.height || $(curRoot).height() !== editorAreaHt) {
+ // Call setSize() instead of $.height() to allow CodeMirror to
+ // check for options like line wrapping
+ this.setSize(null, editorAreaHt);
+ if (forceRefresh === undefined) {
+ forceRefresh = true;
+ }
+ } else if (curWidth !== this._lastEditorWidth) {
+ if (forceRefresh === undefined) {
+ forceRefresh = true;
+ }
+ }
+ this._lastEditorWidth = curWidth;
+
+ if (forceRefresh) {
+ this.refreshAll(forceRefresh);
+ }
+ };
+
// Global settings that affect Editor instances that share the same preference locations
@@ -2245,7 +2397,18 @@ define(function (require, exports, module) {
* @param {boolean} showLinePadding
*/
Editor._toggleLinePadding = function (showLinePadding) {
- $("#editor-holder").toggleClass("show-line-padding", showLinePadding);
+ // apply class to all pane DOM nodes
+ var $holders = [];
+ _instances.forEach(function (editor) {
+ var $editorHolder = editor.$el.parent();
+ if ($holders.indexOf($editorHolder) === -1) {
+ $holders.push($editorHolder);
+ }
+ });
+
+ _.each($holders, function ($holder) {
+ $holder.toggleClass("show-line-padding", Boolean(showLinePadding));
+ });
};
// Set up listeners for preference changes
diff --git a/src/editor/EditorCommandHandlers.js b/src/editor/EditorCommandHandlers.js
index 3933fac7bd5..ea907f78f84 100644
--- a/src/editor/EditorCommandHandlers.js
+++ b/src/editor/EditorCommandHandlers.js
@@ -201,8 +201,7 @@ define(function (require, exports, module) {
// Are there any non-blank lines that aren't commented out? (We ignore blank lines because
// some editors like Sublime don't comment them out)
var i, line, prefix, commentI,
- containsNotLineComment = _containsNotLineComment(editor, startLine, endLine, lineExp),
- updateSelection = false;
+ containsNotLineComment = _containsNotLineComment(editor, startLine, endLine, lineExp);
if (containsNotLineComment) {
// Comment out - prepend the first prefix to each line
@@ -553,10 +552,7 @@ define(function (require, exports, module) {
* An edit description suitable for including in the edits array passed to `Document.doMultipleEdits()`.
*/
function _getLineCommentPrefixSuffixEdit(editor, prefix, suffix, lineSel) {
- var sel = lineSel.selectionForEdit,
- selStart = sel.start,
- selEnd = sel.end,
- edit;
+ var sel = lineSel.selectionForEdit;
// For one-line selections, we shrink the selection to exclude the trailing newline.
if (sel.end.line === sel.start.line + 1 && sel.end.ch === 0) {
@@ -727,8 +723,7 @@ define(function (require, exports, module) {
edits = [];
_.each(lineSelections, function (lineSel, index) {
- var sel = lineSel.selectionForEdit,
- selStartLine = sel.start.line;
+ var sel = lineSel.selectionForEdit;
from = sel.start;
to = sel.end; // this is already at the beginning of the line after the last selected line
diff --git a/src/editor/EditorManager.js b/src/editor/EditorManager.js
index 4536e270e9c..8e54549a339 100644
--- a/src/editor/EditorManager.js
+++ b/src/editor/EditorManager.js
@@ -35,12 +35,18 @@
* must have some knowledge about Document's internal state (we access its _editor property).
*
* This module dispatches the following events:
- * - activeEditorChange -- Fires after the active editor (full or inline) changes and size/visibility
- * are complete. Doesn't fire when editor temporarily loses focus to a non-editor
- * control (e.g. search toolbar or modal dialog, or window deactivation). Does
- * fire when focus moves between inline editor and its full-size container.
- * This event tracks `getActiveEditor()` changes, while DocumentManager's
- * `currentDocumentChange` tracks `getCurrentFullEditor()` changes.
+ * - activeEditorChange -- Fires after the active editor (full or inline).
+ *
+ * Doesn't fire when editor temporarily loses focus to a non-editor
+ * control (e.g. search toolbar or modal dialog, or window deactivation).
+ *
+ * Does fire when focus moves between inline editor and its full-size container.
+ *
+ * This event tracks `MainViewManagers's `currentFileChange` event and all editor
+ * objects "focus" event.
+ *
+ * (e, editorGainingFocus:editor, editorLosingFocus:editor)
+ *
* The 2nd arg to the listener is which Editor became active; the 3rd arg is
* which Editor is deactivated as a result. Either one may be null.
* NOTE (#1257): `getFocusedEditor()` sometimes lags behind this event. Listeners
@@ -52,99 +58,99 @@ define(function (require, exports, module) {
// Load dependent modules
var Commands = require("command/Commands"),
- PanelManager = require("view/PanelManager"),
+ WorkspaceManager = require("view/WorkspaceManager"),
PreferencesManager = require("preferences/PreferencesManager"),
CommandManager = require("command/CommandManager"),
DocumentManager = require("document/DocumentManager"),
+ MainViewManager = require("view/MainViewManager"),
+ ViewStateManager = require("view/ViewStateManager"),
PerfUtils = require("utils/PerfUtils"),
Editor = require("editor/Editor").Editor,
InlineTextEditor = require("editor/InlineTextEditor").InlineTextEditor,
Strings = require("strings"),
- LanguageManager = require("language/LanguageManager");
+ LanguageManager = require("language/LanguageManager"),
+ DeprecationWarning = require("utils/DeprecationWarning");
- /**
- * DOM node that contains all editors (visible and hidden alike)
- * @type {jQueryObject}
- */
- var _editorHolder = null;
-
- /**
- * Currently visible full-size Editor, or null if no editors open
- * @type {?Editor}
- */
- var _currentEditor = null;
-
- /**
- * Document in current editor
- * @type {?Document}
- */
- var _currentEditorsDocument = null;
-
- /**
- * full path to file
- * @type {?string}
- */
- var _currentlyViewedPath = null;
-
- /**
- * DOM node representing UI of custom view
- * @type {?JQuery}
- */
- var _$currentCustomViewer = null;
-
- /**
- * view provider
- * @type {?Object}
- */
- var _currentViewProvider = null;
-
- /**
- * view provider registry
- * @type {?Object}
- */
- var _customViewerRegistry = {};
/**
* Currently focused Editor (full-size, inline, or otherwise)
* @type {?Editor}
+ * @private
*/
var _lastFocusedEditor = null;
- /**
- * Maps full path to scroll pos & cursor/selection info. Not kept up to date while an editor is current.
- * Only updated when switching / closing editor, or when requested explicitly via _getViewState().
- * @type {Object}
- */
- var _viewStateCache = {};
-
- /**
- * Last known editor area width, used to detect when the window is resized horizontally.
- */
- var _lastEditorWidth = null;
-
/**
* Registered inline-editor widget providers sorted descending by priority.
- * See {@link #registerInlineEditProvider()}.
+ * @see {@link #registerInlineEditProvider()}.
* @type {Array.<{priority:number, provider:function(...)}>}
+ * @private
*/
var _inlineEditProviders = [];
/**
* Registered inline documentation widget providers sorted descending by priority.
- * See {@link #registerInlineDocsProvider()}.
+ * @see {@link #registerInlineDocsProvider()}.
* @type {Array.<{priority:number, provider:function(...)}>}
+ * @private
*/
var _inlineDocsProviders = [];
/**
- * Registered jump-to-definition providers. See {@link #registerJumpToDefProvider()}.
+ * Registered jump-to-definition providers.
+ * @see {@link #registerJumpToDefProvider()}.
+ * @private
* @type {Array.}
*/
var _jumpToDefProviders = [];
+
+ /**
+ * DOM element to house any hidden editors created soley for inline widgets
+ * @private
+ * @type {jQuery}
+ */
+ var _$hiddenEditorsContainer;
+
+
+ /**
+ * Retrieves the visible full-size Editor for the currently opened file in the ACTIVE_PANE
+ * @return {?Editor} editor of the current view or null
+ */
+ function getCurrentFullEditor() {
+ var currentPath = MainViewManager.getCurrentlyViewedPath(MainViewManager.ACTIVE_PANE),
+ doc = currentPath && DocumentManager.getOpenDocumentForPath(currentPath);
+ return doc && doc._masterEditor;
+ }
+
+
+
+ /**
+ * Updates _viewStateCache from the given editor's actual current state
+ * @private
+ * @param {!Editor} editor - editor to cache data for
+ */
+ function _saveEditorViewState(editor) {
+ ViewStateManager.updateViewState(editor);
+ }
+
+ /**
+ * Updates _viewStateCache from the given editor's actual current state
+ * @param {!Editor} editor - editor restore cached data
+ * @private
+ */
+ function _restoreEditorViewState(editor) {
+ // We want to ignore the current state of the editor, so don't call __getViewState()
+ var viewState = ViewStateManager.getViewState(editor.document.file);
+ if (viewState) {
+ editor.restoreViewState(viewState);
+ }
+ }
+
+
/**
+ * Editor focus handler to change the currently active editor
* @private
- * @param {?Editor} current
+ * @param {?Editor} current - the editor that will be the active editor
*/
function _notifyActiveEditorChanged(current) {
// Skip if the Editor that gained focus was already the most recently focused editor.
@@ -158,9 +164,27 @@ define(function (require, exports, module) {
$(exports).triggerHandler("activeEditorChange", [current, previous]);
}
+ /**
+ * Current File Changed handler
+ * MainViewManager dispatches a "currentFileChange" event whenever the currently viewed
+ * file changes. Which could mean that the previously viewed file has been closed or a
+ * non-editor view (image) has been given focus. _notifyAcitveEditorChanged is also hooked
+ * up to editor.focus to handle focus events for editors which handles changing focus between
+ * two editors but, because editormanager maintains a "_lastFocusedEditor" state, we have to
+ * "nullify" that state whenever the focus goes to a non-editor or when the current editor is closed
+ * @private
+ * @param {!jQuery.Event} e - event
+ * @param {?File} file - current file (can be null)
+ */
+ function _handleCurrentFileChange(e, file) {
+ var doc = file && DocumentManager.getOpenDocumentForPath(file.fullPath);
+ _notifyActiveEditorChanged(doc && doc._masterEditor);
+ }
+
/**
* Creates a new Editor bound to the given Document.
* The editor is appended to the given container as a visible child.
+ * @private
* @param {!Document} doc Document for the Editor's content
* @param {!boolean} makeMasterEditor If true, the Editor will set itself as the private "master"
* Editor for the Document. If false, the Editor will attach to the Document as a "slave."
@@ -176,6 +200,12 @@ define(function (require, exports, module) {
_notifyActiveEditorChanged(this);
});
+ $(editor).on("beforeDestroy", function () {
+ if (editor.$el.is(":visible")) {
+ _saveEditorViewState(editor);
+ }
+ });
+
return editor;
}
@@ -249,9 +279,52 @@ define(function (require, exports, module) {
return result.promise();
}
+
/**
- * Inserts a prioritized provider object into the array in sorted (descending) order.
+ * Closes any focused inline widget. Else, asynchronously asks providers to create one.
*
+ * @param {Array.<{priority:number, provider:function(...)}>} providers
+ * prioritized list of providers
+ * @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).
+ */
+ function _toggleInlineWidget(providers, errorMsg) {
+ var result = new $.Deferred();
+
+ var currentEditor = getCurrentFullEditor();
+
+ if (currentEditor) {
+ var inlineWidget = currentEditor.getFocusedInlineWidget();
+
+ if (inlineWidget) {
+ // an inline widget's editor has focus, so close it
+ PerfUtils.markStart(PerfUtils.INLINE_WIDGET_CLOSE);
+ inlineWidget.close().done(function () {
+ PerfUtils.addMeasurement(PerfUtils.INLINE_WIDGET_CLOSE);
+ // return a resolved promise to CommandManager
+ result.resolve(false);
+ });
+ } else {
+ // main editor has focus, so create an inline editor
+ _openInlineWidget(currentEditor, providers, errorMsg).done(function () {
+ result.resolve(true);
+ }).fail(function () {
+ result.reject();
+ });
+ }
+ } else {
+ // Can not open an inline editor without a host editor
+ result.reject();
+ }
+
+ return result.promise();
+ }
+
+ /**
+ * Inserts a prioritized provider object into the array in sorted (descending) order.
+ * @private
* @param {Array.<{priority:number, provider:function(...)}>} array
* @param {number} priority
* @param {function(...)} provider
@@ -272,6 +345,26 @@ define(function (require, exports, module) {
array.splice(index, 0, prioritizedProvider);
}
+
+ /**
+ * Creates a hidden, unattached master editor that is needed when a document is created for the
+ * sole purpose of creating an inline editor so operations that require a master editor can be performed
+ * Only called from Document._ensureMasterEditor()
+ * The editor view is placed in a hidden part of the DOM but can later be moved to a visible pane
+ * when the document is opened using pane.addView()
+ * @param {!Document} doc - document to create a hidden editor for
+ */
+ function _createUnattachedMasterEditor(doc) {
+ // attach to the hidden containers DOM node if necessary
+ if (!_$hiddenEditorsContainer) {
+ _$hiddenEditorsContainer = $("#hidden-editors");
+ }
+ // Create an editor
+ var editor = _createEditorForDocument(doc, true, _$hiddenEditorsContainer);
+ // and hide it
+ editor.setVisible(false);
+ }
+
/**
* Removes the given widget UI from the given hostEditor (agnostic of what the widget's content
* is). The widget's onClosed() callback will be run as a result.
@@ -373,24 +466,19 @@ define(function (require, exports, module) {
/**
* @private
* Creates a new "full-size" (not inline) Editor for the given Document, and sets it as the
- * Document's master backing editor. The editor is not yet visible; to show it, use
- * DocumentManager.setCurrentDocument().
+ * Document's master backing editor. The editor is not yet visible;
* Semi-private: should only be called within this module or by Document.
* @param {!Document} document Document whose main/full Editor to create
+ * @param {!Pane} pane Pane in which the editor will be hosted
*/
- function _createFullEditorForDocument(document) {
+ function _createFullEditorForDocument(document, pane) {
// Create editor; make it initially invisible
- var container = _editorHolder.get(0);
- var editor = _createEditorForDocument(document, true, container);
+ var editor = _createEditorForDocument(document, true, pane.$content);
editor.setVisible(false);
+ pane.addView(editor);
+ $(exports).triggerHandler("_fullEditorCreatedForDocument", [document, editor, pane.id]);
}
-
- /** Returns the visible full-size Editor corresponding to DocumentManager.getCurrentDocument() */
- function getCurrentFullEditor() {
- // This *should* always be equivalent to DocumentManager.getCurrentDocument()._masterEditor
- return _currentEditor;
- }
-
+
/**
* Creates a new inline Editor instance for the given Document.
@@ -415,46 +503,6 @@ define(function (require, exports, module) {
return { content: inlineContent, editor: inlineEditor };
}
-
-
- /**
- * Disposes the given Document's full-size editor if the doc is no longer "open" from the user's
- * standpoint - not in the working set and not currentDocument).
- *
- * Destroying the full-size editor releases ONE ref to the Document; if inline editors or other
- * UI elements are still referencing the Document it will still be 'open' (kept alive) from
- * DocumentManager's standpoint. However, destroying the full-size editor does remove the backing
- * "master" editor from the Document, rendering it immutable until either inline-editor edits or
- * currentDocument change triggers `_createFullEditorForDocument()` full-size editor again.
- *
- * In certain edge cases, this is called directly by DocumentManager; see `_gcDocuments()` for details.
- *
- * @param {!Document} document Document whose "master" editor we may destroy
- */
- function _destroyEditorIfUnneeded(document) {
- var editor = document._masterEditor;
-
- if (!editor) {
- if (!(document instanceof DocumentManager.Document)) {
- throw new Error("_destroyEditorIfUnneeded() should be passed a Document");
- }
- return;
- }
-
- // If outgoing editor is no longer needed, dispose it
- var isCurrentDocument = (DocumentManager.getCurrentDocument() === document);
- var isInWorkingSet = (DocumentManager.findInWorkingSet(document.file.fullPath) !== -1);
- if (!isCurrentDocument && !isInWorkingSet) {
- // Destroy the editor widget (which un-refs the Document and reverts it to read-only mode)
- editor.destroy();
-
- // Our callers should really ensure this, but just for safety...
- if (_currentEditor === editor) {
- _currentEditorsDocument = null;
- _currentEditor = null;
- }
- }
- }
/**
* Returns focus to the last visible editor that had focus. If no editor visible, does nothing.
@@ -462,148 +510,31 @@ define(function (require, exports, module) {
* removed. For example, after a dialog with editable text is closed.
*/
function focusEditor() {
- if (_lastFocusedEditor) {
- _lastFocusedEditor.focus();
- }
+ DeprecationWarning.deprecationWarning("Use MainViewManager.focusActivePane() instead of EditorManager.focusEditor().", true);
+ MainViewManager.focusActivePane();
}
-
- /**
- * Flag for `_onEditorAreaResize()` to always force refresh.
- * @const
- * @type {string}
- */
- var REFRESH_FORCE = "force";
-
- /**
- * Flag for `_onEditorAreaResize()` to never refresh.
- * @const
- * @type {string}
- */
- var REFRESH_SKIP = "skip";
-
/**
- * Must be called whenever the size/visibility of editor area siblings is changed without going through
- * PanelManager or Resizer. Resizable panels created via PanelManager do not require this manual call.
+ * @deprecated
+ * resizes the editor
*/
function resizeEditor() {
- if (!_editorHolder) {
- return; // still too early during init
- }
- // PanelManager computes the correct editor-holder size & calls us back with it, via _onEditorAreaResize()
- PanelManager._notifyLayoutChange();
- }
-
- /**
- * Update the current CodeMirror editor's size. Must be called any time the contents of the editor area
- * are swapped or any time the editor-holder area has changed height. EditorManager calls us in the swap
- * case. PanelManager calls us in the most common height-change cases (panel and/or window resize), but
- * some other cases are handled by external code calling `resizeEditor()` (e.g. ModalBar hide/show).
- *
- * @param {number} editorAreaHt
- * @param {string=} refreshFlag For internal use. Set to "force" to ensure the editor will refresh,
- * "skip" to ensure the editor does not refresh, or leave undefined to let `_onEditorAreaResize()`
- * determine whether it needs to refresh.
- */
- function _onEditorAreaResize(event, editorAreaHt, refreshFlag) {
- if (_currentEditor) {
- var curRoot = _currentEditor.getRootElement(),
- curWidth = $(curRoot).width();
- if (!curRoot.style.height || $(curRoot).height() !== editorAreaHt) {
- // Call setSize() instead of $.height() to allow CodeMirror to
- // check for options like line wrapping
- _currentEditor.setSize(null, editorAreaHt);
- if (refreshFlag === undefined) {
- refreshFlag = REFRESH_FORCE;
- }
- } else if (curWidth !== _lastEditorWidth) {
- if (refreshFlag === undefined) {
- refreshFlag = REFRESH_FORCE;
- }
- }
- _lastEditorWidth = curWidth;
-
- if (refreshFlag === REFRESH_FORCE) {
- _currentEditor.refreshAll(true);
- }
- }
- }
-
- /** Updates _viewStateCache from the given editor's actual current state */
- function _saveEditorViewState(editor) {
- _viewStateCache[editor.document.file.fullPath] = {
- selections: editor.getSelections(),
- scrollPos: editor.getScrollPos()
- };
- }
-
- /** Updates the given editor's actual state from _viewStateCache, if any state stored */
- function _restoreEditorViewState(editor) {
- // We want to ignore the current state of the editor, so don't call _getViewState()
- var viewState = _viewStateCache[editor.document.file.fullPath];
- if (viewState) {
- if (viewState.selection) {
- // We no longer write out single-selection, but there might be some view state
- // from an older version.
- editor.setSelection(viewState.selection.start, viewState.selection.end);
- }
- if (viewState.selections) {
- editor.setSelections(viewState.selections);
- }
- if (viewState.scrollPos) {
- editor.setScrollPos(viewState.scrollPos.x, viewState.scrollPos.y);
- }
- }
- }
-
- /** Returns up-to-date view state for the given file, or null if file not open and no state cached */
- function _getViewState(fullPath) {
- if (_currentEditorsDocument && _currentEditorsDocument.file.fullPath === fullPath) {
- _saveEditorViewState(_currentEditor);
- }
- return _viewStateCache[fullPath];
- }
-
- /** Removes all cached view state info and replaces it with the given mapping */
- function _resetViewStates(viewStates) {
- _viewStateCache = viewStates;
+ DeprecationWarning.deprecationWarning("Use WorkspaceManager.recomputeLayout() instead of EditorManager.resizeEditor().", true);
+ WorkspaceManager.recomputeLayout();
}
/**
+ * Create and/or show the editor for the specified document
+ * @param {!Document} document - document to edit
+ * @param {!Pane} pane - pane to show it in
* @private
*/
- function _doShow(document) {
- // Show new editor
- _currentEditorsDocument = document;
- _currentEditor = document._masterEditor;
-
- // Skip refreshing the editor since we're going to refresh it more explicitly below
- _currentEditor.setVisible(true, false);
- _currentEditor.focus();
-
- // Resize and refresh the editor, since it might have changed size or had other edits applied
- // since it was last visible.
- PanelManager._notifyLayoutChange(REFRESH_FORCE);
- }
-
- /**
- * Make the given document's editor visible in the UI, hiding whatever was
- * visible before. Creates a new editor if none is assigned.
- * @param {!Document} document
- */
- function _showEditor(document) {
- // Hide whatever was visible before
- if (!_currentEditor) {
- $("#not-editor").css("display", "none");
- } else {
- _saveEditorViewState(_currentEditor);
- _currentEditor.setVisible(false);
- _destroyEditorIfUnneeded(_currentEditorsDocument);
- }
-
+ function _showEditor(document, pane) {
// Ensure a main editor exists for this document to show in the UI
- var createdNewEditor = false;
- if (!document._masterEditor) {
+ var createdNewEditor = false,
+ editor = document._masterEditor;
+
+ if (!editor) {
createdNewEditor = true;
// Performance (see #4757) Chrome wastes time messing with selection
@@ -613,286 +544,86 @@ define(function (require, exports, module) {
}
// Editor doesn't exist: populate a new Editor with the text
- _createFullEditorForDocument(document);
+ _createFullEditorForDocument(document, pane);
+ } else if (editor.$el.parent() !== pane.$el) {
+ // editor does exist but is not a child of the pane so add it to the
+ // pane (which will switch the view's container as well)
+ pane.addView(editor);
}
-
- _doShow(document);
-
+
+ // show the view
+ pane.showView(document._masterEditor);
+
+ // give it focus
+ document._masterEditor.focus();
+
if (createdNewEditor) {
_restoreEditorViewState(document._masterEditor);
}
}
-
+
/**
- * Resets editor state to make sure `getFocusedEditor()`, `getActiveEditor()`,
- * and `getCurrentFullEditor()` return null when an image or the NoEditor
- * placeholder is displayed.
+ * @deprecated use MainViewManager.getCurrentlyViewedFile() instead
+ * @return {string=} path of the file currently viewed in the active, full sized editor or null when there is no active editor
*/
- function _nullifyEditor() {
- if (_currentEditor) {
- _saveEditorViewState(_currentEditor);
-
- // This is a hack to deal with #5589. The issue is that CodeMirror's logic for polling its
- // hidden input field relies on whether there's a selection in the input field or not. When
- // we hide the editor, the input field loses its selection. Somehow, CodeMirror's readInput()
- // poll can get called before the resulting blur event is asynchronously sent. (Our guess is
- // that if the setTimeout() that the poll is on is overdue, it gets serviced before the backlog
- // of asynchronous events is flushed.) That means that readInput() thinks CM still has focus,
- // but that the hidden input has lost its selection, meaning the user has typed something, which
- // causes it to replace the editor selection (with the same text), leading to the erroneous
- // change event and selection change. To work around this, we simply blur CM's input field
- // before hiding the editor, which forces the blur event to be sent synchronously, before the
- // next readInput() triggers.
- //
- // Note that we only need to do this here, not in _showEditor(), because _showEditor()
- // ends up synchronously setting focus to another editor, which has the effect of
- // forcing a synchronous blur event as well.
- _currentEditor._codeMirror.getInputField().blur();
-
- _currentEditor.setVisible(false);
- _destroyEditorIfUnneeded(_currentEditorsDocument);
-
- _currentEditorsDocument = null;
- _currentEditor = null;
- _currentlyViewedPath = null;
-
- // No other Editor is gaining focus, so in this one special case we must trigger event manually
- _notifyActiveEditorChanged(null);
- }
- }
-
- /** Hide the currently visible editor and show a placeholder UI in its place */
- function _showNoEditor() {
- $("#not-editor").css("display", "");
- _nullifyEditor();
- }
-
function getCurrentlyViewedPath() {
- return _currentlyViewedPath;
- }
-
- function _clearCurrentlyViewedPath() {
- _currentlyViewedPath = null;
- $(exports).triggerHandler("currentlyViewedFileChange");
- }
-
- function _setCurrentlyViewedPath(fullPath) {
- _currentlyViewedPath = fullPath;
- $(exports).triggerHandler("currentlyViewedFileChange");
- }
-
- /** Remove existing custom view if present */
- function _removeCustomViewer() {
+ DeprecationWarning.deprecationWarning("Use MainViewManager.getCurrentlyViewedFile() instead of EditorManager.getCurrentlyViewedPath().", true);
- if (_$currentCustomViewer) {
- _$currentCustomViewer.remove();
- if (_currentViewProvider.onRemove) {
- _currentViewProvider.onRemove();
- }
- }
- _$currentCustomViewer = null;
- _currentViewProvider = null;
- }
-
- /**
- * Closes the customViewer currently displayed, shows the NoEditor view
- * and notifies the ProjectManager to update the file selection
- */
- function _closeCustomViewer() {
- _removeCustomViewer();
- _setCurrentlyViewedPath();
- _showNoEditor();
- }
-
- /**
- * Append custom view to editor-holder
- * @param {!Object} provider custom view provider
- * @param {!string} fullPath path to the file displayed in the custom view
- */
- function _showCustomViewer(provider, fullPath) {
- // Don't show the same custom view again if file path
- // and view provider are still the same.
- if (_currentlyViewedPath === fullPath &&
- _currentViewProvider === provider) {
- return;
- }
+ // We only want to return a path of a document object
+ // not other things like images, etc...
+ var currentPath = MainViewManager.getCurrentlyViewedPath(MainViewManager.ACTIVE_PANE),
+ doc;
- // Clean up currently viewing document or custom viewer
- DocumentManager._clearCurrentDocument();
- _removeCustomViewer();
-
- // Hide the not-editor or reset current editor
- $("#not-editor").css("display", "none");
- _nullifyEditor();
-
- _currentViewProvider = provider;
+ if (currentPath) {
+ doc = DocumentManager.getOpenDocumentForPath(currentPath);
+ }
- // add path, dimensions and file size to the view after loading image
- _$currentCustomViewer = provider.render(fullPath, $("#editor-holder"));
+ if (doc) {
+ return currentPath;
+ }
- _setCurrentlyViewedPath(fullPath);
- }
-
- /**
- * Check whether the given file is currently open in a custom viewer.
- *
- * @param {!string} fullPath file path to check
- * @return {boolean} true if we have a custom viewer showing and the given file
- * path matches the one in the custom viewer, false otherwise.
- */
- function showingCustomViewerForPath(fullPath) {
- return (_currentViewProvider && _currentlyViewedPath === fullPath);
+ return null;
}
/**
- * Registers a new custom viewer provider. To create an extension
- * that enables Brackets to view files that cannot be shown as
- * text such as binary files, use this method to register a CustomViewer.
- *
- * A CustomViewer, such as ImageViewer in Brackets core needs to
- * implement and export two methods:
- * - render
- * @param {!string} fullPath Path to the image file
- * @param {!jQueryObject} $editorHolder The DOM element to append the view to.
- * - onRemove
- * signs off listeners and performs any required clean up when editor manager closes
- * the custom viewer
- *
- * By registering a CustomViewer with EditorManager Brackets is
- * enabled to view files for one or more given file extensions.
- * The first argument defines a so called languageId which bundles
- * file extensions to be handled by the custom viewer, see more
- * in LanguageManager JSDocs.
- * The second argument is an instance of the custom viewer that is ready to display
- * files.
- *
- * @param {!String} languageId, i.e. string such as image, audio, etc to
- * identify a language known to LanguageManager
- * @param {!Object} provider custom view provider instance
+ * @deprecated There is no equivelent API moving forward.
+ * Use MainViewManager._initialize() from a unit test to create a Main View attached to a specific DOM element
*/
- function registerCustomViewer(langId, provider) {
- if (!_customViewerRegistry[langId]) {
- _customViewerRegistry[langId] = provider;
- } else {
- console.error("There already is a custom viewer registered for language id \"" + langId + "\"");
- }
+ function setEditorHolder() {
+ throw new Error("EditorManager.setEditorHolder() has been removed.");
}
/**
- * Update file name if necessary
+ * @deprecated Register a View Factory instead
+ * @see MainViewManager.registerViewFactory()
*/
- function _onFileNameChange(e, oldName, newName) {
- if (_currentlyViewedPath === oldName) {
- _setCurrentlyViewedPath(newName);
- }
+ function registerCustomViewer() {
+ throw new Error("EditorManager.registerCustomViewer() has been removed.");
}
/**
- * Return the provider of a custom viewer for the given path if one exists.
- * Otherwise, return null.
- *
- * @param {!string} fullPath - file path to be checked for a custom viewer
- * @return {?Object}
+ * Determines if the file can be opened in an editor
+ * @param {!string} fullPath - file to be opened
+ * @return {boolean} true if the file can be opened in an editor, false if not
*/
- function getCustomViewerForPath(fullPath) {
- var lang = LanguageManager.getLanguageForPath(fullPath);
-
- return _customViewerRegistry[lang.getId()];
+ function canOpenPath(fullPath) {
+ return !LanguageManager.getLanguageForPath(fullPath).isBinary();
}
/**
- * Clears custom viewer for a file with a given path and displays
- * an alternate file or the no editor view.
- * If no param fullpath is passed an alternate file will be opened
- * regardless of the current value of _currentlyViewedPath.
- * If param fullpath is provided then only if fullpath matches
- * the currently viewed file an alternate file will be opened.
- * @param {?string} fullPath - file path of deleted file.
+ * Opens the specified document in the given pane
+ * @param {!Document} doc - the document to open
+ * @param {!Pane} pane - the pane to open the document in
+ * @return {boolean} true if the file can be opened, false if not
*/
- function notifyPathDeleted(fullPath) {
- function openAlternateFile() {
- var fileToOpen = DocumentManager.getNextPrevFile(1);
- if (fileToOpen) {
- CommandManager.execute(Commands.FILE_OPEN, {fullPath: fileToOpen.fullPath});
- } else {
- _removeCustomViewer();
- _showNoEditor();
- _setCurrentlyViewedPath();
- }
- }
- if (!fullPath || _currentlyViewedPath === fullPath) {
- openAlternateFile();
- }
- }
-
- /** Handles changes to DocumentManager.getCurrentDocument() */
- function _onCurrentDocumentChange() {
- var doc = DocumentManager.getCurrentDocument(),
- container = _editorHolder.get(0);
-
- var perfTimerName = PerfUtils.markStart("EditorManager._onCurrentDocumentChange():\t" + (!doc || doc.file.fullPath));
-
- // When the document or file in view changes clean up.
- _removeCustomViewer();
- // Update the UI to show the right editor (or nothing), and also dispose old editor if no
- // longer needed.
- if (doc) {
- _showEditor(doc);
- _setCurrentlyViewedPath(doc.file.fullPath);
- } else {
- _clearCurrentlyViewedPath();
- _showNoEditor();
- }
+ function openDocument(doc, pane) {
+ var perfTimerName = PerfUtils.markStart("EditorManager.openDocument():\t" + (!doc || doc.file.fullPath));
- PerfUtils.addMeasurement(perfTimerName);
- }
-
- /** Handles removals from DocumentManager's working set list */
- function _onWorkingSetRemove(event, removedFile) {
- // There's one case where an editor should be disposed even though the current document
- // didn't change: removing a document from the working set (via the "X" button). (This may
- // also cover the case where the document WAS current, if the editor-swap happens before the
- // removal from the working set.
- var doc = DocumentManager.getOpenDocumentForPath(removedFile.fullPath);
- if (doc) {
- _destroyEditorIfUnneeded(doc);
+ if (doc && pane) {
+ _showEditor(doc, pane);
}
- // else, file was listed in working set but never shown in the editor - ignore
- }
-
- function _onWorkingSetRemoveList(event, removedFiles) {
- removedFiles.forEach(function (removedFile) {
- _onWorkingSetRemove(event, removedFile);
- });
- }
-
- /**
- * Note: there are several paths that can lead to an editor getting destroyed
- * - file was in working set, but not in current editor; then closed (via working set "X" button)
- * --> handled by _onWorkingSetRemove()
- * - file was in current editor, but not in working set; then navigated away from
- * --> handled by _onCurrentDocumentChange()
- * - file was in current editor, but not in working set; then closed (via File > Close) (and thus
- * implicitly navigated away from)
- * --> handled by _onCurrentDocumentChange()
- * - file was in current editor AND in working set; then closed (via File > Close OR working set
- * "X" button) (and thus implicitly navigated away from)
- * --> handled by _onWorkingSetRemove() currently, but could be _onCurrentDocumentChange()
- * just as easily (depends on the order of events coming from DocumentManager)
- * Designates the DOM node that will contain the currently active editor instance. EditorManager
- * will own the content of this DOM node.
- * @param {!jQueryObject} holder
- */
- function setEditorHolder(holder) {
- if (_currentEditor) {
- console.error("Cannot change editor area after an editor has already been created!");
- return;
- }
-
- _editorHolder = holder;
-
- resizeEditor(); // if no files open at startup, we won't get called back later to resize the "no-editor" placeholder
+ PerfUtils.addMeasurement(perfTimerName);
}
/**
@@ -900,17 +631,11 @@ define(function (require, exports, module) {
* @return {?InlineWidget}
*/
function getFocusedInlineWidget() {
- var result = null;
-
- if (_currentEditor) {
- _currentEditor.getInlineWidgets().forEach(function (widget) {
- if (widget.hasFocus()) {
- result = widget;
- }
- });
+ var currentEditor = getCurrentFullEditor();
+ if (currentEditor) {
+ return currentEditor.getFocusedInlineWidget();
}
-
- return result;
+ return null;
}
/**
@@ -935,7 +660,8 @@ define(function (require, exports, module) {
* @return {?Editor}
*/
function getFocusedEditor() {
- if (_currentEditor) {
+ var currentEditor = getCurrentFullEditor();
+ if (currentEditor) {
// See if any inlines have focus
var focusedInline = _getFocusedInlineEditor();
@@ -944,8 +670,8 @@ define(function (require, exports, module) {
}
// otherwise, see if full-sized editor has focus
- if (_currentEditor.hasFocus()) {
- return _currentEditor;
+ if (currentEditor.hasFocus()) {
+ return currentEditor;
}
}
@@ -962,49 +688,9 @@ define(function (require, exports, module) {
function getActiveEditor() {
return _lastFocusedEditor;
}
+
-
- /**
- * Closes any focused inline widget. Else, asynchronously asks providers to create one.
- *
- * @param {Array.<{priority:number, provider:function(...)}>} providers
- * prioritized list of providers
- * @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).
- */
- function _toggleInlineWidget(providers, errorMsg) {
- var result = new $.Deferred();
-
- if (_currentEditor) {
- var inlineWidget = getFocusedInlineWidget();
-
- if (inlineWidget) {
- // an inline widget's editor has focus, so close it
- PerfUtils.markStart(PerfUtils.INLINE_WIDGET_CLOSE);
- inlineWidget.close().done(function () {
- PerfUtils.addMeasurement(PerfUtils.INLINE_WIDGET_CLOSE);
- // return a resolved promise to CommandManager
- result.resolve(false);
- });
- } else {
- // main editor has focus, so create an inline editor
- _openInlineWidget(_currentEditor, providers, errorMsg).done(function () {
- result.resolve(true);
- }).fail(function () {
- result.reject();
- });
- }
- } else {
- // Can not open an inline editor without a host editor
- result.reject();
- }
-
- return result.promise();
- }
-
- /**
+ /**
* Asynchronously asks providers to handle jump-to-definition.
* @return {!Promise} Resolved when the provider signals that it's done; rejected if no
* provider responded or the provider that responded failed.
@@ -1016,6 +702,7 @@ define(function (require, exports, module) {
result = new $.Deferred();
var editor = getActiveEditor();
+
if (editor) {
var pos = editor.getCursorPos();
@@ -1050,6 +737,33 @@ define(function (require, exports, module) {
return result.promise();
}
+
+ /**
+ * file removed from pane handler.
+ * @param {jQuery.Event} e
+ * @param {File|Array.} removedFiles - file, path or array of files or paths that are being removed
+ */
+ function _handleRemoveFromPaneView(e, removedFiles) {
+ var handleFileRemoved = function (file) {
+ var doc = DocumentManager.getOpenDocumentForPath(file.fullPath);
+
+ if (doc) {
+ MainViewManager._destroyEditorIfNotNeeded(doc);
+ }
+ };
+
+ // when files are removed from a pane then
+ // we should destroy any unnecssary views
+ if ($.isArray(removedFiles)) {
+ removedFiles.forEach(function (removedFile) {
+ handleFileRemoved(removedFile);
+ });
+ } else {
+ handleFileRemoved(removedFiles);
+ }
+ }
+
+
// File-based preferences handling
$(exports).on("activeEditorChange", function (e, current) {
if (current && current.document && current.document.file) {
@@ -1069,47 +783,40 @@ define(function (require, exports, module) {
// Create PerfUtils measurement
PerfUtils.createPerfMeasurement("JUMP_TO_DEFINITION", "Jump-To-Definiiton");
- // Initialize: register listeners
- $(DocumentManager).on("currentDocumentChange", _onCurrentDocumentChange);
- $(DocumentManager).on("workingSetRemove", _onWorkingSetRemove);
- $(DocumentManager).on("workingSetRemoveList", _onWorkingSetRemoveList);
- $(DocumentManager).on("fileNameChange", _onFileNameChange);
- $(PanelManager).on("editorAreaResize", _onEditorAreaResize);
-
+ $(MainViewManager).on("currentFileChange", _handleCurrentFileChange);
+ $(MainViewManager).on("workingSetRemove workingSetRemoveList", _handleRemoveFromPaneView);
+
// For unit tests and internal use only
- exports._openInlineWidget = _openInlineWidget;
exports._createFullEditorForDocument = _createFullEditorForDocument;
- exports._destroyEditorIfUnneeded = _destroyEditorIfUnneeded;
- exports._getViewState = _getViewState;
- exports._resetViewStates = _resetViewStates;
- exports._doShow = _doShow;
exports._notifyActiveEditorChanged = _notifyActiveEditorChanged;
- exports._showCustomViewer = _showCustomViewer;
- exports._closeCustomViewer = _closeCustomViewer;
-
-
-
- exports.REFRESH_FORCE = REFRESH_FORCE;
- exports.REFRESH_SKIP = REFRESH_SKIP;
+
+ // Internal Use only
+ exports._saveEditorViewState = _saveEditorViewState;
+ exports._createUnattachedMasterEditor = _createUnattachedMasterEditor;
// Define public API
- exports.setEditorHolder = setEditorHolder;
- exports.getCurrentFullEditor = getCurrentFullEditor;
exports.createInlineEditorForDocument = createInlineEditorForDocument;
- exports.focusEditor = focusEditor;
- exports.getFocusedEditor = getFocusedEditor;
- exports.getActiveEditor = getActiveEditor;
- exports.getCurrentlyViewedPath = getCurrentlyViewedPath;
exports.getFocusedInlineWidget = getFocusedInlineWidget;
- exports.resizeEditor = resizeEditor;
+ exports.getInlineEditors = getInlineEditors;
+ exports.closeInlineWidget = closeInlineWidget;
+ exports.openDocument = openDocument;
+ exports.canOpenPath = canOpenPath;
+
+ // Convenience Methods
+ exports.getActiveEditor = getActiveEditor;
+ exports.getCurrentFullEditor = getCurrentFullEditor;
+ exports.getFocusedEditor = getFocusedEditor;
+
+
exports.registerInlineEditProvider = registerInlineEditProvider;
exports.registerInlineDocsProvider = registerInlineDocsProvider;
exports.registerJumpToDefProvider = registerJumpToDefProvider;
- exports.getInlineEditors = getInlineEditors;
- exports.closeInlineWidget = closeInlineWidget;
+
+ // Deprecated
exports.registerCustomViewer = registerCustomViewer;
- exports.getCustomViewerForPath = getCustomViewerForPath;
- exports.notifyPathDeleted = notifyPathDeleted;
- exports.showingCustomViewerForPath = showingCustomViewerForPath;
+ exports.resizeEditor = resizeEditor;
+ exports.focusEditor = focusEditor;
+ exports.getCurrentlyViewedPath = getCurrentlyViewedPath;
+ exports.setEditorHolder = setEditorHolder;
});
diff --git a/src/editor/EditorOptionHandlers.js b/src/editor/EditorOptionHandlers.js
index 75dbde476cf..1af9cfa5bf3 100644
--- a/src/editor/EditorOptionHandlers.js
+++ b/src/editor/EditorOptionHandlers.js
@@ -22,19 +22,18 @@
*/
/*jslint vars: true, plusplus: true, devel: true, nomen: true, indent: 4, maxerr: 50 */
-/*global define, $ */
+/*global define */
define(function (require, exports, module) {
"use strict";
- var AppInit = require("utils/AppInit"),
- Editor = require("editor/Editor").Editor,
- EditorManager = require("editor/EditorManager"),
- Commands = require("command/Commands"),
- CommandManager = require("command/CommandManager"),
- PreferencesManager = require("preferences/PreferencesManager"),
- Strings = require("strings"),
- _ = require("thirdparty/lodash");
+ var AppInit = require("utils/AppInit"),
+ Editor = require("editor/Editor").Editor,
+ Commands = require("command/Commands"),
+ CommandManager = require("command/CommandManager"),
+ PreferencesManager = require("preferences/PreferencesManager"),
+ Strings = require("strings"),
+ _ = require("thirdparty/lodash");
// Constants for the preferences referred to in this file
var SHOW_LINE_NUMBERS = "showLineNumbers",
diff --git a/src/editor/EditorStatusBar.js b/src/editor/EditorStatusBar.js
index 7cf5520c4cb..0b742992699 100644
--- a/src/editor/EditorStatusBar.js
+++ b/src/editor/EditorStatusBar.js
@@ -37,6 +37,7 @@ define(function (require, exports, module) {
AppInit = require("utils/AppInit"),
DropdownButton = require("widgets/DropdownButton").DropdownButton,
EditorManager = require("editor/EditorManager"),
+ MainViewManager = require("view/MainViewManager"),
Editor = require("editor/Editor").Editor,
FileUtils = require("file/FileUtils"),
KeyEvent = require("utils/KeyEvent"),
@@ -184,7 +185,7 @@ define(function (require, exports, module) {
$indentWidthInput.off("blur keyup");
// restore focus to the editor
- EditorManager.focusEditor();
+ MainViewManager.focusActivePane();
var valInt = parseInt(value, 10);
if (Editor.getUseTabChar(fullPath)) {
@@ -260,10 +261,10 @@ define(function (require, exports, module) {
}
if (!current) {
- StatusBar.hide(); // calls resizeEditor() if needed
+ StatusBar.hideAllPanes();
} else {
var fullPath = current.document.file.fullPath;
- StatusBar.show(); // calls resizeEditor() if needed
+ StatusBar.showAllPanes();
$(current).on("cursorActivity.statusbar", _updateCursorInfo);
$(current).on("optionChange.statusbar", function () {
@@ -396,8 +397,6 @@ define(function (require, exports, module) {
});
$statusOverwrite.on("click", _updateEditorOverwriteMode);
-
- _onActiveEditorChange(null, EditorManager.getActiveEditor(), null);
}
// Initialize: status bar focused listener
@@ -408,5 +407,7 @@ define(function (require, exports, module) {
// Populate language switcher with all languages after startup; update it later if this set changes
_populateLanguageDropdown();
$(LanguageManager).on("languageAdded languageModified", _populateLanguageDropdown);
+ _onActiveEditorChange(null, EditorManager.getActiveEditor(), null);
+ StatusBar.show();
});
});
diff --git a/src/editor/ImageViewer.js b/src/editor/ImageViewer.js
index 1d914b0d6fd..499067b3398 100644
--- a/src/editor/ImageViewer.js
+++ b/src/editor/ImageViewer.js
@@ -28,172 +28,177 @@ define(function (require, exports, module) {
"use strict";
var DocumentManager = require("document/DocumentManager"),
- EditorManager = require("editor/EditorManager"),
- ImageHolderTemplate = require("text!htmlContent/image-holder.html"),
- PanelManager = require("view/PanelManager"),
+ ImageViewTemplate = require("text!htmlContent/image-view.html"),
ProjectManager = require("project/ProjectManager"),
+ LanguageManager = require("language/LanguageManager"),
+ MainViewFactory = require("view/MainViewFactory"),
Strings = require("strings"),
StringUtils = require("utils/StringUtils"),
FileSystem = require("filesystem/FileSystem"),
- FileUtils = require("file/FileUtils");
+ FileUtils = require("file/FileUtils"),
+ _ = require("thirdparty/lodash");
- var _naturalWidth = 0,
- _naturalHeight = 0,
- _scale = 100,
- _scaleDivInfo = null; // coordinates of hidden scale sticker
- /** Update the scale element, i.e. on resize
- * @param {!string} currentWidth actual width of image in view
- */
- function _updateScale(currentWidth) {
- if (currentWidth && currentWidth < _naturalWidth) {
- _scale = currentWidth / _naturalWidth * 100;
- $("#img-scale").text(Math.floor(_scale) + "%")
- // Keep the position of the image scale div relative to the image.
- .css("left", $("#img-preview").position().left + 5)
- .show();
- } else {
- // Reset everything related to the image scale sticker before hiding it.
- _scale = 100;
- _scaleDivInfo = null;
- $("#img-scale").text("").hide();
- }
- }
-
- function _hideGuidesAndTip() {
- $("#img-tip").hide();
- $(".img-guide").hide();
- }
-
- /** handle editor resize event, i.e. update scale sticker */
- function _onEditorAreaResize() {
- _hideGuidesAndTip();
- _updateScale($("#img-preview").width());
- }
+ var _viewers = {};
/**
- * Update file name if necessary
+ * ImageView objects are constructed when an image is opened
+ * @see {@link Pane} for more information about where ImageViews are rendered
+ *
+ * @constructor
+ * @param {!File} file - The image file object to render
+ * @param {!jQuery} container - The container to render the image view in
*/
- function _onFileNameChange(e, oldName, newName) {
- var oldRelPath = ProjectManager.makeProjectRelativeIfPossible(oldName),
- currentPath = $("#img-path").text();
+ function ImageView(file, $container) {
+ this.file = file;
+ this.$el = $(Mustache.render(ImageViewTemplate, {fullPath: file.fullPath,
+ now: new Date().valueOf()}));
+
+ $container.append(this.$el);
- if (currentPath === oldRelPath) {
- var newRelName = ProjectManager.makeProjectRelativeIfPossible(newName);
- $("#img-path").text(newRelName)
- .attr("title", newRelName);
- }
+ this._naturalWidth = 0;
+ this._naturalHeight = 0;
+ this._scale = 100; // 100%
+ this._scaleDivInfo = null; // coordinates of hidden scale sticker
+
+ this.relPath = ProjectManager.makeProjectRelativeIfPossible(this.file.fullPath);
+
+ this.$imagePath = this.$el.find(".image-path");
+ this.$imagePreview = this.$el.find(".image-preview");
+ this.$imageData = this.$el.find(".image-data");
+
+ this.$image = this.$el.find(".image");
+ this.$imageTip = this.$el.find(".image-tip");
+ this.$imageGuides = this.$el.find(".image-guide");
+ this.$imageScale = this.$el.find(".image-scale");
+ this.$x_value = this.$el.find(".x-value");
+ this.$y_value = this.$el.find(".y-value");
+ this.$horzGuide = this.$el.find(".horz-guide");
+ this.$vertGuide = this.$el.find(".vert-guide");
+
+ this.$imagePath.text(this.relPath).attr("title", this.relPath);
+ this.$imagePreview.on("load", _.bind(this._onImageLoaded, this));
+
+ _viewers[file.fullPath] = this;
}
/**
- * Check mouse entering/exiting the scale sticker.
- * Hide it when entering and show it again when exiting.
- *
- * @param {number} offsetX mouse offset from the left of the previewing image
- * @param {number} offsetY mouseoffset from the top of the previewing image
+ * DocumentManger.fileNameChange handler - when an image is renamed, we must
+ * update the view
+ *
+ * @param {jQuery.Event} e - event
+ * @param {!string} oldPath - the name of the file that's changing changing
+ * @param {!string} newPath - the name of the file that's changing changing
+ * @private
*/
- function _handleMouseEnterOrExitScaleSticker(offsetX, offsetY) {
- var imagePos = $("#img-preview").position(),
- scaleDivPos = $("#img-scale").position(),
- imgWidth = $("#img-preview").width(),
- imgHeight = $("#img-preview").height(),
- scaleDivLeft,
- scaleDivTop,
- scaleDivRight,
- scaleDivBottom;
+ ImageView.prototype._onFilenameChange = function (e, oldPath, newPath) {
+ /*
+ * File objects are already updated when the event is triggered
+ * so we just need to see if the file has the same path as our image
+ */
+ if (this.file.fullPath === newPath) {
+ this.relPath = ProjectManager.makeProjectRelativeIfPossible(newPath);
+ this.$imagePath.text(this.relPath).attr("title", this.relPath);
+ }
+ };
+
+ /**
+ * .on("load") handler - updates content of the image view
+ * initializes computed values
+ * installs event handlers
+ * @param {Event} e - event
+ * @private
+ */
+ ImageView.prototype._onImageLoaded = function (e) {
+ // add dimensions and size
+ this._naturalWidth = e.currentTarget.naturalWidth;
+ this._naturalHeight = e.currentTarget.naturalHeight;
- if (_scaleDivInfo) {
- scaleDivLeft = _scaleDivInfo.left;
- scaleDivTop = _scaleDivInfo.top;
- scaleDivRight = _scaleDivInfo.right;
- scaleDivBottom = _scaleDivInfo.bottom;
-
- if ((imgWidth + imagePos.left) < scaleDivRight) {
- scaleDivRight = imgWidth + imagePos.left;
- }
-
- if ((imgHeight + imagePos.top) < scaleDivBottom) {
- scaleDivBottom = imgHeight + imagePos.top;
- }
-
- } else {
- scaleDivLeft = scaleDivPos.left;
- scaleDivTop = scaleDivPos.top;
- scaleDivRight = $("#img-scale").width() + scaleDivLeft;
- scaleDivBottom = $("#img-scale").height() + scaleDivTop;
+ var extension = FileUtils.getFileExtension(this.file.fullPath);
+ var dimensionString = this._naturalWidth + " × " + this._naturalHeight + " " + Strings.UNIT_PIXELS;
+
+ if (extension === "ico") {
+ dimensionString += " (" + Strings.IMAGE_VIEWER_LARGEST_ICON + ")";
}
- if (_scaleDivInfo) {
- // See whether the cursor is no longer inside the hidden scale div.
- // If so, show it again.
- if ((offsetX < scaleDivLeft || offsetX > scaleDivRight) ||
- (offsetY < scaleDivTop || offsetY > scaleDivBottom)) {
- _scaleDivInfo = null;
- $("#img-scale").show();
- }
- } else if ((offsetX >= scaleDivLeft && offsetX <= scaleDivRight) &&
- (offsetY >= scaleDivTop && offsetY <= scaleDivBottom)) {
- // Handle mouse inside image scale div.
- // But hide it only if the pixel under mouse is also in the image.
- if (offsetX < (imagePos.left + imgWidth) &&
- offsetY < (imagePos.top + imgHeight)) {
- // Remember image scale div coordinates before hiding it.
- _scaleDivInfo = {left: scaleDivPos.left,
- top: scaleDivPos.top,
- right: scaleDivRight,
- bottom: scaleDivBottom};
- $("#img-scale").hide();
+ // get image size
+ var self = this;
+
+ this.file.stat(function (err, stat) {
+ if (err) {
+ self.$imageData.html(dimensionString);
+ } else {
+ var sizeString = "";
+ if (stat.size) {
+ sizeString = " — " + StringUtils.prettyPrintBytes(stat.size, 2);
+ }
+ var dimensionAndSize = dimensionString + sizeString;
+ self.$imageData.html(dimensionAndSize)
+ .attr("title", dimensionAndSize
+ .replace("×", "x")
+ .replace("—", "-"));
}
- }
- }
+ });
+
+ // make sure we always show the right file name
+ $(DocumentManager).on("fileNameChange", _.bind(this._onFilenameChange, this));
+
+ this.$imageTip.hide();
+ this.$imageGuides.hide();
+
+ this.$image.on("mousemove.ImageView", ".image-preview", _.bind(this._showImageTip, this))
+ .on("mouseleave.ImageView", ".image-preview", _.bind(this._hideImageTip, this));
+
+ this._updateScale();
+ };
/**
- * Hide image coordinates info tip
- *
- * @param {MouseEvent} e mouse leave event
+ * Update the scale element
+ * @private
*/
- function _hideImageTip(e) {
- var $target = $(e.target),
- targetPos = $target.position(),
- imagePos = $("#img-preview").position(),
- right = imagePos.left + $("#img-preview").width(),
- bottom = imagePos.top + $("#img-preview").height(),
- x = targetPos.left + e.offsetX,
- y = targetPos.top + e.offsetY;
+ ImageView.prototype._updateScale = function () {
+ var currentWidth = this.$imagePreview.width();
- // Hide image tip and guides only if the cursor is outside of the image.
- if (x < imagePos.left || x >= right ||
- y < imagePos.top || y >= bottom) {
- _hideGuidesAndTip();
- if (_scaleDivInfo) {
- _scaleDivInfo = null;
- $("#img-scale").show();
- }
+ if (currentWidth && currentWidth < this._naturalWidth) {
+ this._scale = currentWidth / this._naturalWidth * 100;
+ this.$imageScale.text(Math.floor(this._scale) + "%")
+ // Keep the position of the image scale div relative to the image.
+ .css("left", this.$imagePreview.position().left + 5)
+ .show();
+ } else {
+ // Reset everything related to the image scale sticker before hiding it.
+ this._scale = 100;
+ this._scaleDivInfo = null;
+ this.$imageScale.text("").hide();
}
- }
-
+ };
+
+
/**
* Show image coordinates under the mouse cursor
- *
- * @param {MouseEvent} e mouse move event
+ * @param {Event} e - event
+ * @private
*/
- function _showImageTip(e) {
- // Don't show image tip if _scale is close to zero.
+ ImageView.prototype._showImageTip = function (e) {
+ // Don't show image tip if this._scale is close to zero.
// since we won't have enough room to show tip anyway.
- if (Math.floor(_scale) === 0) {
+ if (Math.floor(this._scale) === 0) {
return;
}
- var x = Math.round(e.offsetX * 100 / _scale),
- y = Math.round(e.offsetY * 100 / _scale),
- $target = $(e.target),
- imagePos = $("#img-preview").position(),
+ var x = Math.round(e.offsetX * 100 / this._scale),
+ y = Math.round(e.offsetY * 100 / this._scale),
+ imagePos = this.$imagePreview.position(),
left = e.offsetX + imagePos.left,
top = e.offsetY + imagePos.top,
- width = $("#img-preview").width(),
- height = $("#img-preview").height(),
+ width = this.$imagePreview.width(),
+ height = this.$imagePreview.height(),
windowWidth = $(window).width(),
- fourDigitImageWidth = _naturalWidth.toString().length === 4,
+ fourDigitImageWidth = this._naturalWidth.toString().length === 4,
+
+ // @todo -- seems a bit strange that we're computing sizes
+ // using magic numbers
+
infoWidth1 = 112, // info div width 96px + vertical toolbar width 16px
infoWidth2 = 120, // info div width 104px (for 4-digit image width) + vertical toolbar width 16px
tipOffsetX = 10, // adjustment for info div left from x coordinate of cursor
@@ -205,15 +210,15 @@ define(function (require, exports, module) {
// or the rounding calculation above for a scaled image. For example, if an image is 120 px wide,
// we should get mousemove events in the range of 0 <= x < 120, but not 120 or more. If we get
// a value beyond the range, then simply handle the event as if it were a mouseleave.
- if (x < 0 || x >= _naturalWidth || y < 0 || y >= _naturalHeight) {
- _hideImageTip(e);
- $("#img-preview").css("cursor", "auto");
+ if (x < 0 || x >= this._naturalWidth || y < 0 || y >= this._naturalHeight) {
+ this._hideImageTip(e);
+ this.$imagePreview.css("cursor", "auto");
return;
}
- $("#img-preview").css("cursor", "none");
+ this.$imagePreview.css("cursor", "none");
- _handleMouseEnterOrExitScaleSticker(left, top);
+ this._handleMouseEnterOrExitScaleSticker(left, top);
// Check whether to show the image tip on the left.
if ((e.pageX + infoWidth1) > windowWidth ||
@@ -221,106 +226,255 @@ define(function (require, exports, module) {
tipOffsetX = fourDigitImageWidth ? tipMinusOffsetX2 : tipMinusOffsetX1;
}
- $("#x-value").text(x + "px");
- $("#y-value").text(y + "px");
+ this.$x_value.text(x + "px");
+ this.$y_value.text(y + "px");
- $("#img-tip").css({
+ this.$imageTip.css({
left: left + tipOffsetX,
top: top + tipOffsetY
}).show();
- $("#horiz-guide").css({
+ this.$horzGuide.css({
left: imagePos.left,
top: top,
width: width - 1
}).show();
- $("#vert-guide").css({
+ this.$vertGuide.css({
left: left,
top: imagePos.top,
height: height - 1
}).show();
- }
+ };
+
+ /**
+ * Hide image coordinates info tip
+ * @param {Event} e - event
+ * @private
+ */
+ ImageView.prototype._hideImageTip = function (e) {
+ var $target = $(e.target),
+ targetPos = $target.position(),
+ imagePos = this.$imagePreview.position(),
+ right = imagePos.left + this.$imagePreview.width(),
+ bottom = imagePos.top + this.$imagePreview.height(),
+ x = targetPos.left + e.offsetX,
+ y = targetPos.top + e.offsetY;
+ // Hide image tip and guides only if the cursor is outside of the image.
+ if (x < imagePos.left || x >= right ||
+ y < imagePos.top || y >= bottom) {
+ this._hideGuidesAndTip();
+ if (this._scaleDivInfo) {
+ this._scaleDivInfo = null;
+ this.$imageScale.show();
+ }
+ }
+ };
+
/**
- * sign off listeners when editor manager closes
- * the image viewer
+ * Hides both guides and the tip
+ * @private
*/
- function onRemove() {
- $(PanelManager).off("editorAreaResize", _onEditorAreaResize);
- $(DocumentManager).off("fileNameChange", _onFileNameChange);
- $("#img").off("mousemove", "#img-preview", _showImageTip)
- .off("mouseleave", "#img-preview", _hideImageTip);
- }
-
+ ImageView.prototype._hideGuidesAndTip = function () {
+ this.$imageTip.hide();
+ this.$imageGuides.hide();
+ };
+
/**
- * Perform decorations on the view that require loading the image in the browser,
- * i.e. getting actual and natural width and height andplacing the scale sticker
- * @param {!string} fullPath Path to the image file
- * @param {!jQueryObject} $editorHolder The DOM element to append the view to.
+ * Check mouse entering/exiting the scale sticker.
+ * Hide it when entering and show it again when exiting.
+ *
+ * @param {number} offsetX mouse offset from the left of the previewing image
+ * @param {number} offsetY mouseoffset from the top of the previewing image
+ * @private
*/
- function render(fullPath, $editorHolder) {
- var relPath = ProjectManager.makeProjectRelativeIfPossible(fullPath),
- $customViewer = $(Mustache.render(ImageHolderTemplate, {fullPath: fullPath}));
-
- // place DOM node to hold image
- $editorHolder.append($customViewer);
-
- _scale = 100; // initialize to 100
- _scaleDivInfo = null;
+ ImageView.prototype._handleMouseEnterOrExitScaleSticker = function (offsetX, offsetY) {
+ var imagePos = this.$imagePreview.position(),
+ scaleDivPos = this.$imageScale.position(),
+ imgWidth = this.$imagePreview.width(),
+ imgHeight = this.$imagePreview.height(),
+ scaleDivLeft,
+ scaleDivTop,
+ scaleDivRight,
+ scaleDivBottom;
- $("#img-path").text(relPath)
- .attr("title", relPath);
- $("#img-preview").on("load", function () {
- // add dimensions and size
- _naturalWidth = this.naturalWidth;
- _naturalHeight = this.naturalHeight;
- var ext = FileUtils.getFileExtension(fullPath);
- var dimensionString = _naturalWidth + " × " + this.naturalHeight + " " + Strings.UNIT_PIXELS;
- if (ext === "ico") {
- dimensionString += " (" + Strings.IMAGE_VIEWER_LARGEST_ICON + ")";
+ if (this._scaleDivInfo) {
+ scaleDivLeft = this._scaleDivInfo.left;
+ scaleDivTop = this._scaleDivInfo.top;
+ scaleDivRight = this._scaleDivInfo.right;
+ scaleDivBottom = this._scaleDivInfo.bottom;
+
+ if ((imgWidth + imagePos.left) < scaleDivRight) {
+ scaleDivRight = imgWidth + imagePos.left;
+ }
+
+ if ((imgHeight + imagePos.top) < scaleDivBottom) {
+ scaleDivBottom = imgHeight + imagePos.top;
}
- // get image size
- var file = FileSystem.getFileForPath(fullPath);
- file.stat(function (err, stat) {
- if (err) {
- $("#img-data").html(dimensionString);
- } else {
- var sizeString = "";
- if (stat.size) {
- sizeString = " — " + StringUtils.prettyPrintBytes(stat.size, 2);
- }
- var dimensionAndSize = dimensionString + sizeString;
- $("#img-data").html(dimensionAndSize)
- .attr("title", dimensionAndSize
- .replace("×", "x")
- .replace("—", "-"));
- }
- });
- $("#image-holder").show();
- // listen to resize to update the scale sticker
- $(PanelManager).on("editorAreaResize", _onEditorAreaResize);
+ } else {
+ scaleDivLeft = scaleDivPos.left;
+ scaleDivTop = scaleDivPos.top;
+ scaleDivRight = this.$imageScale.width() + scaleDivLeft;
+ scaleDivBottom = this.$imageScale.height() + scaleDivTop;
+ }
+
+ if (this._scaleDivInfo) {
+ // See whether the cursor is no longer inside the hidden scale div.
+ // If so, show it again.
+ if ((offsetX < scaleDivLeft || offsetX > scaleDivRight) ||
+ (offsetY < scaleDivTop || offsetY > scaleDivBottom)) {
+ this._scaleDivInfo = null;
+ this.$imageScale.show();
+ }
+ } else if ((offsetX >= scaleDivLeft && offsetX <= scaleDivRight) &&
+ (offsetY >= scaleDivTop && offsetY <= scaleDivBottom)) {
+ // Handle mouse inside image scale div.
+ // But hide it only if the pixel under mouse is also in the image.
+ if (offsetX < (imagePos.left + imgWidth) &&
+ offsetY < (imagePos.top + imgHeight)) {
+ // Remember image scale div coordinates before hiding it.
+ this._scaleDivInfo = {left: scaleDivPos.left,
+ top: scaleDivPos.top,
+ right: scaleDivRight,
+ bottom: scaleDivBottom};
+ this.$imageScale.hide();
+ }
+ }
+ };
+
+ /**
+ * View Interface functions
+ */
+
+ /*
+ * Retrieves the file object for this view
+ * return {!File} the file object for this view
+ */
+ ImageView.prototype.getFile = function () {
+ return this.file;
+ };
+
+ /*
+ * Updates the layout of the view
+ */
+ ImageView.prototype.updateLayout = function () {
+ this._hideGuidesAndTip();
+
+ var $container = this.$el.parent();
+
+ var pos = $container.position(),
+ iWidth = $container.innerWidth(),
+ iHeight = $container.innerHeight(),
+ oWidth = $container.outerWidth(),
+ oHeight = $container.outerHeight();
- // make sure we always show the right file name
- $(DocumentManager).on("fileNameChange", _onFileNameChange);
+ // $view is "position:absolute" so
+ // we have to update the height, width and position
+ this.$el.css({top: pos.top + ((oHeight - iHeight) / 2),
+ left: pos.left + ((oWidth - iWidth) / 2),
+ width: iWidth,
+ height: iHeight});
+ this._updateScale();
+ };
+
+ /*
+ * Destroys the view
+ */
+ ImageView.prototype.destroy = function () {
+ delete _viewers[this.file.fullPath];
+ $(DocumentManager).off("fileNameChange", _.bind(this._onFilenameChange, this));
+ this.$image.off(".ImageView");
+ this.$el.remove();
+ };
+
+ /*
+ * Refreshes the image preview with what's on disk
+ */
+ ImageView.prototype.refresh = function () {
+ var noCacheUrl = this.$imagePreview.attr("src"),
+ now = new Date().valueOf(),
+ index = noCacheUrl.indexOf("?");
- $("#img-tip").hide();
- $(".img-guide").hide();
- $("#img").on("mousemove", "#img-preview", _showImageTip)
- .on("mouseleave", "#img-preview", _hideImageTip);
+ // strip the old param off
+ if (index > 0) {
+ noCacheUrl = noCacheUrl.slice(0, index);
+ }
+
+ // add a new param which will force chrome to
+ // re-read the image from disk
+ noCacheUrl = noCacheUrl + "?ver=" + now;
+
- _updateScale($(this).width());
+ // Update the DOM node with the src URL
+ this.$imagePreview.attr("src", noCacheUrl);
+ };
+
+ /*
+ * Creates an image view object and adds it to the specified pane
+ * @param {!File} file - the file to create an image of
+ * @param {!Pane} pane - the pane in which to host the view
+ * @return {jQuery.Promise}
+ */
+ function _createImageView(file, pane) {
+ var view = pane.getViewForPath(file.fullPath);
+
+ if (view) {
+ pane.showView(view);
+ } else {
+ view = new ImageView(file, pane.$content);
+ pane.addView(view, true);
+ }
+ return new $.Deferred().resolve().promise();
+ }
+
+ /**
+ * Handles file system change events so we can refresh
+ * image viewers for the files that changed on disk due to external editors
+ * @param {jQuery.event} event - event object
+ * @param {?File} file - file object that changed
+ * @param {Array.=} added If entry is a Directory, contains zero or more added children
+ * @param {Array.=} removed If entry is a Directory, contains zero or more removed children
+ */
+ function _handleFileSystemChange(event, entry, added, removed) {
+ // this may have been called because files were added
+ // or removed to the file system. We don't care about those
+ if (!entry || entry.isDirectory) {
+ return;
+ }
+
+ // Look for a viewer for the changed file
+ var viewer = _viewers[entry.fullPath];
- });
- return $customViewer;
+ // viewer found, call its refresh method
+ if (viewer) {
+ viewer.refresh();
+ }
}
- EditorManager.registerCustomViewer("image", {
- render: render,
- onRemove: onRemove
+ /*
+ * Install an event listener to receive all file system change events
+ * so we can refresh the view when changes are made to the image in an external editor
+ */
+ FileSystem.on("change", _handleFileSystemChange);
+
+ /*
+ * Initialization, register our view factory
+ */
+ MainViewFactory.registerViewFactory({
+ canOpenFile: function (fullPath) {
+ var lang = LanguageManager.getLanguageForPath(fullPath);
+ return (lang.getId() === "image");
+ },
+ openFile: function (file, pane) {
+ return _createImageView(file, pane);
+ }
});
- exports.render = render;
- exports.onRemove = onRemove;
+ /*
+ * This is for extensions that want to create a
+ * view factory based on ImageViewer
+ */
+ exports.ImageView = ImageView;
});
diff --git a/src/editor/InlineTextEditor.js b/src/editor/InlineTextEditor.js
index ca6cc60cbf2..2d9595ff4dd 100644
--- a/src/editor/InlineTextEditor.js
+++ b/src/editor/InlineTextEditor.js
@@ -38,14 +38,6 @@ define(function (require, exports, module) {
InlineWidget = require("editor/InlineWidget").InlineWidget,
KeyEvent = require("utils/KeyEvent");
- /**
- * Returns editor holder width (not CodeMirror's width).
- * @private
- */
- function _editorHolderWidth() {
- return $("#editor-holder").width();
- }
-
/**
* Shows or hides the dirty indicator
* @private
@@ -300,10 +292,6 @@ define(function (require, exports, module) {
* @param {Editor} editor
*/
InlineTextEditor.prototype._updateLineRange = function (editor) {
- var oldStartLine = this._startLine,
- oldEndLine = this._endLine,
- oldLineCount = this._lineCount;
-
this._startLine = editor.getFirstVisibleLine();
this._endLine = editor.getLastVisibleLine();
this._lineCount = this._endLine - this._startLine;
diff --git a/src/editor/MultiRangeInlineEditor.js b/src/editor/MultiRangeInlineEditor.js
index e1714fdc43b..9356faebc27 100644
--- a/src/editor/MultiRangeInlineEditor.js
+++ b/src/editor/MultiRangeInlineEditor.js
@@ -46,8 +46,7 @@ define(function (require, exports, module) {
EditorManager = require("editor/EditorManager"),
Commands = require("command/Commands"),
Strings = require("strings"),
- CommandManager = require("command/CommandManager"),
- PerfUtils = require("utils/PerfUtils");
+ CommandManager = require("command/CommandManager");
var _prevMatchCmd, _nextMatchCmd;
@@ -193,7 +192,6 @@ define(function (require, exports, module) {
this.$rangeList = $("
").appendTo(this.$related);
// create range list & add listeners for range textrange changes
- var rangeItemText;
this._ranges.forEach(this._createListItem, this);
if (this._ranges.length > 1) { // attach to main container
@@ -234,8 +232,6 @@ define(function (require, exports, module) {
* @override
*/
MultiRangeInlineEditor.prototype.onAdded = function () {
- var self = this;
-
// Before setting the inline widget height, force a height on the
// floating related-container in order for CodeMirror to layout and
// compute scrollbars
diff --git a/src/extensibility/ExtensionManager.js b/src/extensibility/ExtensionManager.js
index d3b1a91e182..a679c3a0e38 100644
--- a/src/extensibility/ExtensionManager.js
+++ b/src/extensibility/ExtensionManager.js
@@ -22,7 +22,7 @@
*/
/*jslint vars: true, plusplus: true, devel: true, nomen: true, regexp: true, indent: 4, maxerr: 50 */
-/*global define, window, $, brackets, semver */
+/*global define, $, brackets */
/*unittests: ExtensionManager*/
/**
@@ -39,7 +39,6 @@ define(function (require, exports, module) {
"use strict";
var _ = require("thirdparty/lodash"),
- FileUtils = require("file/FileUtils"),
Package = require("extensibility/Package"),
Async = require("utils/Async"),
ExtensionLoader = require("utils/ExtensionLoader"),
@@ -601,31 +600,6 @@ define(function (require, exports, module) {
}, []);
}
- /**
- * Toggles between truncated and full length extension descriptions
- * @param {string} id The id of the extension clicked
- * @param {JQueryElement} $element The DOM element of the extension clicked
- * @param {boolean} showFull true if full length description should be shown, false for shorten version.
- */
- function toggleDescription(id, $element, showFull) {
- var description, linkTitle,
- entry = extensions[id];
-
- // Toggle between appropriate descriptions and link title,
- // depending on if extension is installed or not
- if (showFull) {
- description = entry.installInfo ? entry.installInfo.metadata.description : entry.registryInfo.metadata.description;
- linkTitle = Strings.VIEW_TRUNCATED_DESCRIPTION;
- } else {
- description = entry.installInfo ? entry.installInfo.metadata.shortdescription : entry.registryInfo.metadata.shortdescription;
- linkTitle = Strings.VIEW_COMPLETE_DESCRIPTION;
- }
-
- $element.attr("data-toggle-desc", showFull ? "trunc-desc" : "expand-desc")
- .attr("title", linkTitle)
- .prev(".ext-full-description").html(description);
- }
-
// Listen to extension load and loadFailed events
$(ExtensionLoader)
.on("load", _handleExtensionLoad)
@@ -651,7 +625,6 @@ define(function (require, exports, module) {
exports.updateExtensions = updateExtensions;
exports.getAvailableUpdates = getAvailableUpdates;
exports.cleanAvailableUpdates = cleanAvailableUpdates;
- exports.toggleDescription = toggleDescription;
exports.ENABLED = ENABLED;
exports.START_FAILED = START_FAILED;
diff --git a/src/extensibility/ExtensionManagerDialog.js b/src/extensibility/ExtensionManagerDialog.js
index 854593ef92c..8008dbc3755 100644
--- a/src/extensibility/ExtensionManagerDialog.js
+++ b/src/extensibility/ExtensionManagerDialog.js
@@ -22,7 +22,7 @@
*/
/*jslint vars: true, plusplus: true, devel: true, nomen: true, indent: 4, maxerr: 50 */
-/*global brackets, define, $, Mustache, window */
+/*global brackets, define, $, Mustache */
define(function (require, exports, module) {
"use strict";
@@ -40,6 +40,7 @@ define(function (require, exports, module) {
InstallExtensionDialog = require("extensibility/InstallExtensionDialog"),
AppInit = require("utils/AppInit"),
Async = require("utils/Async"),
+ KeyEvent = require("utils/KeyEvent"),
ExtensionManager = require("extensibility/ExtensionManager"),
ExtensionManagerView = require("extensibility/ExtensionManagerView").ExtensionManagerView,
ExtensionManagerViewModel = require("extensibility/ExtensionManagerViewModel");
@@ -304,16 +305,36 @@ define(function (require, exports, module) {
$dlg = dialog.getElement();
$search = $(".search", $dlg);
$searchClear = $(".search-clear", $dlg);
-
+
+ function setActiveTab($tab) {
+ models[_activeTabIndex].scrollPos = $(".modal-body", $dlg).scrollTop();
+ $tab.tab("show");
+ $(".modal-body", $dlg).scrollTop(models[_activeTabIndex].scrollPos || 0);
+ $searchClear.click();
+ }
+
// Dialog tabs
$dlg.find(".nav-tabs a")
.on("click", function (event) {
- models[_activeTabIndex].scrollPos = $(".modal-body", $dlg).scrollTop();
- $(this).tab("show");
- $(".modal-body", $dlg).scrollTop(models[_activeTabIndex].scrollPos || 0);
- $searchClear.click();
+ setActiveTab($(this));
});
-
+
+ // navigate through tabs via Ctrl-(Shift)-Tab
+ $dlg.on("keyup", function (event) {
+ if (event.keyCode === KeyEvent.DOM_VK_TAB && event.ctrlKey) {
+ var $tabs = $(".nav-tabs a", $dlg),
+ tabIndex = _activeTabIndex;
+
+ if (event.shiftKey) {
+ tabIndex--;
+ } else {
+ tabIndex++;
+ }
+ tabIndex %= $tabs.length;
+ setActiveTab($tabs.eq(tabIndex));
+ }
+ });
+
// Update & hide/show the notification overlay on a tab's icon, based on its model's notifyCount
function updateNotificationIcon(index) {
var model = models[index],
diff --git a/src/extensibility/ExtensionManagerView.js b/src/extensibility/ExtensionManagerView.js
index 40ab53b8f29..082b9509602 100644
--- a/src/extensibility/ExtensionManagerView.js
+++ b/src/extensibility/ExtensionManagerView.js
@@ -22,7 +22,7 @@
*/
/*jslint vars: true, plusplus: true, devel: true, nomen: true, indent: 4, maxerr: 50, regexp: true */
-/*global define, window, $, brackets, Mustache */
+/*global define, $, brackets, Mustache */
/*unittests: ExtensionManager*/
define(function (require, exports, module) {
@@ -111,6 +111,31 @@ define(function (require, exports, module) {
*/
ExtensionManagerView.prototype._itemViews = null;
+ /**
+ * Toggles between truncated and full length extension descriptions
+ * @param {string} id The id of the extension clicked
+ * @param {JQueryElement} $element The DOM element of the extension clicked
+ * @param {boolean} showFull true if full length description should be shown, false for shortened version.
+ */
+ ExtensionManagerView.prototype._toggleDescription = function (id, $element, showFull) {
+ var description, linkTitle,
+ info = this.model._getEntry(id);
+
+ // Toggle between appropriate descriptions and link title,
+ // depending on if extension is installed or not
+ if (showFull) {
+ description = info.metadata.description;
+ linkTitle = Strings.VIEW_TRUNCATED_DESCRIPTION;
+ } else {
+ description = info.metadata.shortdescription;
+ linkTitle = Strings.VIEW_COMPLETE_DESCRIPTION;
+ }
+
+ $element.data("toggle-desc", showFull ? "trunc-desc" : "expand-desc")
+ .attr("title", linkTitle)
+ .prev(".ext-full-description").text(description);
+ };
+
/**
* @private
* Attaches our event handlers. We wait to do this until we've fully fetched the extension list.
@@ -154,12 +179,12 @@ define(function (require, exports, module) {
ExtensionManager.markForRemoval($target.attr("data-extension-id"), true);
} else if ($target.hasClass("undo-update")) {
ExtensionManager.removeUpdate($target.attr("data-extension-id"));
- } else if ($target.attr("data-toggle-desc") === "expand-desc") {
- ExtensionManager.toggleDescription($target.attr("data-extension-id"), $target, true);
- } else if ($target.attr("data-toggle-desc") === "trunc-desc") {
- ExtensionManager.toggleDescription($target.attr("data-extension-id"), $target, false);
+ } else if ($target.data("toggle-desc") === "expand-desc") {
+ this._toggleDescription($target.attr("data-extension-id"), $target, true);
+ } else if ($target.data("toggle-desc") === "trunc-desc") {
+ this._toggleDescription($target.attr("data-extension-id"), $target, false);
}
- })
+ }.bind(this))
.on("click", "button.install", function (e) {
self._installUsingDialog($(e.target).attr("data-extension-id"));
})
@@ -211,6 +236,22 @@ define(function (require, exports, module) {
context.isCompatible = context.isCompatibleLatest = true;
}
+ // Check if extension metadata contains localized content.
+ var lang = brackets.getLocale(),
+ shortLang = lang.split("-")[0];
+ if (info.metadata["package-i18n"]) {
+ [shortLang, lang].forEach(function (locale) {
+ if (info.metadata["package-i18n"].hasOwnProperty(locale)) {
+ // only overlay specific properties with the localized values
+ ["title", "description", "homepage", "keywords"].forEach(function (prop) {
+ if (info.metadata["package-i18n"][locale].hasOwnProperty(prop)) {
+ info.metadata[prop] = info.metadata["package-i18n"][locale][prop];
+ }
+ });
+ }
+ });
+ }
+
if (info.metadata.description !== undefined) {
info.metadata.shortdescription = StringUtils.truncate(info.metadata.description, 200);
}
@@ -224,9 +265,6 @@ define(function (require, exports, module) {
context.allowInstall = context.isCompatible && !context.isInstalled;
if (Array.isArray(info.metadata.i18n) && info.metadata.i18n.length > 0) {
- var lang = brackets.getLocale(),
- shortLang = lang.split("-")[0];
-
context.translated = true;
context.translatedLangs =
info.metadata.i18n.map(function (value) {
@@ -309,8 +347,7 @@ define(function (require, exports, module) {
* new items for entries that haven't yet been rendered, but will not re-render existing items.
*/
ExtensionManagerView.prototype._render = function () {
- var self = this,
- $item;
+ var self = this;
this._$table.empty();
this._updateMessage();
diff --git a/src/extensibility/ExtensionManagerViewModel.js b/src/extensibility/ExtensionManagerViewModel.js
index 107fc29642e..d40e0a73529 100644
--- a/src/extensibility/ExtensionManagerViewModel.js
+++ b/src/extensibility/ExtensionManagerViewModel.js
@@ -22,7 +22,7 @@
*/
/*jslint vars: true, plusplus: true, devel: true, nomen: true, indent: 4, maxerr: 50, regexp: true */
-/*global define, window, $, brackets, Mustache */
+/*global define, $ */
/*unittests: ExtensionManager*/
define(function (require, exports, module) {
@@ -31,7 +31,6 @@ define(function (require, exports, module) {
var _ = require("thirdparty/lodash");
var ExtensionManager = require("extensibility/ExtensionManager"),
- Package = require("extensibility/Package"),
registry_utils = require("extensibility/registry_utils"),
Strings = require("strings");
diff --git a/src/extensibility/InstallExtensionDialog.js b/src/extensibility/InstallExtensionDialog.js
index c86cde63219..07b29cb9643 100644
--- a/src/extensibility/InstallExtensionDialog.js
+++ b/src/extensibility/InstallExtensionDialog.js
@@ -32,8 +32,6 @@ define(function (require, exports, module) {
File = require("filesystem/File"),
StringUtils = require("utils/StringUtils"),
Strings = require("strings"),
- Commands = require("command/Commands"),
- CommandManager = require("command/CommandManager"),
FileSystem = require("filesystem/FileSystem"),
KeyEvent = require("utils/KeyEvent"),
Package = require("extensibility/Package"),
diff --git a/src/extensibility/node/ExtensionManagerDomain.js b/src/extensibility/node/ExtensionManagerDomain.js
index e2f489e23ee..70d310bbc7a 100644
--- a/src/extensibility/node/ExtensionManagerDomain.js
+++ b/src/extensibility/node/ExtensionManagerDomain.js
@@ -29,9 +29,7 @@ indent: 4, maxerr: 50 */
var semver = require("semver"),
path = require("path"),
- http = require("http"),
request = require("request"),
- os = require("os"),
fs = require("fs-extra"),
temp = require("temp"),
validate = require("./package-validator").validate;
@@ -92,9 +90,7 @@ function _removeFailedInstallation(installDirectory) {
*/
function _performInstall(packagePath, installDirectory, validationResult, callback) {
validationResult.installedTo = installDirectory;
-
- var callbackCalled = false;
-
+
fs.mkdirs(installDirectory, function (err) {
if (err) {
callback(err);
diff --git a/src/extensibility/node/package-validator.js b/src/extensibility/node/package-validator.js
index 9bdf4a5434f..a44d172e0da 100644
--- a/src/extensibility/node/package-validator.js
+++ b/src/extensibility/node/package-validator.js
@@ -30,9 +30,6 @@ indent: 4, maxerr: 50, regexp: true */
var DecompressZip = require("decompress-zip"),
semver = require("semver"),
path = require("path"),
- http = require("http"),
- request = require("request"),
- os = require("os"),
temp = require("temp"),
fs = require("fs-extra");
@@ -269,10 +266,6 @@ function validatePackageJSON(path, packageJSON, options, callback) {
* @param {function(Error, {errors: Array, metadata: Object, commonPrefix: string, extractDir: string})} callback function to call with the result
*/
function extractAndValidateFiles(zipPath, extractDir, options, callback) {
- var callbackCalled = false;
- var metadata;
- var foundMainIn = null;
-
var unzipper = new DecompressZip(zipPath);
unzipper.on("error", function (err) {
// General error to report for problems reading the file
diff --git a/src/extensibility/node/spec/Installation.spec.js b/src/extensibility/node/spec/Installation.spec.js
index 68ac59cb575..9d24ba435cf 100644
--- a/src/extensibility/node/spec/Installation.spec.js
+++ b/src/extensibility/node/spec/Installation.spec.js
@@ -147,8 +147,6 @@ describe("Package Installation", function () {
it("should successfully update an extension", function (done) {
ExtensionsDomain._cmdInstall(basicValidExtension, installDirectory, standardOptions, function (err, result) {
- var extensionDirectory = path.join(installDirectory, "basic-valid-extension");
-
expect(err).toBeNull();
ExtensionsDomain._cmdInstall(basicValidExtension2, installDirectory, standardOptions, function (err, result) {
expect(err).toBeNull();
@@ -327,4 +325,4 @@ describe("Package Installation", function () {
done();
});
});
-});
\ No newline at end of file
+});
diff --git a/src/extensions/default/CSSCodeHints/main.js b/src/extensions/default/CSSCodeHints/main.js
index 932f6c067c8..35963692bd0 100644
--- a/src/extensions/default/CSSCodeHints/main.js
+++ b/src/extensions/default/CSSCodeHints/main.js
@@ -22,22 +22,21 @@
*/
/*jslint vars: true, plusplus: true, devel: true, nomen: true, indent: 4, maxerr: 50, regexp: true */
-/*global define, brackets, $, window */
+/*global define, brackets, $ */
define(function (require, exports, module) {
"use strict";
- var _ = brackets.getModule("thirdparty/lodash"),
- AppInit = brackets.getModule("utils/AppInit"),
- ExtensionUtils = brackets.getModule("utils/ExtensionUtils"),
- CodeHintManager = brackets.getModule("editor/CodeHintManager"),
- CSSUtils = brackets.getModule("language/CSSUtils"),
- HTMLUtils = brackets.getModule("language/HTMLUtils"),
- LanguageManager = brackets.getModule("language/LanguageManager"),
- TokenUtils = brackets.getModule("utils/TokenUtils"),
- StringMatch = brackets.getModule("utils/StringMatch"),
- CSSProperties = require("text!CSSProperties.json"),
- properties = JSON.parse(CSSProperties);
+ var AppInit = brackets.getModule("utils/AppInit"),
+ ExtensionUtils = brackets.getModule("utils/ExtensionUtils"),
+ CodeHintManager = brackets.getModule("editor/CodeHintManager"),
+ CSSUtils = brackets.getModule("language/CSSUtils"),
+ HTMLUtils = brackets.getModule("language/HTMLUtils"),
+ LanguageManager = brackets.getModule("language/LanguageManager"),
+ TokenUtils = brackets.getModule("utils/TokenUtils"),
+ StringMatch = brackets.getModule("utils/StringMatch"),
+ CSSProperties = require("text!CSSProperties.json"),
+ properties = JSON.parse(CSSProperties);
// Context of the last request for hints: either CSSUtils.PROP_NAME,
// CSSUtils.PROP_VALUE or null.
@@ -144,8 +143,7 @@ define(function (require, exports, module) {
*/
CssPropHints.prototype.hasHints = function (editor, implicitChar) {
this.editor = editor;
- var cursor = this.editor.getCursorPos(),
- textAfterCursor;
+ var cursor = this.editor.getCursorPos();
lastContext = null;
this.info = CSSUtils.getInfoAtPos(editor, cursor);
diff --git a/src/extensions/default/CSSCodeHints/unittests.js b/src/extensions/default/CSSCodeHints/unittests.js
index 754ec03d039..67da96a8c64 100644
--- a/src/extensions/default/CSSCodeHints/unittests.js
+++ b/src/extensions/default/CSSCodeHints/unittests.js
@@ -28,9 +28,6 @@ define(function (require, exports, module) {
"use strict";
var SpecRunnerUtils = brackets.getModule("spec/SpecRunnerUtils"),
- CodeHintManager = brackets.getModule("editor/CodeHintManager"),
- DocumentManager = brackets.getModule("document/DocumentManager"),
- FileUtils = brackets.getModule("file/FileUtils"),
testContentCSS = require("text!unittest-files/regions.css"),
testContentHTML = require("text!unittest-files/region-template.html"),
CSSCodeHints = require("main");
@@ -481,7 +478,7 @@ define(function (require, exports, module) {
var expectedString = "shape-inside:polygon()";
testEditor.setCursorPos({ line: 1, ch: 15 }); // after shape-inside
- var hintList = expectHints(CSSCodeHints.cssPropHintProvider);
+ expectHints(CSSCodeHints.cssPropHintProvider);
selectHint(CSSCodeHints.cssPropHintProvider, "polygon()");
expect(testDocument.getLine(1).length).toBe(expectedString.length);
expect(testDocument.getLine(1)).toBe(expectedString);
diff --git a/src/extensions/default/CloseOthers/main.js b/src/extensions/default/CloseOthers/main.js
index e7e5a0711cd..37aadfd345c 100644
--- a/src/extensions/default/CloseOthers/main.js
+++ b/src/extensions/default/CloseOthers/main.js
@@ -22,18 +22,18 @@
*/
/*jslint vars: true, plusplus: true, devel: true, nomen: true, regexp: true, indent: 4, maxerr: 50 */
-/*global define, $, brackets, window, document */
+/*global define, $, brackets */
define(function (require, exports, module) {
"use strict";
- var Menus = brackets.getModule("command/Menus"),
- CommandManager = brackets.getModule("command/CommandManager"),
- Commands = brackets.getModule("command/Commands"),
- DocumentManager = brackets.getModule("document/DocumentManager"),
- Strings = brackets.getModule("strings"),
- workingSetCmenu = Menus.getContextMenu(Menus.ContextMenuIds.WORKING_SET_MENU),
- PreferencesManager = brackets.getModule("preferences/PreferencesManager");
+ var Menus = brackets.getModule("command/Menus"),
+ CommandManager = brackets.getModule("command/CommandManager"),
+ Commands = brackets.getModule("command/Commands"),
+ MainViewManager = brackets.getModule("view/MainViewManager"),
+ Strings = brackets.getModule("strings"),
+ PreferencesManager = brackets.getModule("preferences/PreferencesManager"),
+ workingSetListCmenu = Menus.getContextMenu(Menus.ContextMenuIds.WORKING_SET_CONTEXT_MENU);
// Constants
var closeOthers = "file.close_others",
@@ -54,20 +54,17 @@ define(function (require, exports, module) {
* @param {string} mode
*/
function handleClose(mode) {
- var targetIndex = DocumentManager.findInWorkingSet(DocumentManager.getCurrentDocument().file.fullPath),
- workingSet = DocumentManager.getWorkingSet().slice(0),
- start = (mode === closeBelow) ? (targetIndex + 1) : 0,
- end = (mode === closeAbove) ? (targetIndex) : (workingSet.length),
- files = [],
+ var targetIndex = MainViewManager.findInWorkingSet(MainViewManager.ACTIVE_PANE, MainViewManager.getCurrentlyViewedPath(MainViewManager.ACTIVE_PANE)),
+ workingSetList = MainViewManager.getWorkingSet(MainViewManager.ACTIVE_PANE),
+ start = (mode === closeBelow) ? (targetIndex + 1) : 0,
+ end = (mode === closeAbove) ? (targetIndex) : (workingSetList.length),
+ files = [],
i;
-
- if (mode === closeOthers) {
- end--;
- workingSet.splice(targetIndex, 1);
- }
-
+
for (i = start; i < end; i++) {
- files.push(workingSet[i]);
+ if ((mode === closeOthers && i !== targetIndex) || (mode !== closeOthers)) {
+ files.push(workingSetList[i]);
+ }
}
CommandManager.execute(Commands.FILE_CLOSE_LIST, {fileList: files});
@@ -77,25 +74,25 @@ define(function (require, exports, module) {
* Enable/Disable the menu items depending on which document is selected in the working set
*/
function contextMenuOpenHandler() {
- var doc = DocumentManager.getCurrentDocument();
+ var file = MainViewManager.getCurrentlyViewedFile(MainViewManager.ACTIVE_PANE);
- if (doc) {
- var docIndex = DocumentManager.findInWorkingSet(doc.file.fullPath),
- workingSet = DocumentManager.getWorkingSet().slice(0);
+ if (file) {
+ var targetIndex = MainViewManager.findInWorkingSet(MainViewManager.ACTIVE_PANE, file.fullPath),
+ workingSetListSize = MainViewManager.getWorkingSetSize(MainViewManager.ACTIVE_PANE);
- if (docIndex === workingSet.length - 1) { // hide "Close Others Below" if the last file in Working Files is selected
+ if (targetIndex === workingSetListSize - 1) { // hide "Close Others Below" if the last file in Working Files is selected
CommandManager.get(closeBelow).setEnabled(false);
} else {
CommandManager.get(closeBelow).setEnabled(true);
}
- if (workingSet.length === 1) { // hide "Close Others" if there is only one file in Working Files
+ if (workingSetListSize === 1) { // hide "Close Others" if there is only one file in Working Files
CommandManager.get(closeOthers).setEnabled(false);
} else {
CommandManager.get(closeOthers).setEnabled(true);
}
- if (docIndex === 0) { // hide "Close Others Above" if the first file in Working Files is selected
+ if (targetIndex === 0) { // hide "Close Others Above" if the first file in Working Files is selected
CommandManager.get(closeAbove).setEnabled(false);
} else {
CommandManager.get(closeAbove).setEnabled(true);
@@ -126,25 +123,25 @@ define(function (require, exports, module) {
if (prefs.closeBelow !== menuEntriesShown.closeBelow) {
if (prefs.closeBelow) {
- workingSetCmenu.addMenuItem(closeBelow, "", Menus.AFTER, Commands.FILE_CLOSE);
+ workingSetListCmenu.addMenuItem(closeBelow, "", Menus.AFTER, Commands.FILE_CLOSE);
} else {
- workingSetCmenu.removeMenuItem(closeBelow);
+ workingSetListCmenu.removeMenuItem(closeBelow);
}
}
if (prefs.closeOthers !== menuEntriesShown.closeOthers) {
if (prefs.closeOthers) {
- workingSetCmenu.addMenuItem(closeOthers, "", Menus.AFTER, Commands.FILE_CLOSE);
+ workingSetListCmenu.addMenuItem(closeOthers, "", Menus.AFTER, Commands.FILE_CLOSE);
} else {
- workingSetCmenu.removeMenuItem(closeOthers);
+ workingSetListCmenu.removeMenuItem(closeOthers);
}
}
if (prefs.closeAbove !== menuEntriesShown.closeAbove) {
if (prefs.closeAbove) {
- workingSetCmenu.addMenuItem(closeAbove, "", Menus.AFTER, Commands.FILE_CLOSE);
+ workingSetListCmenu.addMenuItem(closeAbove, "", Menus.AFTER, Commands.FILE_CLOSE);
} else {
- workingSetCmenu.removeMenuItem(closeAbove);
+ workingSetListCmenu.removeMenuItem(closeAbove);
}
}
@@ -168,13 +165,13 @@ define(function (require, exports, module) {
});
if (prefs.closeBelow) {
- workingSetCmenu.addMenuItem(closeBelow, "", Menus.AFTER, Commands.FILE_CLOSE);
+ workingSetListCmenu.addMenuItem(closeBelow, "", Menus.AFTER, Commands.FILE_CLOSE);
}
if (prefs.closeOthers) {
- workingSetCmenu.addMenuItem(closeOthers, "", Menus.AFTER, Commands.FILE_CLOSE);
+ workingSetListCmenu.addMenuItem(closeOthers, "", Menus.AFTER, Commands.FILE_CLOSE);
}
if (prefs.closeAbove) {
- workingSetCmenu.addMenuItem(closeAbove, "", Menus.AFTER, Commands.FILE_CLOSE);
+ workingSetListCmenu.addMenuItem(closeAbove, "", Menus.AFTER, Commands.FILE_CLOSE);
}
menuEntriesShown = prefs;
}
@@ -184,7 +181,7 @@ define(function (require, exports, module) {
initializeCommands();
// Add a context menu open handler
- $(workingSetCmenu).on("beforeContextMenuOpen", contextMenuOpenHandler);
+ $(workingSetListCmenu).on("beforeContextMenuOpen", contextMenuOpenHandler);
prefs.on("change", prefChangeHandler);
});
diff --git a/src/extensions/default/CloseOthers/unittests.js b/src/extensions/default/CloseOthers/unittests.js
index 99754ba2c19..b5022464280 100644
--- a/src/extensions/default/CloseOthers/unittests.js
+++ b/src/extensions/default/CloseOthers/unittests.js
@@ -34,6 +34,7 @@ define(function (require, exports, module) {
Dialogs,
EditorManager,
DocumentManager,
+ MainViewManager,
FileSystem;
describe("CloseOthers", function () {
@@ -86,6 +87,7 @@ define(function (require, exports, module) {
$ = testWindow.$;
brackets = testWindow.brackets;
DocumentManager = testWindow.brackets.test.DocumentManager;
+ MainViewManager = testWindow.brackets.test.MainViewManager;
CommandManager = testWindow.brackets.test.CommandManager;
EditorManager = testWindow.brackets.test.EditorManager;
Dialogs = testWindow.brackets.test.Dialogs;
@@ -127,16 +129,21 @@ define(function (require, exports, module) {
function runCloseOthers() {
- var ws = DocumentManager.getWorkingSet(),
+ var ws = MainViewManager.getWorkingSet(MainViewManager.ACTIVE_PANE),
promise;
if (ws.length > docSelectIndex) {
DocumentManager.getDocumentForPath(ws[docSelectIndex].fullPath).done(function (doc) {
- DocumentManager.setCurrentDocument(doc);
+ MainViewManager._edit(MainViewManager.ACTIVE_PANE, doc);
});
- promise = CommandManager.execute(cmdToRun);
- waitsForDone(promise, cmdToRun);
+ runs(function () {
+ promise = CommandManager.execute(cmdToRun);
+ waitsForDone(promise, cmdToRun);
+ });
+ runs(function () {
+ expect(MainViewManager.getCurrentlyViewedPath(MainViewManager.ACTIVE_PANE)).toEqual(ws[docSelectIndex].fullPath, "Path of document in editor after close others command should be the document that was selected");
+ });
}
}
@@ -144,10 +151,10 @@ define(function (require, exports, module) {
docSelectIndex = 2;
cmdToRun = "file.close_others";
- runs(runCloseOthers);
+ runCloseOthers();
runs(function () {
- expect(DocumentManager.getWorkingSet().length).toEqual(1);
+ expect(MainViewManager.getWorkingSet(MainViewManager.ACTIVE_PANE).length).toEqual(1);
});
});
@@ -155,10 +162,10 @@ define(function (require, exports, module) {
docSelectIndex = 2;
cmdToRun = "file.close_above";
- runs(runCloseOthers);
+ runCloseOthers();
runs(function () {
- expect(DocumentManager.getWorkingSet().length).toEqual(3);
+ expect(MainViewManager.getWorkingSet(MainViewManager.ACTIVE_PANE).length).toEqual(3);
});
});
@@ -166,10 +173,10 @@ define(function (require, exports, module) {
docSelectIndex = 1;
cmdToRun = "file.close_below";
- runs(runCloseOthers);
+ runCloseOthers();
runs(function () {
- expect(DocumentManager.getWorkingSet().length).toEqual(2);
+ expect(MainViewManager.getWorkingSet(MainViewManager.ACTIVE_PANE).length).toEqual(2);
});
});
});
diff --git a/src/extensions/default/DarkTheme/main.less b/src/extensions/default/DarkTheme/main.less
index a2dc9e168d3..b40225671e1 100644
--- a/src/extensions/default/DarkTheme/main.less
+++ b/src/extensions/default/DarkTheme/main.less
@@ -159,11 +159,11 @@
/* Non-editor styling */
-#image-holder,
-#not-editor {
+.image-view,
+.not-editor {
background-color: @background;
}
-#image-holder {
+.view-pane .image-view {
color: @foreground;
}
diff --git a/src/extensions/default/DebugCommands/ErrorNotification.js b/src/extensions/default/DebugCommands/ErrorNotification.js
index 5af4fafff41..e75fcbc52ba 100644
--- a/src/extensions/default/DebugCommands/ErrorNotification.js
+++ b/src/extensions/default/DebugCommands/ErrorNotification.js
@@ -22,7 +22,7 @@
*/
/*jslint vars: true, plusplus: true, devel: true, nomen: true, regexp: true, indent: 4, maxerr: 50 */
-/*global define, $, brackets, window, document */
+/*global define, $, brackets, window */
define(function (require, exports, module) {
"use strict";
diff --git a/src/extensions/default/DebugCommands/NodeDebugUtils.js b/src/extensions/default/DebugCommands/NodeDebugUtils.js
index c268c0daead..36fbace5957 100644
--- a/src/extensions/default/DebugCommands/NodeDebugUtils.js
+++ b/src/extensions/default/DebugCommands/NodeDebugUtils.js
@@ -22,7 +22,7 @@
*/
/*jslint vars: true, plusplus: true, devel: true, nomen: true, indent: 4, maxerr: 50 */
-/*global define, $, brackets, window */
+/*global define, $, brackets */
define(function (require, exports, module) {
"use strict";
@@ -130,4 +130,4 @@ define(function (require, exports, module) {
exports.restartNode = restartNode;
exports.enableDebugger = enableDebugger;
-});
\ No newline at end of file
+});
diff --git a/src/extensions/default/HTMLCodeHints/main.js b/src/extensions/default/HTMLCodeHints/main.js
index efdc4ea01ea..6641569266c 100644
--- a/src/extensions/default/HTMLCodeHints/main.js
+++ b/src/extensions/default/HTMLCodeHints/main.js
@@ -294,8 +294,7 @@ define(function (require, exports, module) {
var pos = editor.getCursorPos(),
tokenType,
offset,
- query,
- textAfterCursor;
+ query;
this.editor = editor;
this.tagInfo = HTMLUtils.getTagInfo(editor, pos);
@@ -385,8 +384,7 @@ define(function (require, exports, module) {
query = {queryStr: null},
tokenType,
offset,
- result = [],
- textAfterCursor;
+ result = [];
this.tagInfo = HTMLUtils.getTagInfo(this.editor, cursor);
tokenType = this.tagInfo.position.tokenType;
@@ -570,4 +568,4 @@ define(function (require, exports, module) {
exports.tagHintProvider = tagHints;
exports.attrHintProvider = attrHints;
});
-});
\ No newline at end of file
+});
diff --git a/src/extensions/default/HTMLCodeHints/unittests.js b/src/extensions/default/HTMLCodeHints/unittests.js
index 0a0e5cc55a0..39d76ced899 100644
--- a/src/extensions/default/HTMLCodeHints/unittests.js
+++ b/src/extensions/default/HTMLCodeHints/unittests.js
@@ -23,7 +23,7 @@
/*jslint vars: true, plusplus: true, devel: true, browser: true, nomen: true, indent: 4, maxerr: 50 */
-/*global define, describe, it, xit, expect, beforeEach, afterEach, waitsFor, runs, $, brackets, waitsForDone */
+/*global define, describe, it, xit, expect, beforeEach, afterEach, $, brackets */
define(function (require, exports, module) {
"use strict";
@@ -31,7 +31,6 @@ define(function (require, exports, module) {
// Modules from the SpecRunner window
var SpecRunnerUtils = brackets.getModule("spec/SpecRunnerUtils"),
Editor = brackets.getModule("editor/Editor").Editor,
- CodeHintManager = brackets.getModule("editor/CodeHintManager"),
HTMLCodeHints = require("main");
describe("HTML Code Hinting", function () {
@@ -447,7 +446,7 @@ define(function (require, exports, module) {
// Expect no filtering - however, we offer some attributes (including first in the list) that
// are specific to the tag, so we can't use the default "no filtering" empty arg here.
- // (This smart filtering isn't officially part of the sprint, so no unit tests specifically
+ // (This smart filtering isn't officially part of the release, so no unit tests specifically
// targeting that functionality yet).
verifyAttrHints(hintList, "accept");
});
diff --git a/src/extensions/default/HtmlEntityCodeHints/unittests.js b/src/extensions/default/HtmlEntityCodeHints/unittests.js
index 268743ccf4a..13ee46d4545 100644
--- a/src/extensions/default/HtmlEntityCodeHints/unittests.js
+++ b/src/extensions/default/HtmlEntityCodeHints/unittests.js
@@ -23,15 +23,13 @@
/*jslint vars: true, plusplus: true, devel: true, browser: true, nomen: true, indent: 4, maxerr: 50 */
-/*global define, describe, it, xit, expect, beforeEach, afterEach, waitsFor, runs, $, brackets, waitsForDone */
+/*global define, describe, it, expect, beforeEach, afterEach, brackets */
define(function (require, exports, module) {
"use strict";
// Modules from the SpecRunner window
var SpecRunnerUtils = brackets.getModule("spec/SpecRunnerUtils"),
- Editor = brackets.getModule("editor/Editor").Editor,
- CodeHintManager = brackets.getModule("editor/CodeHintManager"),
HTMLEntityHints = require("main").SpecialCharHints,
defaultContent = require("text!unittest-files/default.html");
diff --git a/src/extensions/default/InlineColorEditor/InlineColorEditor.js b/src/extensions/default/InlineColorEditor/InlineColorEditor.js
index 25e8836c392..06fc801a7d7 100644
--- a/src/extensions/default/InlineColorEditor/InlineColorEditor.js
+++ b/src/extensions/default/InlineColorEditor/InlineColorEditor.js
@@ -22,7 +22,7 @@
*/
/*jslint vars: true, plusplus: true, nomen: true, regexp: true, maxerr: 50 */
-/*global define, brackets, $, window */
+/*global define, brackets, $ */
define(function (require, exports, module) {
"use strict";
diff --git a/src/extensions/default/InlineColorEditor/main.js b/src/extensions/default/InlineColorEditor/main.js
index 74fbdd9892b..5b205d9c0b7 100644
--- a/src/extensions/default/InlineColorEditor/main.js
+++ b/src/extensions/default/InlineColorEditor/main.js
@@ -22,13 +22,12 @@
*/
/*jslint vars: true, plusplus: true, nomen: true, regexp: true, maxerr: 50 */
-/*global define, brackets, $, document */
+/*global define, brackets, $ */
define(function (require, exports, module) {
"use strict";
var EditorManager = brackets.getModule("editor/EditorManager"),
- ProjectManager = brackets.getModule("project/ProjectManager"),
ExtensionUtils = brackets.getModule("utils/ExtensionUtils"),
InlineColorEditor = require("InlineColorEditor").InlineColorEditor,
ColorUtils = brackets.getModule("utils/ColorUtils");
@@ -43,8 +42,7 @@ define(function (require, exports, module) {
* @return {?{color:String, start:TextMarker, end:TextMarker}}
*/
function prepareEditorForProvider(hostEditor, pos) {
- var colorPicker, colorRegEx, cursorLine, inlineColorEditor, match, result,
- sel, start, end, startBookmark, endBookmark;
+ var colorRegEx, cursorLine, match, sel, start, end, startBookmark, endBookmark;
sel = hostEditor.getSelection();
if (sel.start.line !== sel.end.line) {
diff --git a/src/extensions/default/InlineColorEditor/unittests.js b/src/extensions/default/InlineColorEditor/unittests.js
index d97dd065dbb..0f5733fb51b 100644
--- a/src/extensions/default/InlineColorEditor/unittests.js
+++ b/src/extensions/default/InlineColorEditor/unittests.js
@@ -23,16 +23,13 @@
/*jslint vars: true, plusplus: true, devel: true, browser: true, nomen: true, indent: 4, maxerr: 50 */
-/*global define, describe, it, expect, beforeEach, afterEach, waits, waitsFor, runs, $, brackets, waitsForDone, spyOn, tinycolor, KeyEvent */
+/*global define, describe, it, expect, beforeEach, afterEach, waits, runs, $, brackets, waitsForDone, spyOn, tinycolor */
define(function (require, exports, module) {
"use strict";
// Modules from the SpecRunner window
var SpecRunnerUtils = brackets.getModule("spec/SpecRunnerUtils"),
- Editor = brackets.getModule("editor/Editor").Editor,
- DocumentManager = brackets.getModule("document/DocumentManager"),
- Strings = brackets.getModule("strings"),
KeyEvent = brackets.getModule("utils/KeyEvent"),
testContentCSS = require("text!unittest-files/unittests.css"),
testContentHTML = require("text!unittest-files/unittests.html"),
diff --git a/src/extensions/default/InlineTimingFunctionEditor/BezierCurveEditor.js b/src/extensions/default/InlineTimingFunctionEditor/BezierCurveEditor.js
index 353424382df..532eaac66a9 100644
--- a/src/extensions/default/InlineTimingFunctionEditor/BezierCurveEditor.js
+++ b/src/extensions/default/InlineTimingFunctionEditor/BezierCurveEditor.js
@@ -27,19 +27,16 @@
define(function (require, exports, module) {
"use strict";
- var EditorManager = brackets.getModule("editor/EditorManager"),
- KeyEvent = brackets.getModule("utils/KeyEvent"),
+ var KeyEvent = brackets.getModule("utils/KeyEvent"),
Strings = brackets.getModule("strings");
- var TimingFunctionUtils = require("TimingFunctionUtils"),
- InlineTimingFunctionEditor = require("InlineTimingFunctionEditor").InlineTimingFunctionEditor;
+ var TimingFunctionUtils = require("TimingFunctionUtils");
/** Mustache template that forms the bare DOM structure of the UI */
- var BezierCurveEditorTemplate = require("text!BezierCurveEditorTemplate.html");
+ var BezierCurveEditorTemplate = require("text!BezierCurveEditorTemplate.html");
/** @const @type {number} */
- var STEP_MULTIPLIER = 5,
- HEIGHT_ABOVE = 75, // extra height above main grid
+ var HEIGHT_ABOVE = 75, // extra height above main grid
HEIGHT_BELOW = 75, // extra height below main grid
HEIGHT_MAIN = 150, // height of main grid
WIDTH_MAIN = 150; // width of main grid
@@ -134,9 +131,7 @@ define(function (require, exports, module) {
offsetsToCoordinates: function (element) {
var p = this.padding,
w = this.canvas.width,
- h = this.canvas.height * 0.5,
- x,
- y;
+ h = this.canvas.height * 0.5;
// Convert padding percentage to actual padding
p = p.map(function (a, i) {
diff --git a/src/extensions/default/InlineTimingFunctionEditor/StepEditor.js b/src/extensions/default/InlineTimingFunctionEditor/StepEditor.js
index 02cb07852be..8a21766223a 100644
--- a/src/extensions/default/InlineTimingFunctionEditor/StepEditor.js
+++ b/src/extensions/default/InlineTimingFunctionEditor/StepEditor.js
@@ -27,23 +27,17 @@
define(function (require, exports, module) {
"use strict";
- var EditorManager = brackets.getModule("editor/EditorManager"),
- KeyEvent = brackets.getModule("utils/KeyEvent"),
- Strings = brackets.getModule("strings");
+ var KeyEvent = brackets.getModule("utils/KeyEvent"),
+ Strings = brackets.getModule("strings");
- var TimingFunctionUtils = require("TimingFunctionUtils"),
- InlineTimingFunctionEditor = require("InlineTimingFunctionEditor").InlineTimingFunctionEditor;
+ var TimingFunctionUtils = require("TimingFunctionUtils");
/** Mustache template that forms the bare DOM structure of the UI */
var StepEditorTemplate = require("text!StepEditorTemplate.html");
/** @const @type {number} */
- var STEP_LINE = 1,
- DASH_LINE = 2,
- HEIGHT_MAIN = 150, // height of main grid
- WIDTH_MAIN = 150; // width of main grid
-
- var animationRequest = null;
+ var STEP_LINE = 1,
+ DASH_LINE = 2;
/**
* StepParameters object constructor
diff --git a/src/extensions/default/InlineTimingFunctionEditor/TimingFunctionUtils.js b/src/extensions/default/InlineTimingFunctionEditor/TimingFunctionUtils.js
index 687239f8309..5a980da2412 100644
--- a/src/extensions/default/InlineTimingFunctionEditor/TimingFunctionUtils.js
+++ b/src/extensions/default/InlineTimingFunctionEditor/TimingFunctionUtils.js
@@ -22,7 +22,7 @@
*/
/*jslint vars: true, plusplus: true, devel: true, nomen: true, regexp: true, indent: 4, maxerr: 50 */
-/*global define, brackets, $ */
+/*global define, brackets */
/**
* Utilities functions related to color matching
@@ -60,15 +60,15 @@ define(function (require, exports, module) {
* If string is a number, then convert it.
*
* @param {string} str value parsed from page.
- * @return { isNumber: boolean, value: number }
+ * @return { isNumber: boolean, value: ?number }
*/
function _convertToNumber(str) {
- if (typeof (str) !== "string") {
- return { isNumber: false };
+ if (typeof str !== "string") {
+ return { isNumber: false, value: null };
}
- var val = parseFloat(str, 10),
- isNum = (typeof (val) === "number") && !isNaN(val) &&
+ var val = parseFloat(+str, 10),
+ isNum = (typeof val === "number") && !isNaN(val) &&
(val !== Infinity) && (val !== -Infinity);
return {
@@ -173,8 +173,7 @@ define(function (require, exports, module) {
def = [ "5", "end" ],
params = def,
oldIndex = match.index, // we need to store the old match.index to re-set the index afterwards
- originalString = match[0],
- i;
+ originalString = match[0];
if (match) {
match = match[1].split(",");
diff --git a/src/extensions/default/InlineTimingFunctionEditor/main.js b/src/extensions/default/InlineTimingFunctionEditor/main.js
index e9cffa1ad09..2ed79471921 100644
--- a/src/extensions/default/InlineTimingFunctionEditor/main.js
+++ b/src/extensions/default/InlineTimingFunctionEditor/main.js
@@ -41,7 +41,7 @@
*/
/*jslint vars: true, plusplus: true, devel: true, nomen: true, regexp: true, indent: 4, maxerr: 50 */
-/*global define, brackets, $, window, Mustache */
+/*global define, brackets, $, Mustache */
define(function (require, exports, module) {
"use strict";
diff --git a/src/extensions/default/InlineTimingFunctionEditor/unittests.js b/src/extensions/default/InlineTimingFunctionEditor/unittests.js
index cc85c37a23b..d24defa52b2 100644
--- a/src/extensions/default/InlineTimingFunctionEditor/unittests.js
+++ b/src/extensions/default/InlineTimingFunctionEditor/unittests.js
@@ -22,7 +22,7 @@
*/
/*jslint vars: true, plusplus: true, devel: true, browser: true, nomen: true, indent: 4, maxerr: 50 */
-/*global define, describe, it, expect, beforeEach, afterEach, waits, waitsFor, runs, $, brackets, waitsForDone, spyOn, KeyEvent */
+/*global define, describe, it, expect, beforeEach, afterEach, runs, $, brackets, waitsForDone */
define(function (require, exports, module) {
"use strict";
@@ -215,6 +215,9 @@ define(function (require, exports, module) {
it("should correct cubic-bezier function with 5 parameters", function () {
testInvalidBezier("cubic-bezier(0, 0, 1, 1, 1)", ["cubic-bezier(0, 0, 1, 1)", "0", "0", "1", "1"]);
});
+ it("should correct cubic-bezier function with trailing comma", function () {
+ testInvalidBezier("cubic-bezier(.42, 0, .58, .5,)", ["cubic-bezier(.42, 0, .58, .5)", ".42", "0", ".58", ".5"]);
+ });
// Real invalid cubic-beziers - they should NOT be corrected automatically
it("should not match cubic-bezier function with invalid whitespace", function () {
diff --git a/src/extensions/default/JSLint/main.js b/src/extensions/default/JSLint/main.js
index e1c5d21b429..cb1e77a96ba 100644
--- a/src/extensions/default/JSLint/main.js
+++ b/src/extensions/default/JSLint/main.js
@@ -22,7 +22,7 @@
*/
-/*global define, $, JSLINT, brackets */
+/*global define, JSLINT, brackets */
/**
* Provides JSLint results via the core linting extension point
diff --git a/src/extensions/default/JSLint/unittests.js b/src/extensions/default/JSLint/unittests.js
index e0197beb8bc..9b8d2a3e3a7 100644
--- a/src/extensions/default/JSLint/unittests.js
+++ b/src/extensions/default/JSLint/unittests.js
@@ -22,7 +22,7 @@
*/
/*jslint vars: true, plusplus: true, devel: true, browser: true, nomen: true, indent: 4, maxerr: 50 */
-/*global define, describe, it, expect, beforeEach, afterEach, waitsFor, runs, brackets, waitsForDone, spyOn */
+/*global define, describe, it, expect, beforeEach, afterEach, runs, brackets, waitsForDone, spyOn */
define(function (require, exports, module) {
"use strict";
diff --git a/src/extensions/default/JavaScriptCodeHints/ParameterHintManager.js b/src/extensions/default/JavaScriptCodeHints/ParameterHintManager.js
index a5b99048b2a..abe8c50c37b 100644
--- a/src/extensions/default/JavaScriptCodeHints/ParameterHintManager.js
+++ b/src/extensions/default/JavaScriptCodeHints/ParameterHintManager.js
@@ -35,15 +35,13 @@ define(function (require, exports, module) {
Menus = brackets.getModule("command/Menus"),
Strings = brackets.getModule("strings"),
HintsUtils2 = require("HintUtils2"),
- ScopeManager = require("ScopeManager"),
- Session = require("Session");
+ ScopeManager = require("ScopeManager");
/** @const {string} Show Function Hint command ID */
var SHOW_PARAMETER_HINT_CMD_ID = "showParameterHint", // string must MATCH string in native code (brackets_extensions)
PUSH_EXISTING_HINT = true,
OVERWRITE_EXISTING_HINT = false,
- PRESERVE_FUNCTION_STACK = true,
hintContainerHTML = require("text!ParameterHintTemplate.html"),
KeyboardPrefs = JSON.parse(require("text!keyboard.json"));
@@ -136,8 +134,7 @@ define(function (require, exports, module) {
* of the function call.
*/
function formatHint(functionInfo) {
- var hints = session.getParameterHint(functionInfo.functionCallPos),
- pendingOptional = false;
+ var hints = session.getParameterHint(functionInfo.functionCallPos);
$hintContent.empty();
$hintContent.addClass("brackets-js-hints");
@@ -440,4 +437,4 @@ define(function (require, exports, module) {
exports.startCursorTracking = startCursorTracking;
exports.stopCursorTracking = stopCursorTracking;
-});
\ No newline at end of file
+});
diff --git a/src/extensions/default/JavaScriptCodeHints/Preferences.js b/src/extensions/default/JavaScriptCodeHints/Preferences.js
index 9605fa9c1f0..75fc119fdc9 100644
--- a/src/extensions/default/JavaScriptCodeHints/Preferences.js
+++ b/src/extensions/default/JavaScriptCodeHints/Preferences.js
@@ -61,7 +61,7 @@
*/
/*jslint vars: true, plusplus: true, devel: true, nomen: true, indent: 4, maxerr: 50, regexp: true */
-/*global define, brackets, $ */
+/*global define, brackets */
define(function (require, exports, module) {
"use strict";
diff --git a/src/extensions/default/JavaScriptCodeHints/ScopeManager.js b/src/extensions/default/JavaScriptCodeHints/ScopeManager.js
index 146f590bf70..80f76d24b59 100644
--- a/src/extensions/default/JavaScriptCodeHints/ScopeManager.js
+++ b/src/extensions/default/JavaScriptCodeHints/ScopeManager.js
@@ -44,7 +44,6 @@ define(function (require, exports, module) {
ExtensionUtils = brackets.getModule("utils/ExtensionUtils"),
FileSystem = brackets.getModule("filesystem/FileSystem"),
FileUtils = brackets.getModule("file/FileUtils"),
- globmatch = brackets.getModule("thirdparty/globmatch"),
LanguageManager = brackets.getModule("language/LanguageManager"),
PreferencesManager = brackets.getModule("preferences/PreferencesManager"),
ProjectManager = brackets.getModule("project/ProjectManager"),
@@ -1137,7 +1136,6 @@ define(function (require, exports, module) {
var file = document.file,
path = file.fullPath,
dir = file.parentPath,
- files = [],
pr;
var addFilesDeferred = $.Deferred();
diff --git a/src/extensions/default/JavaScriptCodeHints/Session.js b/src/extensions/default/JavaScriptCodeHints/Session.js
index a269a93923b..7cb0280114f 100644
--- a/src/extensions/default/JavaScriptCodeHints/Session.js
+++ b/src/extensions/default/JavaScriptCodeHints/Session.js
@@ -30,7 +30,6 @@ define(function (require, exports, module) {
var StringMatch = brackets.getModule("utils/StringMatch"),
LanguageManager = brackets.getModule("language/LanguageManager"),
HTMLUtils = brackets.getModule("language/HTMLUtils"),
- TokenUtils = brackets.getModule("utils/TokenUtils"),
HintUtils = require("HintUtils"),
ScopeManager = require("ScopeManager"),
Acorn = require("thirdparty/acorn/acorn"),
@@ -549,7 +548,7 @@ define(function (require, exports, module) {
*
* @param {Array} hints - array of hints
* @param {StringMatcher} matcher
- * @returns {Array} - array of matching hints.
+ * @return {Array} - array of matching hints.
*/
function filterWithQueryAndMatcher(hints, matcher) {
var matchResults = $.map(hints, function (hint) {
@@ -750,8 +749,6 @@ define(function (require, exports, module) {
// HTML file - need to send back only the bodies of the
//