1
0
mirror of https://github.com/adobe/brackets.git synced 2024-11-20 09:53:00 +01:00

Implement Splitview

This commit is contained in:
Jeff Booher 2014-08-28 22:51:45 -07:00
parent 9083d5280c
commit af55f97b93
120 changed files with 9186 additions and 3284 deletions

View File

@ -40,6 +40,7 @@ define(function GotoAgent(require, exports, module) {
var DocumentManager = require("document/DocumentManager");
var EditorManager = require("editor/EditorManager");
var MainViewManager = require("view/MainViewManager");
/** Return the URL without the query string
* @param {string} URL
@ -172,7 +173,7 @@ define(function GotoAgent(require, exports, module) {
path = decodeURI(path);
var promise = DocumentManager.getDocumentForPath(path);
promise.done(function onDone(doc) {
DocumentManager.setCurrentDocument(doc);
MainViewManager._edit(MainViewManager.ACTIVE_PANE, doc);
if (location) {
openLocation(location, noFlash);
}

View File

@ -155,6 +155,10 @@ define(function HTMLDocumentModule(require, exports, module) {
self._onChange(event, editor, change);
});
$(this.editor).on("beforeDestroy.HTMLDocument", function (event, editor) {
self._onDestroy(event, editor);
});
// Experimental code
if (LiveDevelopment.config.experimental) {
$(HighlightAgent).on("highlight.HTMLDocument", function (event, node) {
@ -266,6 +270,18 @@ define(function HTMLDocumentModule(require, exports, module) {
});
};
/**
* Triggered when the editor is being destroyed
* @param {$.Event} event Event
* @param {!Editor} editor The editor being destroyed
*/
HTMLDocument.prototype._onDestroy = function (event, editor) {
if (this.editor === editor) {
this.detachFromEditor();
}
};
/**
* Triggered on change by the editor
* @param {$.Event} event Event

View File

@ -85,6 +85,7 @@ define(function LiveDevelopment(require, exports, module) {
FileSystemError = require("filesystem/FileSystemError"),
FileUtils = require("file/FileUtils"),
LiveDevServerManager = require("LiveDevelopment/LiveDevServerManager"),
MainViewManager = require("view/MainViewManager"),
NativeApp = require("utils/NativeApp"),
PreferencesDialogs = require("preferences/PreferencesDialogs"),
ProjectManager = require("project/ProjectManager"),
@ -1318,18 +1319,18 @@ define(function LiveDevelopment(require, exports, module) {
}
}
// TODO: need to run _onDocumentChange() after load if doc != currentDocument here? Maybe not, since activeEditorChange
// TODO: need to run _onFileChanged() after load if doc != currentDocument here? Maybe not, since activeEditorChange
// doesn't trigger it, while inline editors can still cause edits in doc other than currentDoc...
_getInitialDocFromCurrent().done(function (doc) {
var prepareServerPromise = (doc && _prepareServer(doc)) || new $.Deferred().reject(),
otherDocumentsInWorkingFiles;
if (doc && !doc._masterEditor) {
otherDocumentsInWorkingFiles = DocumentManager.getWorkingSet().length;
DocumentManager.addToWorkingSet(doc.file);
otherDocumentsInWorkingFiles = MainViewManager.getWorkingSet(MainViewManager.ALL_PANES).length;
MainViewManager.addToWorkingSet(MainViewManager.ACTIVE_PANE, doc.file);
if (!otherDocumentsInWorkingFiles) {
DocumentManager.setCurrentDocument(doc);
MainViewManager._edit(MainViewManager.ACTIVE_PANE, doc);
}
}
@ -1371,9 +1372,9 @@ define(function LiveDevelopment(require, exports, module) {
/**
* @private
* DocumentManager currentDocumentChange event handler.
* MainViewManager.currentFileChange event handler.
*/
function _onDocumentChange() {
function _onFileChanged() {
var doc = _getCurrentDocument();
if (!doc || !Inspector.connected()) {
@ -1472,10 +1473,13 @@ define(function LiveDevelopment(require, exports, module) {
// We may get interim added/removed events when pushing incremental updates
$(CSSAgent).on("styleSheetAdded.livedev", _styleSheetAdded);
$(DocumentManager).on("currentDocumentChange", _onDocumentChange)
$(MainViewManager)
.on("currentFileChange", _onFileChanged);
$(DocumentManager)
.on("documentSaved", _onDocumentSaved)
.on("dirtyFlagChange", _onDirtyFlagChange);
$(ProjectManager).on("beforeProjectClose beforeAppClose", close);
$(ProjectManager)
.on("beforeProjectClose beforeAppClose", close);
// Register user defined server provider
LiveDevServerManager.registerServer({ create: _createUserServer }, 99);

View File

@ -105,6 +105,7 @@ define(function (require, exports, module) {
DeprecationWarning = require("utils/DeprecationWarning"),
ViewCommandHandlers = require("view/ViewCommandHandlers"),
ThemeManager = require("view/ThemeManager"),
MainViewManager = require("view/MainViewManager"),
_ = require("thirdparty/lodash");
// DEPRECATED: In future we want to remove the global CodeMirror, but for now we
@ -139,6 +140,9 @@ define(function (require, exports, module) {
require("file/NativeFileSystem");
require("file/NativeFileError");
// Compatibility shim for PanelManager to WorkspaceManager migration
require("view/PanelManager");
PerfUtils.addMeasurement("brackets module dependencies resolved");
// Local variables
@ -188,6 +192,8 @@ define(function (require, exports, module) {
LanguageManager : LanguageManager,
LiveDevelopment : require("LiveDevelopment/LiveDevelopment"),
LiveDevServerManager : require("LiveDevelopment/LiveDevServerManager"),
MainViewManager : MainViewManager,
MainViewFactory : require("view/MainViewFactory"),
Menus : Menus,
MultiRangeInlineEditor : require("editor/MultiRangeInlineEditor").MultiRangeInlineEditor,
NativeApp : NativeApp,
@ -198,7 +204,6 @@ define(function (require, exports, module) {
ScrollTrackMarkers : require("search/ScrollTrackMarkers"),
UpdateNotification : require("utils/UpdateNotification"),
WorkingSetView : WorkingSetView,
doneLoading : false
};
@ -213,8 +218,6 @@ define(function (require, exports, module) {
function _onReady() {
PerfUtils.addMeasurement("window.document Ready");
EditorManager.setEditorHolder($("#editor-holder"));
// Let the user know Brackets doesn't run in a web browser yet
if (brackets.inBrowser) {
Dialogs.showModalDialog(
@ -248,6 +251,9 @@ define(function (require, exports, module) {
// Load the initial project after extensions have loaded
extensionLoaderPromise.always(function () {
// Signal that extensions are loaded
AppInit._dispatchReady(AppInit.EXTENSIONS_LOADED);
// Finish UI initialization
ViewCommandHandlers.restoreFontSize();
var initialProjectPath = ProjectManager.getInitialProjectPath();
@ -265,7 +271,7 @@ define(function (require, exports, module) {
if (ProjectManager.isWelcomeProjectPath(initialProjectPath)) {
FileSystem.resolve(initialProjectPath + "index.html", function (err, file) {
if (!err) {
var promise = CommandManager.execute(Commands.FILE_ADD_TO_WORKING_SET, { fullPath: file.fullPath });
var promise = CommandManager.execute(Commands.CMD_ADD_TO_WORKINGSET_AND_OPEN, { fullPath: file.fullPath });
promise.then(deferred.resolve, deferred.reject);
} else {
deferred.reject();

View File

@ -30,24 +30,6 @@ define(function (require, exports, module) {
var DeprecationWarning = require("utils/DeprecationWarning");
/**
* @private
* Create a deprecation warning and action for updated Command constants
* @param {!string} oldConstant
* @param {!string} newConstant
*/
function _deprecateCommand(oldConstant, newConstant) {
var warning = "Use Commands." + newConstant + " instead of Commands." + oldConstant,
newValue = exports[newConstant];
Object.defineProperty(exports, oldConstant, {
get: function () {
DeprecationWarning.deprecationWarning(warning, true);
return newValue;
}
});
}
/**
* List of constants for global command IDs.
*/
@ -56,7 +38,7 @@ define(function (require, exports, module) {
exports.FILE_NEW_UNTITLED = "file.newDoc"; // DocumentCommandHandlers.js handleFileNew()
exports.FILE_NEW = "file.newFile"; // DocumentCommandHandlers.js handleFileNewInProject()
exports.FILE_NEW_FOLDER = "file.newFolder"; // DocumentCommandHandlers.js handleNewFolderInProject()
exports.FILE_OPEN = "file.open"; // DocumentCommandHandlers.js handleFileOpen()
exports.FILE_OPEN = "file.open"; // DocumentCommandHandlers.js handleDocumentOpen()
exports.FILE_OPEN_FOLDER = "file.openFolder"; // ProjectManager.js openProject()
exports.FILE_SAVE = "file.save"; // DocumentCommandHandlers.js handleFileSave()
exports.FILE_SAVE_ALL = "file.saveAll"; // DocumentCommandHandlers.js handleFileSaveAll()
@ -64,7 +46,6 @@ define(function (require, exports, module) {
exports.FILE_CLOSE = "file.close"; // DocumentCommandHandlers.js handleFileClose()
exports.FILE_CLOSE_ALL = "file.close_all"; // DocumentCommandHandlers.js handleFileCloseAll()
exports.FILE_CLOSE_LIST = "file.close_list"; // DocumentCommandHandlers.js handleFileCloseList()
exports.FILE_ADD_TO_WORKING_SET = "file.addToWorkingSet"; // DocumentCommandHandlers.js handleFileAddToWorkingSet()
exports.FILE_OPEN_DROPPED_FILES = "file.openDroppedFiles"; // DragAndDrop.js openDroppedFiles()
exports.FILE_LIVE_FILE_PREVIEW = "file.liveFilePreview"; // LiveDevelopment/main.js _handleGoLiveCommand()
exports.CMD_RELOAD_LIVE_PREVIEW = "file.reloadLivePreview"; // LiveDevelopment/main.js _handleReloadLivePreviewCommand()
@ -133,10 +114,15 @@ define(function (require, exports, module) {
exports.TOGGLE_LINE_NUMBERS = "view.toggleLineNumbers"; // EditorOptionHandlers.js _getToggler()
exports.TOGGLE_ACTIVE_LINE = "view.toggleActiveLine"; // EditorOptionHandlers.js _getToggler()
exports.TOGGLE_WORD_WRAP = "view.toggleWordWrap"; // EditorOptionHandlers.js _getToggler()
exports.SORT_WORKINGSET_BY_ADDED = "view.sortWorkingSetByAdded"; // WorkingSetSort.js _handleSortWorkingSetByAdded()
exports.SORT_WORKINGSET_BY_NAME = "view.sortWorkingSetByName"; // WorkingSetSort.js _handleSortWorkingSetByName()
exports.SORT_WORKINGSET_BY_TYPE = "view.sortWorkingSetByType"; // WorkingSetSort.js _handleSortWorkingSetByType()
exports.SORT_WORKINGSET_AUTO = "view.sortWorkingSetAuto"; // WorkingSetSort.js _handleAutomaticSort()
exports.CMD_ADD_TO_WORKINGSET_AND_OPEN = "cmd.addToWorkingSetAndOpen"; // DocumentCommandHandlers.js handleOpenDocumentInNewPane()
exports.CMD_OPEN = "cmd.open";
exports.CMD_ADD_TO_WORKINGSET_AND_OPEN = "cmd.addToWorkingSetAndOpen"; // DocumentCommandHandlers.js handleOpenDocumentInNewPane()
exports.CMD_WORKINGSET_SORT_BY_ADDED = "cmd.sortWorkingSetByAdded"; // WorkingSetSort.js _handleSort()
exports.CMD_WORKINGSET_SORT_BY_NAME = "cmd.sortWorkingSetByName"; // WorkingSetSort.js _handleSort()
exports.CMD_WORKINGSET_SORT_BY_TYPE = "cmd.sortWorkingSetByType"; // WorkingSetSort.js _handleSort()
exports.CMD_WORKING_SORT_TOGGLE_AUTO = "cmd.sortWorkingSetToggleAuto"; // WorkingSetSort.js _handleToggleAutoSort()
// NAVIGATE
exports.NAVIGATE_NEXT_DOC = "navigate.nextDoc"; // DocumentCommandHandlers.js handleGoNextDoc()
@ -176,15 +162,24 @@ define(function (require, exports, module) {
exports.APP_ABORT_QUIT = "app.abort_quit"; // DocumentCommandHandlers.js handleAbortQuit()
exports.APP_BEFORE_MENUPOPUP = "app.before_menupopup"; // DocumentCommandHandlers.js handleBeforeMenuPopup()
// ADD_TO_WORKING_SET is deprectated but we need a handler for it because the new command doesn't return the same result as the legacy command
exports.FILE_ADD_TO_WORKING_SET = "file.addToWorkingSet"; // Deprecated through DocumentCommandHandlers.js handleFileAddToWorkingSet
// DEPRECATED: Working Set Commands
DeprecationWarning.deprecateConstant(exports, "SORT_WORKINGSET_BY_ADDED", "CMD_WORKINGSET_SORT_BY_ADDED");
DeprecationWarning.deprecateConstant(exports, "SORT_WORKINGSET_BY_NAME", "CMD_WORKINGSET_SORT_BY_NAME");
DeprecationWarning.deprecateConstant(exports, "SORT_WORKINGSET_BY_TYPE", "CMD_WORKINGSET_SORT_BY_TYPE");
DeprecationWarning.deprecateConstant(exports, "SORT_WORKINGSET_AUTO", "CMD_WORKING_SORT_TOGGLE_AUTO");
// DEPRECATED: Edit commands that were moved from the Edit Menu to the Find Menu
_deprecateCommand("EDIT_FIND", "CMD_FIND");
_deprecateCommand("EDIT_FIND_IN_SELECTED", "CMD_FIND_IN_SELECTED");
_deprecateCommand("EDIT_FIND_IN_SUBTREE", "CMD_FIND_IN_SUBTREE");
_deprecateCommand("EDIT_FIND_NEXT", "CMD_FIND_NEXT");
_deprecateCommand("EDIT_FIND_PREVIOUS", "CMD_FIND_PREVIOUS");
_deprecateCommand("EDIT_FIND_ALL_AND_SELECT", "CMD_FIND_ALL_AND_SELECT");
_deprecateCommand("EDIT_ADD_NEXT_MATCH", "CMD_ADD_NEXT_MATCH");
_deprecateCommand("EDIT_SKIP_CURRENT_MATCH", "CMD_SKIP_CURRENT_MATCH");
_deprecateCommand("EDIT_REPLACE", "CMD_REPLACE");
DeprecationWarning.deprecateConstant(exports, "EDIT_FIND", "CMD_FIND");
DeprecationWarning.deprecateConstant(exports, "EDIT_FIND_IN_SELECTED", "CMD_FIND_IN_SELECTED");
DeprecationWarning.deprecateConstant(exports, "EDIT_FIND_IN_SUBTREE", "CMD_FIND_IN_SUBTREE");
DeprecationWarning.deprecateConstant(exports, "EDIT_FIND_NEXT", "CMD_FIND_NEXT");
DeprecationWarning.deprecateConstant(exports, "EDIT_FIND_PREVIOUS", "CMD_FIND_PREVIOUS");
DeprecationWarning.deprecateConstant(exports, "EDIT_FIND_ALL_AND_SELECT", "CMD_FIND_ALL_AND_SELECT");
DeprecationWarning.deprecateConstant(exports, "EDIT_ADD_NEXT_MATCH", "CMD_ADD_NEXT_MATCH");
DeprecationWarning.deprecateConstant(exports, "EDIT_SKIP_CURRENT_MATCH", "CMD_SKIP_CURRENT_MATCH");
DeprecationWarning.deprecateConstant(exports, "EDIT_REPLACE", "CMD_REPLACE");
});

View File

@ -205,6 +205,36 @@ define(function (require, exports, module) {
menu.addMenuItem(Commands.HELP_ABOUT);
}
/*
* WorkingSet context and gear menus
* NOTE: Unlike most context menus defined here, these menus cannot
* be setup to listen to click or context menu events when
* this module intializes because the DOM nodes for these are
* created by pane views which are created at runtime.
* All other context menus have DOM elements to attach to
* out of index.html
*/
var workingset_cmenu = Menus.registerContextMenu(Menus.ContextMenuIds.WORKING_SET_CONTEXT_MENU);
workingset_cmenu.addMenuItem(Commands.FILE_SAVE);
workingset_cmenu.addMenuItem(Commands.FILE_SAVE_AS);
workingset_cmenu.addMenuItem(Commands.FILE_RENAME);
workingset_cmenu.addMenuItem(Commands.NAVIGATE_SHOW_IN_FILE_TREE);
workingset_cmenu.addMenuItem(Commands.NAVIGATE_SHOW_IN_OS);
workingset_cmenu.addMenuDivider();
workingset_cmenu.addMenuItem(Commands.CMD_FIND_IN_SUBTREE);
workingset_cmenu.addMenuItem(Commands.CMD_REPLACE_IN_SUBTREE);
workingset_cmenu.addMenuDivider();
workingset_cmenu.addMenuItem(Commands.FILE_CLOSE);
var workingset_configuration_menu = Menus.registerContextMenu(Menus.ContextMenuIds.WORKING_SET_CONFIG_MENU);
workingset_configuration_menu.addMenuItem(Commands.CMD_WORKINGSET_SORT_BY_ADDED);
workingset_configuration_menu.addMenuItem(Commands.CMD_WORKINGSET_SORT_BY_NAME);
workingset_configuration_menu.addMenuItem(Commands.CMD_WORKINGSET_SORT_BY_TYPE);
workingset_configuration_menu.addMenuDivider();
workingset_configuration_menu.addMenuItem(Commands.CMD_WORKING_SORT_TOGGLE_AUTO);
/*
* Context Menus
*/
@ -220,26 +250,6 @@ define(function (require, exports, module) {
project_cmenu.addMenuDivider();
project_cmenu.addMenuItem(Commands.FILE_REFRESH);
var working_set_cmenu = Menus.registerContextMenu(Menus.ContextMenuIds.WORKING_SET_MENU);
working_set_cmenu.addMenuItem(Commands.FILE_SAVE);
working_set_cmenu.addMenuItem(Commands.FILE_SAVE_AS);
working_set_cmenu.addMenuItem(Commands.FILE_RENAME);
working_set_cmenu.addMenuItem(Commands.NAVIGATE_SHOW_IN_FILE_TREE);
working_set_cmenu.addMenuItem(Commands.NAVIGATE_SHOW_IN_OS);
working_set_cmenu.addMenuDivider();
working_set_cmenu.addMenuItem(Commands.CMD_FIND_IN_SUBTREE);
working_set_cmenu.addMenuItem(Commands.CMD_REPLACE_IN_SUBTREE);
working_set_cmenu.addMenuDivider();
working_set_cmenu.addMenuItem(Commands.FILE_CLOSE);
var working_set_settings_cmenu = Menus.registerContextMenu(Menus.ContextMenuIds.WORKING_SET_SETTINGS_MENU);
working_set_settings_cmenu.addMenuItem(Commands.SORT_WORKINGSET_BY_ADDED);
working_set_settings_cmenu.addMenuItem(Commands.SORT_WORKINGSET_BY_NAME);
working_set_settings_cmenu.addMenuItem(Commands.SORT_WORKINGSET_BY_TYPE);
working_set_settings_cmenu.addMenuDivider();
working_set_settings_cmenu.addMenuItem(Commands.SORT_WORKINGSET_AUTO);
var editor_cmenu = Menus.registerContextMenu(Menus.ContextMenuIds.EDITOR_MENU);
// editor_cmenu.addMenuItem(Commands.NAVIGATE_JUMPTO_DEFINITION);
editor_cmenu.addMenuItem(Commands.TOGGLE_QUICK_EDIT);
@ -294,20 +304,12 @@ define(function (require, exports, module) {
});
/**
* Context menus for folder tree & working set list
* Context menu for folder tree
*/
$("#project-files-container").on("contextmenu", function (e) {
project_cmenu.open(e);
});
$("#open-files-container").on("contextmenu", function (e) {
working_set_cmenu.open(e);
});
/**
* Dropdown menu for workspace sorting
*/
Menus.ContextMenu.assignContextMenuToSelector("#working-set-option-btn", working_set_settings_cmenu);
// Prevent the browser context menu since Brackets creates a custom context menu
$(window).contextmenu(function (e) {

View File

@ -61,11 +61,10 @@ define(function (require, exports, module) {
EDITOR_MENU: "editor-context-menu",
INLINE_EDITOR_MENU: "inline-editor-context-menu",
PROJECT_MENU: "project-context-menu",
WORKING_SET_MENU: "working-set-context-menu",
WORKING_SET_SETTINGS_MENU: "working-set-settings-context-menu"
WORKING_SET_CONTEXT_MENU: "workingset-context-menu",
WORKING_SET_CONFIG_MENU: "workingset-configuration-menu"
};
/**
* Brackets Application Menu Section Constants
* It is preferred that plug-ins specify the location of new MenuItems
@ -1176,6 +1175,10 @@ define(function (require, exports, module) {
return cmenu;
}
// Deprecated menu ids
DeprecationWarning.deprecateConstant(ContextMenuIds, "WORKING_SET_MENU", "WORKING_SET_CONTEXT_MENU");
DeprecationWarning.deprecateConstant(ContextMenuIds, "WORKING_SET_SETTINGS_MENU", "WORKING_SET_CONFIG_MENU");
// Define public API
exports.AppMenuBar = AppMenuBar;
exports.ContextMenuIds = ContextMenuIds;

View File

@ -227,7 +227,7 @@ define(function (require, exports, module) {
*/
Document.prototype._ensureMasterEditor = function () {
if (!this._masterEditor) {
EditorManager._createFullEditorForDocument(this);
EditorManager._createUnattachedMasterEditor(this);
}
};

View File

@ -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"),
@ -56,7 +58,8 @@ define(function (require, exports, module) {
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.)
@ -127,9 +130,13 @@ define(function (require, exports, module) {
*/
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 +168,7 @@ define(function (require, exports, module) {
var newToolbarHeight = _$titleContainerToolbar.height();
if (_lastToolbarHeight !== newToolbarHeight) {
_lastToolbarHeight = newToolbarHeight;
EditorManager.resizeEditor();
WorkspaceManager.recomputeLayout();
}
}
@ -184,7 +191,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 +207,36 @@ define(function (require, exports, module) {
}
}
function updateDocumentTitle() {
var newDocument = DocumentManager.getCurrentDocument();
/**
* Handles currentFileChange and filenameChanged events and updates the titlebar
*/
function handleCurrentFileChange() {
var newFile = MainViewManager.getCurrentlyViewedFile(MainViewManager.ACTIVE_PANE);
// 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));
if (newFile) {
var newDocument = DocumentManager.getOpenDocumentForPath(newFile.fullPath);
if (newDocument) {
_currentTitlePath = _shortTitleForDocument(newDocument);
} else {
var currentlyViewedFilePath = EditorManager.getCurrentlyViewedPath();
if (currentlyViewedFilePath) {
_currentTitlePath = ProjectManager.makeProjectRelativeIfPossible(currentlyViewedFilePath);
_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,37 +245,29 @@ 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 resolved with a file for the specified file path or
* - be rejected 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();
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();
}
@ -283,7 +282,7 @@ define(function (require, exports, module) {
}
if (!fullPath) {
console.error("doOpen() called without fullPath");
console.error("_doOpen() called without fullPath");
result.reject();
} else {
var perfTimerName = PerfUtils.markStart("Open File:\t" + fullPath);
@ -291,31 +290,16 @@ define(function (require, exports, module) {
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);
}
});
} 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);
MainViewManager._open(paneId, file)
.done(function () {
result.resolve(file);
})
.fail(function (fileError) {
_showErrorAndCleanUp(fileError, fullPath);
result.reject();
});
}
}
return result.promise();
}
@ -328,16 +312,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,7 +335,7 @@ 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);
@ -358,16 +343,14 @@ define(function (require, exports, module) {
filteredPaths.forEach(function (file) {
filesToOpen.push(FileSystem.getFileForPath(file));
});
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(filteredPaths[filteredPaths.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 +361,7 @@ define(function (require, exports, module) {
}
});
} else {
result = doOpen(fullPath, silent);
result = _doOpen(fullPath, silent, paneId);
}
return result.promise();
@ -410,28 +393,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,20 +455,81 @@ 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 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) {
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);
}
// 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();
}
/**
@ -507,6 +577,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 +591,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 +617,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 +628,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();
}
@ -692,7 +763,7 @@ define(function (require, exports, module) {
result.resolve(file);
}
result.always(function () {
EditorManager.focusEditor();
MainViewManager.focusActivePane();
});
return result.promise();
}
@ -700,6 +771,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 +779,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 +835,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 +879,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 +908,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 +1009,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 +1025,7 @@ define(function (require, exports, module) {
* @return {$.Promise}
*/
function saveAll() {
return _saveFileList(DocumentManager.getWorkingSet());
return _saveFileList(MainViewManager.getWorkingSet(MainViewManager.ALL_PANES));
}
/**
@ -986,7 +1064,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 +1080,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 +1171,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.<FileEntry>} list
* @param {boolean} promptOnly
* @param {boolean} clearCurrentDoc
* @param {!Array.<File>} 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 +1270,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 +1278,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 +1289,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,6 +1318,9 @@ 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) {
@ -1313,7 +1368,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 +1390,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 +1425,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 +1433,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 +1450,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 +1499,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) {
@ -1523,16 +1588,27 @@ define(function (require, exports, module) {
});
}
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 (loadWithoutExtensions) {
if (!params.get("reloadWithoutUserExts")) {
params.put("reloadWithoutUserExts", true);
}
} else {
if (params.get("reloadWithoutUserExts")) {
params.remove("reloadWithoutUserExts");
}
}
if (href.indexOf("?") !== -1) {
href = href.substring(0, href.indexOf("?"));
@ -1549,29 +1625,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,9 +1665,15 @@ 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);
// Deprecated commands
CommandManager.register(Strings.CMD_ADD_TO_WORKINGSET_AND_OPEN, Commands.FILE_ADD_TO_WORKING_SET, handleFileAddToWorkingSet);
CommandManager.register(Strings.CMD_FILE_OPEN, Commands.FILE_OPEN, handleDocumentOpen);
// New commands
CommandManager.register(Strings.CMD_FILE_OPEN, Commands.CMD_OPEN, handleFileOpen);
CommandManager.register(Strings.CMD_ADD_TO_WORKINGSET_AND_OPEN, Commands.CMD_ADD_TO_WORKINGSET_AND_OPEN, handleFileAddToWorkingSetAndOpen);
// 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);
@ -1619,15 +1683,19 @@ define(function (require, exports, module) {
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);
CommandManager.register(quitString, Commands.FILE_QUIT, handleFileQuit);
// Traversal
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);
// 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 +1706,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; });

File diff suppressed because it is too large Load Diff

View File

@ -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.
@ -194,7 +196,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 +209,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 +235,7 @@ define(function (require, exports, module) {
this._inlineWidgets = [];
this._inlineWidgetQueues = {};
this._hideMarks = [];
this._lastEditorWidth = null;
this._$messagePopover = null;
@ -263,6 +273,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, {
@ -328,6 +345,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 +360,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 +514,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:
@ -887,6 +912,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.
* @param {boolean} expandTabs If true, return the actual visual column number instead of the character offset in
@ -896,7 +930,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 +1031,7 @@ define(function (require, exports, module) {
this._codeMirror.setSize(width, height);
};
/** @const */
var CENTERING_MARGIN = 0.15;
/**
@ -1365,6 +1400,7 @@ define(function (require, exports, module) {
return this._codeMirror.getWrapperElement();
};
/**
* Gets the lineSpace element within the editor (the container around the individual lines of code).
* FUTURE: This is fairly CodeMirror-specific. Logic that depends on this may break if we switch
@ -1384,6 +1420,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 +1535,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
@ -1585,6 +1628,22 @@ define(function (require, exports, module) {
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
* cursor if space allows, otherwise below.
@ -1595,7 +1654,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 +1725,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 +1879,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 +1951,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 +1967,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 +1998,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 +2024,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 +2066,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());
};
@ -1983,6 +2089,16 @@ define(function (require, exports, module) {
*/
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
* events caused by us (vs. change events caused by others, which we need to pay attention to).
@ -2089,6 +2205,38 @@ define(function (require, exports, module) {
}
};
/**
* 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 +2393,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

File diff suppressed because it is too large Load Diff

View File

@ -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.hide();
} else {
var fullPath = current.document.file.fullPath;
StatusBar.show(); // calls resizeEditor() if needed
StatusBar.show();
$(current).on("cursorActivity.statusbar", _updateCursorInfo);
$(current).on("optionChange.statusbar", function () {

View File

@ -28,62 +28,258 @@ 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
var _viewers = {};
/**
* 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 _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 ImageView(file, $container) {
this.file = file;
this.$el = $(Mustache.render(ImageViewTemplate, {fullPath: file.fullPath}));
function _hideGuidesAndTip() {
$("#img-tip").hide();
$(".img-guide").hide();
}
$container.append(this.$el);
/** handle editor resize event, i.e. update scale sticker */
function _onEditorAreaResize() {
_hideGuidesAndTip();
_updateScale($("#img-preview").width());
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;
}
/**
* Update file name if necessary
* 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 _onFileNameChange(e, oldName, newName) {
var oldRelPath = ProjectManager.makeProjectRelativeIfPossible(oldName),
currentPath = $("#img-path").text();
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);
}
};
if (currentPath === oldRelPath) {
var newRelName = ProjectManager.makeProjectRelativeIfPossible(newName);
$("#img-path").text(newRelName)
.attr("title", newRelName);
/**
* <img>.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;
var extension = FileUtils.getFileExtension(this.file.fullPath);
var dimensionString = this._naturalWidth + " &times; " + this._naturalHeight + " " + Strings.UNIT_PIXELS;
if (extension === "ico") {
dimensionString += " (" + Strings.IMAGE_VIEWER_LARGEST_ICON + ")";
}
// 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 = " &mdash; " + StringUtils.prettyPrintBytes(stat.size, 2);
}
var dimensionAndSize = dimensionString + sizeString;
self.$imageData.html(dimensionAndSize)
.attr("title", dimensionAndSize
.replace("&times;", "x")
.replace("&mdash;", "-"));
}
});
// 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();
};
/**
* Update the scale element
* @private
*/
ImageView.prototype._updateScale = function () {
var currentWidth = this.$imagePreview.width();
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 {Event} e - event
* @private
*/
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(this._scale) === 0) {
return;
}
var x = Math.round(e.offsetX * 100 / this._scale),
y = Math.round(e.offsetY * 100 / this._scale),
$target = $(e.target),
imagePos = this.$imagePreview.position(),
left = e.offsetX + imagePos.left,
top = e.offsetY + imagePos.top,
width = this.$imagePreview.width(),
height = this.$imagePreview.height(),
windowWidth = $(window).width(),
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
tipOffsetY = -54, // adjustment for info div top from y coordinate of cursor
tipMinusOffsetX1 = -82, // for less than 4-digit image width
tipMinusOffsetX2 = -90; // for 4-digit image width
// Check whether we're getting mousemove events beyond the image boundaries due to a browser bug
// 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 >= this._naturalWidth || y < 0 || y >= this._naturalHeight) {
this._hideImageTip(e);
this.$imagePreview.css("cursor", "auto");
return;
}
this.$imagePreview.css("cursor", "none");
this._handleMouseEnterOrExitScaleSticker(left, top);
// Check whether to show the image tip on the left.
if ((e.pageX + infoWidth1) > windowWidth ||
(fourDigitImageWidth && (e.pageX + infoWidth2) > windowWidth)) {
tipOffsetX = fourDigitImageWidth ? tipMinusOffsetX2 : tipMinusOffsetX1;
}
this.$x_value.text(x + "px");
this.$y_value.text(y + "px");
this.$imageTip.css({
left: left + tipOffsetX,
top: top + tipOffsetY
}).show();
this.$horzGuide.css({
left: imagePos.left,
top: top,
width: width - 1
}).show();
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();
}
}
};
/**
* Hides both guides and the tip
* @private
*/
ImageView.prototype._hideGuidesAndTip = function () {
this.$imageTip.hide();
this.$imageGuides.hide();
};
/**
* Check mouse entering/exiting the scale sticker.
@ -91,22 +287,23 @@ define(function (require, exports, module) {
*
* @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 _handleMouseEnterOrExitScaleSticker(offsetX, offsetY) {
var imagePos = $("#img-preview").position(),
scaleDivPos = $("#img-scale").position(),
imgWidth = $("#img-preview").width(),
imgHeight = $("#img-preview").height(),
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;
if (_scaleDivInfo) {
scaleDivLeft = _scaleDivInfo.left;
scaleDivTop = _scaleDivInfo.top;
scaleDivRight = _scaleDivInfo.right;
scaleDivBottom = _scaleDivInfo.bottom;
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;
@ -119,17 +316,17 @@ define(function (require, exports, module) {
} else {
scaleDivLeft = scaleDivPos.left;
scaleDivTop = scaleDivPos.top;
scaleDivRight = $("#img-scale").width() + scaleDivLeft;
scaleDivBottom = $("#img-scale").height() + scaleDivTop;
scaleDivRight = this.$imageScale.width() + scaleDivLeft;
scaleDivBottom = this.$imageScale.height() + scaleDivTop;
}
if (_scaleDivInfo) {
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)) {
_scaleDivInfo = null;
$("#img-scale").show();
this._scaleDivInfo = null;
this.$imageScale.show();
}
} else if ((offsetX >= scaleDivLeft && offsetX <= scaleDivRight) &&
(offsetY >= scaleDivTop && offsetY <= scaleDivBottom)) {
@ -138,189 +335,143 @@ define(function (require, exports, module) {
if (offsetX < (imagePos.left + imgWidth) &&
offsetY < (imagePos.top + imgHeight)) {
// Remember image scale div coordinates before hiding it.
_scaleDivInfo = {left: scaleDivPos.left,
this._scaleDivInfo = {left: scaleDivPos.left,
top: scaleDivPos.top,
right: scaleDivRight,
bottom: scaleDivBottom};
$("#img-scale").hide();
}
this.$imageScale.hide();
}
}
};
/**
* Hide image coordinates info tip
*
* @param {MouseEvent} e mouse leave event
* View Interface functions
*/
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;
// 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();
}
}
}
/**
* Show image coordinates under the mouse cursor
*
* @param {MouseEvent} e mouse move event
/*
* Retrieves the file object for this view
* return {!File} the file object for this view
*/
function _showImageTip(e) {
// Don't show image tip if _scale is close to zero.
// since we won't have enough room to show tip anyway.
if (Math.floor(_scale) === 0) {
return;
}
ImageView.prototype.getFile = function () {
return this.file;
};
var x = Math.round(e.offsetX * 100 / _scale),
y = Math.round(e.offsetY * 100 / _scale),
$target = $(e.target),
imagePos = $("#img-preview").position(),
left = e.offsetX + imagePos.left,
top = e.offsetY + imagePos.top,
width = $("#img-preview").width(),
height = $("#img-preview").height(),
windowWidth = $(window).width(),
fourDigitImageWidth = _naturalWidth.toString().length === 4,
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
tipOffsetY = -54, // adjustment for info div top from y coordinate of cursor
tipMinusOffsetX1 = -82, // for less than 4-digit image width
tipMinusOffsetX2 = -90; // for 4-digit image width
// Check whether we're getting mousemove events beyond the image boundaries due to a browser bug
// 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");
return;
}
$("#img-preview").css("cursor", "none");
_handleMouseEnterOrExitScaleSticker(left, top);
// Check whether to show the image tip on the left.
if ((e.pageX + infoWidth1) > windowWidth ||
(fourDigitImageWidth && (e.pageX + infoWidth2) > windowWidth)) {
tipOffsetX = fourDigitImageWidth ? tipMinusOffsetX2 : tipMinusOffsetX1;
}
$("#x-value").text(x + "px");
$("#y-value").text(y + "px");
$("#img-tip").css({
left: left + tipOffsetX,
top: top + tipOffsetY
}).show();
$("#horiz-guide").css({
left: imagePos.left,
top: top,
width: width - 1
}).show();
$("#vert-guide").css({
left: left,
top: imagePos.top,
height: height - 1
}).show();
}
/**
* sign off listeners when editor manager closes
* the image viewer
/*
* Updates the layout of the view
*/
function onRemove() {
$(PanelManager).off("editorAreaResize", _onEditorAreaResize);
$(DocumentManager).off("fileNameChange", _onFileNameChange);
$("#img").off("mousemove", "#img-preview", _showImageTip)
.off("mouseleave", "#img-preview", _hideImageTip);
}
ImageView.prototype.updateLayout = function () {
this._hideGuidesAndTip();
/**
* 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.
var $container = this.$el.parent();
var pos = $container.position(),
iWidth = $container.innerWidth(),
iHeight = $container.innerHeight(),
oWidth = $container.outerWidth(),
oHeight = $container.outerHeight();
// $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
*/
function render(fullPath, $editorHolder) {
var relPath = ProjectManager.makeProjectRelativeIfPossible(fullPath),
$customViewer = $(Mustache.render(ImageHolderTemplate, {fullPath: fullPath}));
ImageView.prototype.destroy = function () {
delete _viewers[this.file.fullPath];
$(DocumentManager).off("fileNameChange", _.bind(this._onFilenameChange, this));
this.$image.off(".ImageView");
this.$el.remove();
};
// place DOM node to hold image
$editorHolder.append($customViewer);
/*
* Refreshes the image preview with what's on disk
*/
ImageView.prototype.refresh = function () {
var noCacheUrl = this.$imagePreview.attr("src"),
now = new Date().valueOf();
_scale = 100; // initialize to 100
_scaleDivInfo = null;
$("#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 + " &times; " + this.naturalHeight + " " + Strings.UNIT_PIXELS;
if (ext === "ico") {
dimensionString += " (" + Strings.IMAGE_VIEWER_LARGEST_ICON + ")";
}
// get image size
var file = FileSystem.getFileForPath(fullPath);
file.stat(function (err, stat) {
if (err) {
$("#img-data").html(dimensionString);
// Append a #<time-stamp> fragement to the URL
// to force a reload of the image
if (noCacheUrl.indexOf("#") > 0) {
noCacheUrl = noCacheUrl.replace(/#\d+/, "#" + now);
} else {
var sizeString = "";
if (stat.size) {
sizeString = " &mdash; " + StringUtils.prettyPrintBytes(stat.size, 2);
}
var dimensionAndSize = dimensionString + sizeString;
$("#img-data").html(dimensionAndSize)
.attr("title", dimensionAndSize
.replace("&times;", "x")
.replace("&mdash;", "-"));
}
});
$("#image-holder").show();
// listen to resize to update the scale sticker
$(PanelManager).on("editorAreaResize", _onEditorAreaResize);
// make sure we always show the right file name
$(DocumentManager).on("fileNameChange", _onFileNameChange);
$("#img-tip").hide();
$(".img-guide").hide();
$("#img").on("mousemove", "#img-preview", _showImageTip)
.on("mouseleave", "#img-preview", _hideImageTip);
_updateScale($(this).width());
});
return $customViewer;
noCacheUrl = noCacheUrl + "#" + now;
}
EditorManager.registerCustomViewer("image", {
render: render,
onRemove: onRemove
// 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.$el);
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.<FileSystemEntry>=} added If entry is a Directory, contains zero or more added children
* @param {Array.<FileSystemEntry>=} 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];
// viewer found, call its refresh method
if (viewer) {
viewer.refresh();
}
}
/*
* 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;
});

View File

@ -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

View File

@ -31,8 +31,9 @@ define(function (require, exports, module) {
CommandManager = brackets.getModule("command/CommandManager"),
Commands = brackets.getModule("command/Commands"),
DocumentManager = brackets.getModule("document/DocumentManager"),
MainViewManager = brackets.getModule("view/MainViewManager"),
Strings = brackets.getModule("strings"),
workingSetCmenu = Menus.getContextMenu(Menus.ContextMenuIds.WORKING_SET_MENU),
workingSetListCmenu = Menus.getContextMenu(Menus.ContextMenuIds.WORKING_SET_CONTEXT_MENU),
PreferencesManager = brackets.getModule("preferences/PreferencesManager");
// Constants
@ -54,20 +55,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),
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) : (workingSet.length),
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 +75,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 +124,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 +166,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 +182,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);
});

View File

@ -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);
});
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);
});
});
});

View File

@ -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;
}

View File

@ -549,7 +549,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) {

View File

@ -29,6 +29,7 @@ define(function (require, exports, module) {
var Commands = brackets.getModule("command/Commands"),
CommandManager = brackets.getModule("command/CommandManager"),
MainViewManager = brackets.getModule("view/MainViewManager"),
DocumentManager = brackets.getModule("document/DocumentManager"),
Editor = brackets.getModule("editor/Editor").Editor,
EditorManager = brackets.getModule("editor/EditorManager"),
@ -54,7 +55,7 @@ define(function (require, exports, module) {
CommandManager.register("test-file-open", Commands.FILE_OPEN, function (fileInfo) {
// Register a command for FILE_OPEN, which the jump to def code will call
return DocumentManager.getDocumentForPath(fileInfo.fullPath).done(function (doc) {
DocumentManager.setCurrentDocument(doc);
MainViewManager._edit(MainViewManager.ACTIVE_PANE, doc);
});
});
@ -440,7 +441,7 @@ define(function (require, exports, module) {
// The following call ensures that the document is reloaded
// from disk before each test
DocumentManager.closeAll();
MainViewManager._closeAll(MainViewManager.ALL_PANES);
SpecRunnerUtils.destroyMockEditor(testDoc);
testEditor = null;
testDoc = null;

View File

@ -74,12 +74,12 @@ define(function (require, exports, module) {
* @param {!number} openOffset The offset index location within openFile to open an inline editor.
* @param {?boolean} expectInline Use false to verify that an inline editor should not be opened. Omit otherwise.
*/
var _initInlineTest = function (openFile, openOffset, expectInline, workingSet) {
var _initInlineTest = function (openFile, openOffset, expectInline, filesToOpen) {
var allFiles,
inlineOpened = null,
spec = this;
workingSet = workingSet || [];
filesToOpen = filesToOpen || [];
expectInline = (expectInline !== undefined) ? expectInline : true;
runs(function () {
@ -89,8 +89,8 @@ define(function (require, exports, module) {
SpecRunnerUtils.loadProjectInTestWindow(tempPath);
runs(function () {
workingSet.push(openFile);
waitsForDone(SpecRunnerUtils.openProjectFiles(workingSet), "openProjectFiles");
filesToOpen.push(openFile);
waitsForDone(SpecRunnerUtils.openProjectFiles(filesToOpen), "openProjectFiles");
});
if (openOffset !== undefined) {

View File

@ -54,7 +54,7 @@ define(function (require, exports, module) {
/**
* @param {string} query what the user is searching for
* @returns {Array.<SearchResult>} sorted and filtered results that match the query
* @return {Array.<SearchResult>} sorted and filtered results that match the query
*/
function search(query, matcher) {
var selectorList = matcher.selectorList;

View File

@ -87,7 +87,7 @@ define(function (require, exports, module) {
/**
* @param {string} query what the user is searching for
* @returns {Array.<SearchResult>} sorted and filtered results that match the query
* @return {Array.<SearchResult>} sorted and filtered results that match the query
*/
function search(query, matcher) {
var idList = matcher.idList;

View File

@ -80,7 +80,7 @@ define(function (require, exports, module) {
/**
* @param {string} query what the user is searching for
* @param {StringMatch.StringMatcher} matcher object that caches search-in-progress data
* @returns {Array.<SearchResult>} sorted and filtered results that match the query
* @return {Array.<SearchResult>} sorted and filtered results that match the query
*/
function search(query, matcher) {
var functionList = matcher.functionList;

View File

@ -36,6 +36,7 @@ define(function (require, exports, module) {
KeyBindingManager = brackets.getModule("command/KeyBindingManager"),
Menus = brackets.getModule("command/Menus"),
EditorManager = brackets.getModule("editor/EditorManager"),
MainViewManager = brackets.getModule("view/MainViewManager"),
ExtensionUtils = brackets.getModule("utils/ExtensionUtils"),
FileSystem = brackets.getModule("filesystem/FileSystem"),
AppInit = brackets.getModule("utils/AppInit"),
@ -268,7 +269,8 @@ define(function (require, exports, module) {
$("#titlebar .nav").off("click", closeDropdown);
$dropdown = null;
EditorManager.focusEditor();
MainViewManager.focusActivePane();
$(window).off("keydown", keydownHook);
}

View File

@ -29,9 +29,8 @@ define(function (require, exports, module) {
"use strict";
// Modules from the SpecRunner window
var DocumentManager = brackets.getModule("document/DocumentManager"),
Editor = brackets.getModule("editor/Editor").Editor,
EditorManager = brackets.getModule("editor/EditorManager"),
var MasterDocumentManager = brackets.getModule("document/DocumentManager"),
MasterMainViewManager = brackets.getModule("view/MainViewManager"),
FileUtils = brackets.getModule("file/FileUtils"),
SpecRunnerUtils = brackets.getModule("spec/SpecRunnerUtils"),
UrlCodeHints = require("main");
@ -68,7 +67,7 @@ define(function (require, exports, module) {
function setupTests(testFilePath) {
runs(function () {
DocumentManager.getDocumentForPath(testFilePath).done(function (doc) {
MasterDocumentManager.getDocumentForPath(testFilePath).done(function (doc) {
testDocument = doc;
});
});
@ -80,7 +79,7 @@ define(function (require, exports, module) {
// create Editor instance (containing a CodeMirror instance)
runs(function () {
testEditor = createMockEditor(testDocument);
DocumentManager.setCurrentDocument(testDocument);
MasterMainViewManager._edit(MasterMainViewManager.ACTIVE_PANE, testDocument);
});
}
@ -88,8 +87,7 @@ define(function (require, exports, module) {
runs(function () {
// The following call ensures that the document is reloaded
// from disk before each test
DocumentManager.closeAll();
MasterMainViewManager._closeAll(MasterMainViewManager.ALL_PANES);
SpecRunnerUtils.destroyMockEditor(testDocument);
testEditor = null;
testDocument = null;
@ -302,6 +300,7 @@ define(function (require, exports, module) {
CommandManager,
Commands,
DocumentManager,
MainViewManager,
EditorManager;
it("should hint site root '/'", function () {
@ -314,6 +313,7 @@ define(function (require, exports, module) {
Commands = brackets.test.Commands;
DocumentManager = brackets.test.DocumentManager;
EditorManager = brackets.test.EditorManager;
MainViewManager = brackets.test.MainViewManager;
});
});
@ -337,7 +337,7 @@ define(function (require, exports, module) {
}, "Unable to open test document", 2000);
runs(function () {
DocumentManager.setCurrentDocument(testDocument);
MainViewManager._edit(MainViewManager.ACTIVE_PANE, testDocument);
testEditor = EditorManager.getCurrentFullEditor();
testEditor.setCursorPos({ line: 22, ch: 12 });
CommandManager.execute(Commands.SHOW_CODE_HINTS);
@ -361,6 +361,7 @@ define(function (require, exports, module) {
Commands = null;
DocumentManager = null;
EditorManager = null;
MainViewManager = null;
SpecRunnerUtils.closeTestWindow();
});
});

View File

@ -0,0 +1,12 @@
<div class="brackets-config-central">
<div class="config-options">
<label>
<p>Default file Extension When Creating New Files:</p>
<input type="text" value="{{defaultExtension}}">
</label>
<label>
<p>Number of space units for tabs</p>
<input type="text" value="{{spaceUnits}}">
</label>
</div>
</div>

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@ -0,0 +1,120 @@
/*
* Copyright (c) 2012 Adobe Systems Incorporated. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
/*jslint vars: true, plusplus: true, devel: true, nomen: true, regexp: true, indent: 4, maxerr: 50 */
/*global define, brackets, window, $, Mustache, navigator */
define(function (require, exports, module) {
"use strict";
// Brackets modules
var FileUtils = brackets.getModule("file/FileUtils"),
ExtensionUtils = brackets.getModule("utils/ExtensionUtils"),
DocumentManager = brackets.getModule("document/DocumentManager"),
MainViewFactory = brackets.getModule("view/MainViewFactory"),
ConfigViewContent = require("text!htmlContent/Config.html");
/* our module object */
var _module = module;
/* @type {Object.<string, ConfigView>} List of open views */
function ConfigView(doc, $container) {
this.$container = $container;
this.doc = doc;
this.json = JSON.parse(this.doc.getText());
this.$view = $(Mustache.render(ConfigViewContent, this.json));
this.$view.css({
"background-image": "url(file://" + FileUtils.getNativeModuleDirectoryPath(_module) + "/htmlContent/logo-sm.png)",
"background-position": "bottom right",
"background-repeat": "no-repeat"
});
$container.append(this.$view);
}
/*
* Retrieves the file object for this view
* return {!File} the file object for this view
*/
ConfigView.prototype.getFile = function () {
return this.doc.file;
};
/*
* Updates the layout of the view
*/
ConfigView.prototype.updateLayout = function () {
};
/*
* Destroys the view
*/
ConfigView.prototype.destroy = function () {
this.$view.remove();
};
/*
* Creates a view of a file (.brackets.json)
* @param {!File} file - the file to create a view for
* @param {!Pane} pane - the pane where to create the view
* @private
*/
function _createConfigViewOf(file, pane) {
var result = new $.Deferred(),
view = pane.findViewOfFile(file.fullPath);
if (view) {
// existing view, then just show it
pane.showView(view);
result.resolve(view.getFile());
} else {
DocumentManager.getDocumentForPath(file.fullPath)
.done(function (doc) {
var view = new ConfigView(doc, pane.$el);
pane.addView(view, true);
result.resolve(doc.file);
})
.fail(function (fileError) {
result.reject(fileError);
});
}
return result.promise();
}
/*
* Create a view factory that can create views for the file
* `.brackets.json` in a project's root folder.
*/
var configViewFactory = {
canOpenFile: function (fullPath) {
var filename = fullPath.substr(fullPath.lastIndexOf("/") + 1);
return (filename.toLowerCase() === ".brackets.json");
},
openFile: function (file, pane) {
return _createConfigViewOf(file, pane);
}
};
/* load styles used by our template */
ExtensionUtils.loadStyleSheet(module, "styles/styles.css");
MainViewFactory.registerViewFactory(configViewFactory);
});

View File

@ -0,0 +1,12 @@
{
"name": "JeffryBooher.BracketsConfigCentral",
"title": "Brackets Config Central",
"description": "A simple view factory provider",
"homepage": "https://github.com/JeffryBooher",
"version": "0.0.1",
"author": "@JeffryBooher",
"license": "MIT",
"engines": {
"brackets": ">=0.44.0"
}
}

View File

@ -0,0 +1,15 @@
.brackets-config-central
{
background-color: bisque;
}
.brackets-config-central input[type="text"]
{
width: 1em;
}
.brackets-config-central .config-options
{
margin: 2em;
}

View File

@ -164,6 +164,8 @@ define(function (require, exports, module) {
result = Strings.CONTENTS_MODIFIED_ERR;
} else if (name === FileSystemError.UNSUPPORTED_ENCODING) {
result = Strings.UNSUPPORTED_ENCODING_ERR;
} else if (name === FileSystemError.UNSUPPORTED_FILETYPE) {
result = Strings.UNSUPPORTED_FILE_TYPE_ERR;
} else {
result = StringUtils.format(Strings.GENERIC_ERROR, name);
}

View File

@ -34,6 +34,10 @@
define(function (require, exports, module) {
"use strict";
/**
* Enumerated File System Errors
* @enum {string}
*/
module.exports = {
UNKNOWN : "Unknown",
INVALID_PARAMS : "InvalidParams",
@ -46,7 +50,8 @@ define(function (require, exports, module) {
TOO_MANY_ENTRIES : "TooManyEntries",
ALREADY_EXISTS : "AlreadyExists",
CONTENTS_MODIFIED : "ContentsModified",
ROOT_NOT_WATCHED : "RootNotBeingWatched"
ROOT_NOT_WATCHED : "RootNotBeingWatched",
UNSUPPORTED_FILETYPE : "UnsupportedFileType"
// FUTURE: Add remote connection errors: timeout, not logged in, connection err, etc.
};

View File

@ -1,26 +0,0 @@
<div id="image-holder">
<div id="img-centering">
<div id="img-header">
<div id="img-data"></div>
<div id="img-path"></div>
</div>
<div id="img">
<div id="img-scale"></div>
<img id="img-preview" src="file:///{{fullPath}}">
<div id="img-tip">
<table class="tip-container">
<tr>
<td class="variable">x: </td>
<td id="x-value"></td>
</tr>
<tr>
<td class="variable">y: </td>
<td id="y-value"></td>
</tr>
</table>
</div>
<div id="horiz-guide" class="img-guide"></div>
<div id="vert-guide" class="img-guide"></div>
</div>
</div>
</div>

View File

@ -0,0 +1,26 @@
<div class="image-view">
<div class="image-centering">
<div class="image-header">
<div class="image-data"></div>
<div class="image-path"></div>
</div>
<div class="image">
<div class="image-scale"></div>
<img class="image-preview" src="file:///{{fullPath}}">
<div class="image-tip">
<table class="tip-container">
<tr>
<td class="variable">x: </td>
<td class="x-value"></td>
</tr>
<tr>
<td class="variable">y: </td>
<td class="y-value"></td>
</tr>
</table>
</div>
<div class="horz-guide image-guide"></div>
<div class="vert-guide image-guide"></div>
</div>
</div>
</div>

View File

@ -41,15 +41,9 @@
<!-- Main UI: horizontal set of sidebar, main content vertical stack, and vertical toolbar -->
<div class="main-view">
<div id="sidebar" class="sidebar panel quiet-scrollbars horz-resizable right-resizer collapsible" data-minsize="0" data-forceleft=".content">
<div id="working-set-header">{{WORKING_FILES}}
<div id="working-set-option-btn" class="btn-alt-quiet"></div>
</div>
<div id="open-files-container">
<!-- This will contain runtime-generated <li>'s for each file in the working set -->
<ul>
</ul>
</div>
<div id="working-set-list-container">
</div>
<div id="project-files-header">
<span id="project-title" class="title"></span>
</div>
@ -63,8 +57,8 @@
(status bar is injected later - see StatusBar.init()).
Note: all children must be in a vertical stack with heights explicitly set in a fixed
unit such as px (not percent/em/auto). If you change the height later, you must
call EditorManager.resizeEditor() each time. Otherwise editor-holder's height will
not get set correctly. Use PanelManager to have this managed for you automatically.
call WorkspaceManager.recomputeLayout() each time. Otherwise the layout will
not get set correctly. Use WorkspaceManager to have this managed for you automatically.
-->
<div class="content">
<!-- Horizontal titlebar containing menus & filename when inBrowser -->
@ -79,10 +73,8 @@
</div>
</div>
<!-- Editors are programmatically created inside here -->
<div id="editor-holder">
<div id="not-editor">
</div>
<!-- View Panes are programatically created here -->
</div>
<!-- Bottom panels and status bar are programmatically created here -->
@ -112,3 +104,4 @@
<div id="codehint-menu-bar">
<ul data-dropdown="dropdown"></ul>
</div>
<div id="hidden-editors"></div>

View File

@ -0,0 +1,3 @@
<div id="{{id}}" class="view-pane">
<div class="not-editor"></div>
</div>

View File

@ -0,0 +1,10 @@
<div id="{{id}}">
<div class="working-set-header"><span class="working-set-header-title">{{WORKING_FILES}}</span>
<div class="working-set-option-btn btn-alt-quiet"></div>
</div>
<div class="open-files-container">
<!-- This will contain runtime-generated <li>'s for each file in the working set -->
<ul>
</ul>
</div>
<div>

View File

@ -43,10 +43,11 @@ define(function (require, exports, module) {
// Load dependent modules
var Commands = require("command/Commands"),
PanelManager = require("view/PanelManager"),
WorkspaceManager = require("view/WorkspaceManager"),
CommandManager = require("command/CommandManager"),
DocumentManager = require("document/DocumentManager"),
EditorManager = require("editor/EditorManager"),
MainViewManager = require("view/MainViewManager"),
FileUtils = require("file/FileUtils"),
LanguageManager = require("language/LanguageManager"),
PreferencesManager = require("preferences/PreferencesManager"),
@ -474,8 +475,12 @@ define(function (require, exports, module) {
function updateListeners() {
if (_enabled) {
// register our event listeners
$(MainViewManager)
.on("currentFileChange.codeInspection", function () {
run();
});
$(DocumentManager)
.on("currentDocumentChange.codeInspection currentDocumentLanguageChanged.codeInspection", function () {
.on("currentDocumentLanguageChanged.codeInspection", function () {
run();
})
.on("documentSaved.codeInspection documentRefreshed.codeInspection", function (event, document) {
@ -485,6 +490,7 @@ define(function (require, exports, module) {
});
} else {
$(DocumentManager).off(".codeInspection");
$(MainViewManager).off(".codeInspection");
}
}
@ -577,7 +583,7 @@ define(function (require, exports, module) {
AppInit.htmlReady(function () {
// Create bottom panel to list error details
var panelHtml = Mustache.render(PanelTemplate, Strings);
var resultsPanel = PanelManager.createBottomPanel("errors", $(panelHtml), 100);
var resultsPanel = WorkspaceManager.createBottomPanel("errors", $(panelHtml), 100);
$problemsPanel = $("#problems-panel");
var $selectedRow;
@ -608,7 +614,7 @@ define(function (require, exports, module) {
var editor = EditorManager.getCurrentFullEditor();
editor.setCursorPos(line, character, true);
EditorManager.focusEditor();
MainViewManager.focusActivePane();
}
}
});

View File

@ -38,6 +38,7 @@ define({
"NO_MODIFICATION_ALLOWED_ERR_FILE" : "The permissions do not allow you to make modifications.",
"CONTENTS_MODIFIED_ERR" : "The file has been modified outside of {APP_NAME}.",
"UNSUPPORTED_ENCODING_ERR" : "{APP_NAME} currently only supports UTF-8 encoded text files.",
"UNSUPPORTED_FILE_TYPE_ERR" : "The file is not a supported file type.",
"FILE_EXISTS_ERR" : "The file or directory already exists.",
"FILE" : "file",
"FILE_TITLE" : "File",
@ -220,6 +221,14 @@ define({
"UNTITLED" : "Untitled",
"WORKING_FILES" : "Working Files",
/**
* MainViewManager
*/
"TOP" : "Top",
"BOTTOM" : "Bottom",
"LEFT" : "Left",
"RIGHT" : "Right",
/**
* Keyboard modifier names
*/
@ -276,7 +285,7 @@ define({
"CMD_FILE_NEW" : "New File",
"CMD_FILE_NEW_FOLDER" : "New Folder",
"CMD_FILE_OPEN" : "Open\u2026",
"CMD_ADD_TO_WORKING_SET" : "Add To Working Set",
"CMD_ADD_TO_WORKINGSET_AND_OPEN" : "Add To Working Set and Open",
"CMD_OPEN_DROPPED_FILES" : "Open Dropped Files",
"CMD_OPEN_FOLDER" : "Open Folder\u2026",
"CMD_FILE_CLOSE" : "Close",
@ -355,10 +364,10 @@ define({
"CMD_TOGGLE_WORD_WRAP" : "Word Wrap",
"CMD_LIVE_HIGHLIGHT" : "Live Preview Highlight",
"CMD_VIEW_TOGGLE_INSPECTION" : "Lint Files on Save",
"CMD_SORT_WORKINGSET_BY_ADDED" : "Sort by Added",
"CMD_SORT_WORKINGSET_BY_NAME" : "Sort by Name",
"CMD_SORT_WORKINGSET_BY_TYPE" : "Sort by Type",
"CMD_SORT_WORKINGSET_AUTO" : "Automatic Sort",
"CMD_WORKINGSET_SORT_BY_ADDED" : "Sort by Added",
"CMD_WORKINGSET_SORT_BY_NAME" : "Sort by Name",
"CMD_WORKINGSET_SORT_BY_TYPE" : "Sort by Type",
"CMD_WORKING_SORT_TOGGLE_AUTO" : "Automatic Sort",
"CMD_THEMES" : "Themes\u2026",
// Navigate menu Commands

View File

@ -45,6 +45,7 @@ define(function (require, exports, module) {
// Load dependent modules
var ProjectManager = require("project/ProjectManager"),
DocumentManager = require("document/DocumentManager"),
MainViewManager = require("view/MainViewManager"),
EditorManager = require("editor/EditorManager"),
Commands = require("command/Commands"),
CommandManager = require("command/CommandManager"),
@ -181,7 +182,7 @@ define(function (require, exports, module) {
*/
function syncUnopenWorkingSet() {
// We only care about working set entries that have never been open (have no Document).
var unopenWorkingSetFiles = DocumentManager.getWorkingSet().filter(function (wsFile) {
var unopenWorkingSetFiles = MainViewManager.getWorkingSet(MainViewManager.ALL_PANES).filter(function (wsFile) {
return !DocumentManager.getOpenDocumentForPath(wsFile.fullPath);
});
@ -471,7 +472,7 @@ define(function (require, exports, module) {
// If we showed a dialog, restore focus to editor
if (editConflicts.length > 0 || deleteConflicts.length > 0) {
EditorManager.focusEditor();
MainViewManager.focusActivePane();
}
// (Any errors that ocurred during presentConflicts() have already

View File

@ -50,13 +50,15 @@ define(function (require, exports, module) {
// Load dependent modules
var DocumentManager = require("document/DocumentManager"),
MainViewManager = require("view/MainViewManager"),
CommandManager = require("command/CommandManager"),
EditorManager = require("editor/EditorManager"),
PerfUtils = require("utils/PerfUtils"),
Commands = require("command/Commands");
Commands = require("command/Commands"),
DeprecationWarning = require("utils/DeprecationWarning");
/**
* Tracks whether a "currentDocumentChange" notification occured due to a call to
* Tracks whether a "currentFileChange" notification occured due to a call to
* openAndSelectDocument.
* @see FileviewController.openAndSelectDocument
* @private
@ -74,7 +76,7 @@ define(function (require, exports, module) {
/**
* Change the doc selection to the working set when ever a new file is added to the working set
*/
$(DocumentManager).on("workingSetAdd", function (event, addedFile) {
$(MainViewManager).on("workingSetAdd", function (event, addedFile) {
_fileSelectionFocus = WORKING_SET_VIEW;
$(exports).triggerHandler("documentSelectionFocusChange");
});
@ -82,13 +84,12 @@ define(function (require, exports, module) {
/**
* Update the file selection focus whenever the contents of the editor area change
*/
$(EditorManager).on("currentlyViewedFileChange", function (event) {
$(MainViewManager).on("currentFileChange", function (event, file, paneId) {
var perfTimerName;
// The the cause of the doc change was not openAndSelectDocument, so pick the best fileSelectionFocus
if (!_curDocChangedDueToMe) {
var curDoc = DocumentManager.getCurrentDocument();
perfTimerName = PerfUtils.markStart("FileViewController._onCurrentDocumentChange():\t" + (!curDoc || curDoc.file.fullPath));
if (curDoc && DocumentManager.findInWorkingSet(curDoc.file.fullPath) !== -1) {
// The the cause of the doc change was not openAndSelectDocument, so pick the best fileSelectionFocus
perfTimerName = PerfUtils.markStart("FileViewController._oncurrentFileChange():\t" + (file ? (file.fullPath) : "(no open file)"));
if (file && MainViewManager.findInWorkingSet(paneId, file.fullPath) !== -1) {
_fileSelectionFocus = WORKING_SET_VIEW;
} else {
_fileSelectionFocus = PROJECT_MANAGER;
@ -104,16 +105,18 @@ define(function (require, exports, module) {
/**
* @private
* @return {$.Promise}
* @param {string=} paneId - the Pane to activate
*/
function _selectCurrentDocument() {
function _activatePane(paneId) {
if (paneId) {
MainViewManager.setActivePaneId(paneId);
} else {
MainViewManager.focusActivePane();
}
// If fullPath corresonds to the current doc being viewed then opening the file won't
// trigger a currentDocumentChanged event, so we need to trigger a documentSelectionFocusChange
// trigger a currentFileChange event, so we need to trigger a documentSelectionFocusChange
// in this case to signify the selection focus has changed even though the current document has not.
$(exports).triggerHandler("documentSelectionFocusChange");
// Ensure the editor has focus even though we didn't open a new file.
EditorManager.focusEditor();
}
/**
@ -134,11 +137,12 @@ define(function (require, exports, module) {
/**
* Opens a document if it's not open and selects the file in the UI corresponding to
* fileSelectionFocus
* @param {!fullPath}
* @param {string} - must be either WORKING_SET_VIEW or PROJECT_MANAGER
* @param {!fullPath} fullPath - full path of the document to open
* @param {string} fileSelectionFocus - (WORKING_SET_VIEW || PROJECT_MANAGER)
* @param {string} paneId - pane in which to open the document
* @return {$.Promise}
*/
function openAndSelectDocument(fullPath, fileSelectionFocus) {
function openAndSelectDocument(fullPath, fileSelectionFocus, paneId) {
var result;
if (fileSelectionFocus !== PROJECT_MANAGER && fileSelectionFocus !== WORKING_SET_VIEW) {
@ -148,21 +152,23 @@ define(function (require, exports, module) {
// Opening files are asynchronous and we want to know when this function caused a file
// to open so that _fileSelectionFocus is set appropriatly. _curDocChangedDueToMe is set here
// and checked in the currentDocumentChange handler
// and checked in the currentFileChange handler
_curDocChangedDueToMe = true;
_fileSelectionFocus = fileSelectionFocus;
paneId = (paneId || MainViewManager.ACTIVE_PANE);
// If fullPath corresonds to the current doc being viewed then opening the file won't
// trigger a currentDocumentChanged event, so we need to trigger a documentSelectionFocusChange
// trigger a currentFileChange event, so we need to trigger a documentSelectionFocusChange
// in this case to signify the selection focus has changed even though the current document has not.
var curDoc = DocumentManager.getCurrentDocument();
if (curDoc && curDoc.file.fullPath === fullPath &&
!EditorManager.getCustomViewerForPath(fullPath)) {
_selectCurrentDocument();
var currentPath = MainViewManager.getCurrentlyViewedPath(paneId);
if (currentPath === fullPath) {
_activatePane(paneId);
result = (new $.Deferred()).resolve().promise();
} else {
result = CommandManager.execute(Commands.FILE_OPEN, {fullPath: fullPath});
result = CommandManager.execute(Commands.FILE_OPEN, {fullPath: fullPath,
paneId: paneId});
}
// clear after notification is done
@ -177,30 +183,24 @@ define(function (require, exports, module) {
* Opens the specified document if it's not already open, adds it to the working set,
* and selects it in the WorkingSetView
* @param {!fullPath}
* @param {?String} selectIn - specify either WORING_SET_VIEW or PROJECT_MANAGER.
* Default is WORING_SET_VIEW.
* @param {number=} index - insert into the working set list at this 0-based index
* @param {string=} paneId - Pane in which to add the view. If omitted, the command default is to use the ACTIVE_PANE
* @return {!$.Promise}
*/
function addToWorkingSetAndSelect(fullPath, selectIn, index) {
function openFileAndAddToWorkingSet(fullPath, paneId) {
var result = new $.Deferred(),
promise = CommandManager.execute(Commands.FILE_ADD_TO_WORKING_SET, {fullPath: fullPath, index: index});
promise = CommandManager.execute(Commands.CMD_ADD_TO_WORKINGSET_AND_OPEN, {fullPath: fullPath,
paneId: paneId});
// This properly handles sending the right nofications in cases where the document
// is already the current one. In that case we will want to notify with
// documentSelectionFocusChange so the views change their selection
promise.done(function (doc) {
// FILE_ADD_TO_WORKING_SET command sets the current document. Update the
promise.done(function (file) {
// CMD_ADD_TO_WORKINGSET_AND_OPEN command sets the current document. Update the
// selection focus only if doc is not null. When double-clicking on an
// image file, we get a null doc here but we still want to keep _fileSelectionFocus
// as PROJECT_MANAGER. Regardless of doc is null or not, call _selectCurrentDocument
// as PROJECT_MANAGER. Regardless of doc is null or not, call _activatePane
// to trigger documentSelectionFocusChange event.
if (doc) {
_fileSelectionFocus = selectIn || WORKING_SET_VIEW;
}
_selectCurrentDocument();
result.resolve(doc);
result.resolve(file);
}).fail(function (err) {
result.reject(err);
});
@ -208,6 +208,34 @@ define(function (require, exports, module) {
return result.promise();
}
/**
* Opens the specified document if it's not already open, adds it to the working set,
* and selects it in the WorkingSetView
* @deprecated use FileViewController.openFileAndAddToWorkingSet() instead
* @param {!fullPath}
* @return {!$.Promise}
*/
function addToWorkingSetAndSelect(fullPath) {
DeprecationWarning.deprecationWarning("Use FileViewController.openFileAndAddToWorkingSet() instead of FileViewController.addToWorkingSetAndSelect().", true);
var result = new $.Deferred();
openFileAndAddToWorkingSet(fullPath)
.done(function (file) {
var doc;
if (file) {
doc = DocumentManager.getOpenDocumentForPath(file.fullPath);
}
result.resolve(doc);
})
.fail(function (err) {
result.reject(err);
});
return result.promise();
}
/**
* returns either WORKING_SET_VIEW or PROJECT_MANAGER
* @return {!String}
@ -217,11 +245,14 @@ define(function (require, exports, module) {
}
// Deprecated
exports.addToWorkingSetAndSelect = addToWorkingSetAndSelect;
// Define public API
exports.getFileSelectionFocus = getFileSelectionFocus;
exports.openAndSelectDocument = openAndSelectDocument;
exports.addToWorkingSetAndSelect = addToWorkingSetAndSelect;
exports.openFileAndAddToWorkingSet = openFileAndAddToWorkingSet;
exports.setFileViewFocus = setFileViewFocus;
exports.WORKING_SET_VIEW = WORKING_SET_VIEW;
exports.PROJECT_MANAGER = PROJECT_MANAGER;

View File

@ -56,6 +56,7 @@ define(function (require, exports, module) {
PreferencesDialogs = require("preferences/PreferencesDialogs"),
PreferencesManager = require("preferences/PreferencesManager"),
DocumentManager = require("document/DocumentManager"),
MainViewManager = require("view/MainViewManager"),
InMemoryFile = require("document/InMemoryFile"),
CommandManager = require("command/CommandManager"),
Commands = require("command/Commands"),
@ -307,8 +308,7 @@ define(function (require, exports, module) {
// Prefer file tree selection, else use working set selection
var selectedEntry = _getTreeSelectedItem();
if (!selectedEntry) {
var doc = DocumentManager.getCurrentDocument();
selectedEntry = (doc && doc.file);
selectedEntry = MainViewManager.getCurrentlyViewedFile();
}
return selectedEntry;
}
@ -318,12 +318,12 @@ define(function (require, exports, module) {
}
function _documentSelectionFocusChange() {
var curFile = EditorManager.getCurrentlyViewedPath();
if (curFile && _hasFileSelectionFocus()) {
var curFullPath = MainViewManager.getCurrentlyViewedPath(MainViewManager.ACTIVE_PANE);
if (curFullPath && _hasFileSelectionFocus()) {
var nodeFound = $("#project-files-container li").is(function (index) {
var $treeNode = $(this),
entry = $treeNode.data("entry");
if (entry && entry.fullPath === curFile) {
if (entry && entry.fullPath === curFullPath) {
if (!_projectTree.jstree("is_selected", $treeNode)) {
if ($treeNode.parents(".jstree-closed").length) {
//don't auto-expand tree to show file - but remember it if parent is manually expanded later
@ -650,12 +650,12 @@ define(function (require, exports, module) {
function (event, data) {
if (event.type === "open_node") {
// select the current document if it becomes visible when this folder is opened
var curDoc = DocumentManager.getCurrentDocument();
var curFile = MainViewManager.getCurrentlyViewedFile();
if (_hasFileSelectionFocus() && curDoc && data) {
if (_hasFileSelectionFocus() && curFile && data) {
var entry = data.rslt.obj.data("entry");
if (entry && curDoc.file.fullPath.indexOf(entry.fullPath) === 0) {
if (entry && curFile.fullPath.indexOf(entry.fullPath) === 0) {
_forceSelection(data.rslt.obj, _lastSelected);
} else {
_redraw(true, false);
@ -770,7 +770,7 @@ define(function (require, exports, module) {
.bind("dblclick.jstree", function (event) {
var entry = $(event.target).closest("li").data("entry");
if (entry && entry.isFile && !_isInRename(event.target)) {
FileViewController.addToWorkingSetAndSelect(entry.fullPath);
FileViewController.openFileAndAddToWorkingSet(entry.fullPath);
}
if (_mouseupTimeoutId !== null) {
window.clearTimeout(_mouseupTimeoutId);
@ -1221,7 +1221,7 @@ define(function (require, exports, module) {
}
// close all the old files
DocumentManager.closeAll();
MainViewManager._closeAll(MainViewManager.ALL_PANES);
_unwatchProjectRoot().always(function () {
// Finish closing old project (if any)
@ -1846,9 +1846,9 @@ define(function (require, exports, module) {
var entry = isFolder ? FileSystem.getDirectoryForPath(oldName) : FileSystem.getFileForPath(oldName);
entry.rename(newName, function (err) {
if (!err) {
if (EditorManager.getCurrentlyViewedPath()) {
if (MainViewManager.getCurrentlyViewedPath(MainViewManager.ACTIVE_PANE)) {
FileViewController.openAndSelectDocument(
EditorManager.getCurrentlyViewedPath(),
MainViewManager.getCurrentlyViewedPath(MainViewManager.ACTIVE_PANE),
FileViewController.getFileSelectionFocus()
);
}
@ -2016,11 +2016,7 @@ define(function (require, exports, module) {
// Trigger notifications after tree updates are complete
arr.forEach(function (entry) {
if (DocumentManager.getCurrentDocument()) {
DocumentManager.notifyPathDeleted(entry.fullPath);
} else {
EditorManager.notifyPathDeleted(entry.fullPath);
}
});
}
@ -2116,7 +2112,7 @@ define(function (require, exports, module) {
.done(function (result) {
// Add working set entries, if requested
if (includeWorkingSet) {
DocumentManager.getWorkingSet().forEach(function (file) {
MainViewManager.getWorkingSet(MainViewManager.ALL_PANES).forEach(function (file) {
if (result.indexOf(file) === -1 && !(file instanceof InMemoryFile)) {
result.push(file);
}

View File

@ -43,6 +43,7 @@ define(function (require, exports, module) {
var AppInit = require("utils/AppInit"),
ProjectManager = require("project/ProjectManager"),
WorkingSetView = require("project/WorkingSetView"),
MainViewManager = require("view/MainViewManager"),
CommandManager = require("command/CommandManager"),
Commands = require("command/Commands"),
Strings = require("strings"),
@ -57,7 +58,8 @@ define(function (require, exports, module) {
$sidebarMenuText,
$openFilesContainer,
$projectTitle,
$projectFilesContainer;
$projectFilesContainer,
$workingSetViewsContainer;
/**
* @private
@ -115,6 +117,7 @@ define(function (require, exports, module) {
$openFilesContainer = $("#open-files-container");
$projectTitle = $("#project-title");
$projectFilesContainer = $("#project-files-container");
$workingSetViewsContainer = $("#working-set-list-container");
function _resizeSidebarSelection() {
var $element;
@ -125,8 +128,6 @@ define(function (require, exports, module) {
}
// init
WorkingSetView.create($openFilesContainer);
$sidebar.on("panelResizeStart", function (evt, width) {
$sidebar.find(".sidebar-selection-triangle").css("display", "none");
$sidebar.find(".scroller-shadow").css("display", "none");
@ -163,11 +164,22 @@ define(function (require, exports, module) {
if (!$sidebar.is(":visible")) {
$sidebar.trigger("panelCollapsed");
}
// wire up an event handler to monitor when panes are created
$(MainViewManager).on("paneCreate", function (evt, paneId) {
WorkingSetView.createWorkingSetViewForPane($workingSetViewsContainer, paneId);
});
// create WorkingSetViews for each pane already created
_.forEach(MainViewManager.getPaneIdList(), function (paneId) {
WorkingSetView.createWorkingSetViewForPane($workingSetViewsContainer, paneId);
});
});
$(ProjectManager).on("projectOpen", _updateProjectTitle);
CommandManager.register(Strings.CMD_HIDE_SIDEBAR, Commands.VIEW_HIDE_SIDEBAR, toggle);
// Define public API
exports.toggle = toggle;
exports.show = show;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012 Adobe Systems Incorporated. All rights reserved.
* Copyright (c) 2014 Adobe Systems Incorporated. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
@ -26,48 +26,73 @@
/*global define, $, window */
/**
* Manages the workingSet sort methods.
* Manages the workingSetList sort methods.
*/
define(function (require, exports, module) {
"use strict";
var Commands = require("command/Commands"),
CommandManager = require("command/CommandManager"),
DocumentManager = require("document/DocumentManager"),
MainViewManager = require("view/MainViewManager"),
PreferencesManager = require("preferences/PreferencesManager"),
FileUtils = require("file/FileUtils"),
AppInit = require("utils/AppInit"),
Strings = require("strings");
var defaultPrefs = {
currentSort: Commands.SORT_WORKINGSET_BY_ADDED,
automaticSort: false
};
Strings = require("strings"),
_ = require("thirdparty/lodash");
/**
* List of sorting method objects
* @private
* @type {Array.<Sort>}
*/
var _sorts = [];
/**
* Denotes the current sort method object
* @private
* @type {Sort}
*/
var _currentSort = null;
/**
* Denotes if automatic sorting is enabled or not
* @private
* @type {boolean}
*/
var _automaticSort = false;
/**
* Maps Legacy sort method names to new sort method names
* @private
* @type {boolean}
* Used to know when to do the automatic sort for MRU order.
* @type {object.<string: string>} oldname: newname
*/
var _openedDocument = false;
var _sortPrefConversionMap = {
"view.sortWorkingSetByAdded" : "cmd.sortWorkingSetByAdded",
"view.sortWorkingSetByName" : "cmd.sortWorkingSetByName",
"view.sortWorkingSetByType" : "cmd.sortWorkingSetByType"
};
/**
* Events which the sort command will listen for to trigger a sort
* @constant {string}
* @private
*/
var _SORT_EVENT_NAMES = "workingSetAdd workingSetAddList";
/**
* Preference name
* @constant {string}
* @private
*/
var _WORKING_SET_SORT_PREF = "workingSetSortMethod";
/**
* Legacy preference name
* @constant {string}
* @private
*/
var _LEGACY_SORT_PREF = "currentSort";
/**
* Retrieves a Sort object by id
@ -89,6 +114,27 @@ define(function (require, exports, module) {
return _sorts[commandID];
}
/**
* Converts the old brackets working set sort preference into the modern paneview sort preference
* @private
* @param {!string} sortMethod - sort preference to convert
* @return {?string} new sort preference string or undefined if an sortMethod is not found
*/
function _convertSortPref(sortMethod) {
if (!sortMethod) {
return null;
}
if (_sortPrefConversionMap.hasOwnProperty(sortMethod)) {
sortMethod = _sortPrefConversionMap[sortMethod];
PreferencesManager.setViewState(_WORKING_SET_SORT_PREF, sortMethod);
} else {
sortMethod = null;
}
return sortMethod;
}
/**
* @return {boolean} Enabled state of Automatic Sort.
*/
@ -97,11 +143,11 @@ define(function (require, exports, module) {
}
/**
* Removes the sort listeners.
* @private
* Removes the sort DocumentManager listeners.
*/
function _removeListeners() {
$(DocumentManager).off(".sort");
$(MainViewManager).off(".sort");
}
/**
@ -110,11 +156,11 @@ define(function (require, exports, module) {
*/
function setAutomatic(enable) {
_automaticSort = enable;
PreferencesManager.setViewState("automaticSort", enable);
CommandManager.get(Commands.SORT_WORKINGSET_AUTO).setChecked(enable);
_currentSort.setChecked(enable);
PreferencesManager.setViewState("automaticSort", _automaticSort);
CommandManager.get(Commands.CMD_WORKING_SORT_TOGGLE_AUTO).setChecked(_automaticSort);
_currentSort.setChecked(_automaticSort);
if (enable) {
if (_automaticSort) {
_currentSort.sort();
} else {
_removeListeners();
@ -122,16 +168,16 @@ define(function (require, exports, module) {
}
/**
* Adds the current sort MainViewManager listeners.
* @private
* Adds the current sort DocumentManager listeners.
*/
function _addListeners() {
if (_automaticSort && _currentSort && _currentSort.getEvents()) {
$(DocumentManager)
$(MainViewManager)
.on(_currentSort.getEvents(), function () {
_currentSort.sort();
})
.on("workingSetDisableAutoSorting.sort", function () {
.on("_workingSetDisableAutoSort.sort", function () {
setAutomatic(false);
});
}
@ -139,8 +185,8 @@ define(function (require, exports, module) {
/**
* @private
* Sets the current sort method and checks it on the context menu.
* @private
* @param {Sort} newSort
*/
function _setCurrentSort(newSort) {
@ -153,8 +199,8 @@ define(function (require, exports, module) {
newSort.setChecked(true);
}
CommandManager.get(Commands.SORT_WORKINGSET_AUTO).setEnabled(!!newSort.getEvents());
PreferencesManager.setViewState("currentSort", newSort.getCommandID());
CommandManager.get(Commands.CMD_WORKING_SORT_TOGGLE_AUTO).setEnabled(!!newSort.getEvents());
PreferencesManager.setViewState(_WORKING_SET_SORT_PREF, newSort.getCommandID());
_currentSort = newSort;
}
}
@ -162,12 +208,10 @@ define(function (require, exports, module) {
/**
* @constructor
* @private
*
* @param {string} commandID A valid command identifier.
* @param {function(File, File): number} compareFn A valid sort
* function (see register for a longer explanation).
* @param {string} events Space-separated DocumentManager possible events
* @param {string} events Space-separated WorkingSetSort possible events
* ending with ".sort".
*/
function Sort(commandID, compareFn, events, automaticFn) {
@ -193,7 +237,7 @@ define(function (require, exports, module) {
};
/**
* The DocumentManager events
* Gets the event that this sort object is listening to
* @return {string}
*/
Sort.prototype.getEvents = function () {
@ -225,7 +269,7 @@ define(function (require, exports, module) {
Sort.prototype.sort = function () {
if (_currentSort === this) {
_removeListeners();
DocumentManager.sortWorkingSet(this._compareFn);
MainViewManager._sortWorkingSet(MainViewManager.ALL_PANES, this._compareFn);
_addListeners();
}
};
@ -280,82 +324,109 @@ define(function (require, exports, module) {
}
/** Command Handlers */
function _handleSortWorkingSetByAdded() {
get(Commands.SORT_WORKINGSET_BY_ADDED).execute();
}
function _handleSortWorkingSetByName() {
get(Commands.SORT_WORKINGSET_BY_NAME).execute();
}
function _handleSortWorkingSetByType() {
get(Commands.SORT_WORKINGSET_BY_TYPE).execute();
}
function _handleAutomaticSort() {
/**
* Command Handler for CMD_WORKING_SORT_TOGGLE_AUTO
* @private
*/
function _handleToggleAutoSort() {
setAutomatic(!getAutomatic());
}
/**
* Command Handler for CMD_WORKINGSET_SORT_BY_*
* @private
* @param {!string} commandId identifies the sort method to use
*/
function _handleSort(commandId) {
get(commandId).execute();
}
// Register Sort Methods
/**
* Register Sort Methods
*/
register(
Commands.SORT_WORKINGSET_BY_ADDED,
function (file1, file2) {
var index1 = DocumentManager.findInWorkingSetAddedOrder(file1.fullPath),
index2 = DocumentManager.findInWorkingSetAddedOrder(file2.fullPath);
Commands.CMD_WORKINGSET_SORT_BY_ADDED,
function (paneId, file1, file2) {
var index1 = MainViewManager.findInWorkingSetByAddedOrder(paneId, file1.fullPath),
index2 = MainViewManager.findInWorkingSetByAddedOrder(paneId, file2.fullPath);
return index1 - index2;
},
"workingSetAdd workingSetAddList"
_SORT_EVENT_NAMES
);
register(
Commands.SORT_WORKINGSET_BY_NAME,
function (file1, file2) {
Commands.CMD_WORKINGSET_SORT_BY_NAME,
function (paneId, file1, file2) {
return FileUtils.compareFilenames(file1.name, file2.name, false);
},
"workingSetAdd workingSetAddList"
_SORT_EVENT_NAMES
);
register(
Commands.SORT_WORKINGSET_BY_TYPE,
function (file1, file2) {
Commands.CMD_WORKINGSET_SORT_BY_TYPE,
function (paneId, file1, file2) {
return FileUtils.compareFilenames(file1.name, file2.name, true);
},
"workingSetAdd workingSetAddList"
_SORT_EVENT_NAMES
);
// Register Command Handlers
CommandManager.register(Strings.CMD_SORT_WORKINGSET_BY_ADDED, Commands.SORT_WORKINGSET_BY_ADDED, _handleSortWorkingSetByAdded);
CommandManager.register(Strings.CMD_SORT_WORKINGSET_BY_NAME, Commands.SORT_WORKINGSET_BY_NAME, _handleSortWorkingSetByName);
CommandManager.register(Strings.CMD_SORT_WORKINGSET_BY_TYPE, Commands.SORT_WORKINGSET_BY_TYPE, _handleSortWorkingSetByType);
CommandManager.register(Strings.CMD_SORT_WORKINGSET_AUTO, Commands.SORT_WORKINGSET_AUTO, _handleAutomaticSort);
/**
* Register Command Handlers
*/
CommandManager.register(Strings.CMD_WORKINGSET_SORT_BY_ADDED, Commands.CMD_WORKINGSET_SORT_BY_ADDED, _.partial(_handleSort, Commands.CMD_WORKINGSET_SORT_BY_ADDED));
CommandManager.register(Strings.CMD_WORKINGSET_SORT_BY_NAME, Commands.CMD_WORKINGSET_SORT_BY_NAME, _.partial(_handleSort, Commands.CMD_WORKINGSET_SORT_BY_NAME));
CommandManager.register(Strings.CMD_WORKINGSET_SORT_BY_TYPE, Commands.CMD_WORKINGSET_SORT_BY_TYPE, _.partial(_handleSort, Commands.CMD_WORKINGSET_SORT_BY_TYPE));
CommandManager.register(Strings.CMD_WORKING_SORT_TOGGLE_AUTO, Commands.CMD_WORKING_SORT_TOGGLE_AUTO, _handleToggleAutoSort);
// Initialize default values for sorting preferences
PreferencesManager.stateManager.definePreference("currentSort", "string", Commands.SORT_WORKINGSET_BY_ADDED);
/**
* Initialize default values for sorting preferences
*/
PreferencesManager.stateManager.definePreference("automaticSort", "boolean", false);
PreferencesManager.convertPreferences(module, {_LEGACY_SORT_PREF: "user", "automaticSort": "user"}, true);
PreferencesManager.convertPreferences(module, {"currentSort": "user", "automaticSort": "user"}, true);
/**
* Define a default sort method that's empty so that we
* just convert and use the legacy sort method
*/
PreferencesManager.stateManager.definePreference(_WORKING_SET_SORT_PREF, "string", "");
// Initialize items dependent on extensions/workingSet
/*
* initializes global sort method from preference settings or the default
*/
function initSortMethod() {
var sortMethod = PreferencesManager.getViewState(_WORKING_SET_SORT_PREF);
if (!sortMethod) {
sortMethod = _convertSortPref(PreferencesManager.getViewState(_LEGACY_SORT_PREF));
}
if (!sortMethod) {
sortMethod = Commands.CMD_WORKINGSET_SORT_BY_ADDED;
}
return sortMethod;
}
/**
* Initialize items dependent on extensions/workingSetList
*/
AppInit.appReady(function () {
var curSort = get(PreferencesManager.getViewState("currentSort")),
var sortMethod = initSortMethod(),
curSort = get(sortMethod),
autoSort = PreferencesManager.getViewState("automaticSort");
if (curSort) {
_setCurrentSort(curSort);
}
if (autoSort) {
setAutomatic(true);
setAutomatic(autoSort);
}
if (curSort && autoSort) {
curSort.sort();
}
});
// Define public API
// Public API
exports.register = register;
exports.get = get;
exports.getAutomatic = getAutomatic;

File diff suppressed because it is too large Load Diff

View File

@ -37,6 +37,7 @@ define(function (require, exports, module) {
KeyEvent = require("utils/KeyEvent"),
ModalBar = require("widgets/ModalBar").ModalBar,
PreferencesManager = require("preferences/PreferencesManager"),
MainViewManager = require("view/MainViewManager"),
Strings = require("strings"),
ViewUtils = require("utils/ViewUtils");
@ -240,7 +241,7 @@ define(function (require, exports, module) {
self._modalBar = null;
self._closed = true;
FindBar._removeFindBar(self);
EditorManager.focusEditor();
MainViewManager.focusActivePane();
$(self).trigger("close");
});

View File

@ -37,6 +37,7 @@ define(function (require, exports, module) {
ProjectManager = require("project/ProjectManager"),
DocumentModule = require("document/Document"),
DocumentManager = require("document/DocumentManager"),
MainViewManager = require("view/MainViewManager"),
FileSystem = require("filesystem/FileSystem"),
LanguageManager = require("language/LanguageManager"),
SearchModel = require("search/SearchModel").SearchModel,
@ -310,10 +311,7 @@ define(function (require, exports, module) {
// Still need to make sure it's within project or working set
// In getCandidateFiles(), this is covered by the baseline getAllFiles() itself
if (file.fullPath.indexOf(ProjectManager.getProjectRoot().fullPath) !== 0) {
var inWorkingSet = DocumentManager.getWorkingSet().some(function (wsFile) {
return wsFile.fullPath === file.fullPath;
});
if (!inWorkingSet) {
if (MainViewManager.findInWorkingSet(MainViewManager.ALL_PANES, file.fullPath) === -1) {
return false;
}
}

View File

@ -39,6 +39,7 @@ define(function (require, exports, module) {
Dialogs = require("widgets/Dialogs"),
DefaultDialogs = require("widgets/DefaultDialogs"),
EditorManager = require("editor/EditorManager"),
WorkspaceManager = require("view/WorkspaceManager"),
FileFilters = require("search/FileFilters"),
FileUtils = require("file/FileUtils"),
FindBar = require("search/FindBar").FindBar,
@ -117,7 +118,7 @@ define(function (require, exports, module) {
function _showFindBar(scope, showReplace) {
// If the scope is a file with a custom viewer, then we
// don't show find in files dialog.
if (scope && EditorManager.getCustomViewerForPath(scope.fullPath)) {
if (scope && !EditorManager.canOpenPath(scope.fullPath)) {
return;
}
@ -252,7 +253,7 @@ define(function (require, exports, module) {
scrollPos = fullEditor.getScrollPos();
scrollPos.y -= oldModalBarHeight; // modalbar already showing, adjust for old height
}
EditorManager.resizeEditor();
WorkspaceManager.recomputeLayout();
if (fullEditor) {
fullEditor._codeMirror.scrollTo(scrollPos.x, scrollPos.y + _findBar._modalBar.height());
}

View File

@ -38,6 +38,7 @@ define(function (require, exports, module) {
AppInit = require("utils/AppInit"),
Commands = require("command/Commands"),
DocumentManager = require("document/DocumentManager"),
MainViewManager = require("view/MainViewManager"),
ProjectManager = require("project/ProjectManager"),
Strings = require("strings"),
StringUtils = require("utils/StringUtils"),
@ -47,7 +48,6 @@ define(function (require, exports, module) {
FindUtils = require("search/FindUtils"),
FindInFilesUI = require("search/FindInFilesUI"),
ScrollTrackMarkers = require("search/ScrollTrackMarkers"),
PanelManager = require("view/PanelManager"),
Resizer = require("utils/Resizer"),
StatusBar = require("widgets/StatusBar"),
PreferencesManager = require("preferences/PreferencesManager"),
@ -669,7 +669,7 @@ define(function (require, exports, module) {
* When the user switches documents (or closes the last document), ensure that the find bar
* closes, and also close the Replace All panel.
*/
function _handleDocumentChange() {
function _handleFileChanged() {
if (findBar) {
findBar.close();
}
@ -745,7 +745,7 @@ define(function (require, exports, module) {
}
}
$(DocumentManager).on("currentDocumentChange", _handleDocumentChange);
$(MainViewManager).on("currentFileChange", _handleFileChanged);
CommandManager.register(Strings.CMD_FIND, Commands.CMD_FIND, _launchFind);
CommandManager.register(Strings.CMD_FIND_NEXT, Commands.CMD_FIND_NEXT, _findNext);

View File

@ -29,6 +29,7 @@ define(function (require, exports, module) {
var Async = require("utils/Async"),
DocumentManager = require("document/DocumentManager"),
MainViewManager = require("view/MainViewManager"),
FileSystem = require("filesystem/FileSystem"),
FileUtils = require("file/FileUtils"),
ProjectManager = require("project/ProjectManager"),
@ -176,7 +177,7 @@ define(function (require, exports, module) {
options = options || {};
// If we're forcing files open, or if the document is in the working set but not actually open
// yet, we want to open the file and do the replacement in memory.
if (!doc && (options.forceFilesOpen || DocumentManager.findInWorkingSet(fullPath) !== -1)) {
if (!doc && (options.forceFilesOpen || MainViewManager.findInWorkingSet(MainViewManager.ALL_PANES, fullPath) !== -1)) {
return DocumentManager.getDocumentForPath(fullPath).then(function (newDoc) {
return _doReplaceInDocument(newDoc, matchInfo, replaceText, options.isRegexp);
});
@ -244,7 +245,7 @@ define(function (require, exports, module) {
var newDoc = DocumentManager.getOpenDocumentForPath(firstPath);
// newDoc might be null if the replacement failed.
if (newDoc) {
DocumentManager.setCurrentDocument(newDoc);
MainViewManager._edit(MainViewManager.ACTIVE_PANE, newDoc);
}
}
}

View File

@ -42,6 +42,8 @@ define(function (require, exports, module) {
var DocumentManager = require("document/DocumentManager"),
EditorManager = require("editor/EditorManager"),
MainViewManager = require("view/MainViewManager"),
MainViewFactory = require("view/MainViewFactory"),
CommandManager = require("command/CommandManager"),
Strings = require("strings"),
StringUtils = require("utils/StringUtils"),
@ -355,7 +357,7 @@ define(function (require, exports, module) {
// So we call `prepareClose()` first, and finish the close later.
doClose = false;
this.modalBar.prepareClose();
CommandManager.execute(Commands.FILE_ADD_TO_WORKING_SET, {fullPath: fullPath})
CommandManager.execute(Commands.CMD_ADD_TO_WORKINGSET_AND_OPEN, {fullPath: fullPath})
.done(function () {
if (cursorPos) {
var editor = EditorManager.getCurrentFullEditor();
@ -372,7 +374,7 @@ define(function (require, exports, module) {
if (doClose) {
this.close();
EditorManager.focusEditor();
MainViewManager.focusActivePane();
}
};
@ -876,7 +878,8 @@ define(function (require, exports, module) {
// Return files that are non-binary, or binary files that have a custom viewer
function _filter(file) {
return !LanguageManager.getLanguageForPath(file.fullPath).isBinary() || EditorManager.getCustomViewerForPath(file.fullPath);
return !LanguageManager.getLanguageForPath(file.fullPath).isBinary()
|| MainViewFactory.findSuitableFactoryForPath(file.fullPath);
}
// Start fetching the file list, which will be needed the first time the user enters

View File

@ -37,7 +37,7 @@ define(function (require, exports, module) {
var Editor = require("editor/Editor"),
EditorManager = require("editor/EditorManager"),
PanelManager = require("view/PanelManager");
WorkspaceManager = require("view/WorkspaceManager");
/**
@ -142,7 +142,7 @@ define(function (require, exports, module) {
_calcScaling();
// Update tickmarks during editor resize (whenever resizing has paused/stopped for > 1/3 sec)
$(PanelManager).on("editorAreaResize.ScrollTrackMarkers", _.debounce(function () {
$(WorkspaceManager).on("workspaceUpdateLayout.ScrollTrackMarkers", _.debounce(function () {
if (marks.length) {
_calcScaling();
$(".tickmark-track", editor.getRootElement()).empty();
@ -155,7 +155,7 @@ define(function (require, exports, module) {
$(".tickmark-track", curEditor.getRootElement()).remove();
editor = null;
marks = [];
$(PanelManager).off("editorAreaResize.ScrollTrackMarkers");
$(WorkspaceManager).off("workspaceUpdateLayout.ScrollTrackMarkers");
}
}

View File

@ -37,7 +37,7 @@ define(function (require, exports, module) {
FileViewController = require("project/FileViewController"),
FileUtils = require("file/FileUtils"),
FindUtils = require("search/FindUtils"),
PanelManager = require("view/PanelManager"),
WorkspaceManager = require("view/WorkspaceManager"),
StringUtils = require("utils/StringUtils"),
Strings = require("strings"),
_ = require("thirdparty/lodash"),
@ -75,7 +75,7 @@ define(function (require, exports, module) {
function SearchResultsView(model, panelID, panelName) {
var panelHtml = Mustache.render(searchPanelTemplate, {panelID: panelID});
this._panel = PanelManager.createBottomPanel(panelName, $(panelHtml), 100);
this._panel = WorkspaceManager.createBottomPanel(panelName, $(panelHtml), 100);
this._$summary = this._panel.$panel.find(".title");
this._$table = this._panel.$panel.find(".table-container");
this._model = model;
@ -176,7 +176,7 @@ define(function (require, exports, module) {
// Add the file to the working set on double click
.on("dblclick.searchResults", ".table-container tr:not(.file-section)", function (e) {
var item = self._searchList[$(this).data("file-index")];
FileViewController.addToWorkingSetAndSelect(item.fullPath);
FileViewController.openFileAndAddToWorkingSet(item.fullPath);
})
// Add the click event listener directly on the table parent

View File

@ -71,6 +71,8 @@ html, body {
}
}
.resizing-container {
position: absolute;
top: 0;
@ -132,6 +134,10 @@ a, img {
}
}
.forced-hidden {
display: none !important;
}
.busyCursor {
cursor: wait !important;
}
@ -316,7 +322,7 @@ a, img {
position: relative;
/* Placeholder shown when there is no editor open */
#not-editor {
.not-editor {
height: 100%;
.vbox;
.box-pack(center);
@ -328,8 +334,17 @@ a, img {
}
}
.view-pane {
display: block;
margin: 0;
overflow: hidden;
height: 100%;
width: 100%;
border: solid rgba(9, 9, 9, .05) 2px;
box-sizing: border-box;
/* Image Preview */
#image-holder {
.image-view {
overflow: hidden;
position: absolute;
top: 0px;
@ -337,20 +352,19 @@ a, img {
bottom: 0px;
left: 0px;
text-align: center;
display: none;
#img-centering {
.image-centering {
display: inline-block;
vertical-align: middle;
margin-top: -50px; /* Offset as vertical align takes image metadata into account */
max-width: 90%;
max-height: 90%;
}
#img-data {
.image-data {
font-weight: @font-weight-semibold;
}
}
#image-holder:before {
.image-view:before {
content: '';
display: inline-block;
height: 100%;
@ -358,7 +372,7 @@ a, img {
vertical-align: middle;
}
#img-preview {
.image-preview {
background: url(images/preview_bg.png);
box-shadow: 0 1px 3px @bc-shadow;
max-height: 90%;
@ -369,15 +383,15 @@ a, img {
}
}
#img-header {
.image-header {
display: block;
width: 100%;
height: 38px;
margin-bottom: 15px;
}
#img-data,
#img-path {
.image-data,
.image-path {
text-align: left;
.user-select(text);
white-space: nowrap;
@ -385,22 +399,22 @@ a, img {
overflow: hidden;
}
#img-data::selection,
#img-path::selection {
.image-data::selection,
.image-path::selection {
background: @selection-color-focused;
}
#img {
.image {
position: relative;
}
.img-guide,
#img-tip,
#img-scale {
.image-guide,
.image-tip,
.image-scale {
pointer-events: none;
}
#img-scale {
.image-scale {
display: block;
position: absolute;
top: 5px;
@ -418,7 +432,7 @@ a, img {
}
}
#img-tip {
.image-tip {
display: block;
position: absolute;
text-align: left;
@ -438,8 +452,8 @@ a, img {
}
}
#x-value,
#y-value {
.x-value,
.y-value {
text-align: right;
}
@ -447,27 +461,37 @@ a, img {
border: 0;
}
#horiz-guide {
.horz-guide {
background-image: url("images/horizontal-dash.svg");
background-repeat: repeat-x;
width: 8px;
height: 1px;
}
#vert-guide {
.vert-guide {
background-image: url("images/vertical-dash.svg");
background-repeat: repeat-y;
width: 1px;
height: 8px;
}
#horiz-guide,
#vert-guide {
.horz-guide,
.vert-guide {
position: absolute;
display: block;
}
}
.active-pane {
border: solid rgba(0, 0, 255, .2) 2px;
box-sizing: border-box;
.dark & {
border: solid rgba(255, 255, 255, .2) 2px;
}
}
}
.vert-resizer {
position: absolute;
height: 6px;
@ -638,7 +662,7 @@ a, img {
/* Project panel */
#working-set-header {
.working-set-header {
position: relative;
height: 19px;
padding: 10px 0 9px 12px;
@ -653,13 +677,13 @@ a, img {
}
}
#working-set-option-btn {
.working-set-option-btn {
position: absolute;
right: 4px;
top: 7px;
padding: 4px 6px;
.sprite-icon(0, 0, 13px, 13px, "images/topcoat-settings-13.svg");
background-position: center;
background-position:center;
opacity: 0.8;
}
@ -685,7 +709,7 @@ a, img {
overflow: hidden;
}
#open-files-container {
.open-files-container {
.box-flex(0);
background: @bc-sidebar-bg;
padding: 0px;
@ -704,14 +728,6 @@ a, img {
padding: 0 0 0 8px;
min-height: 18px;
vertical-align: baseline;
&.selected a {
color: @open-working-file-name-highlight;
}
&.selected .extension {
color: @open-working-file-ext-highlight;
}
}
a {
@ -742,6 +758,19 @@ a, img {
}
}
.open-files-container.active {
li {
&.selected a {
color: @open-working-file-name-highlight;
}
&.selected .extension {
color: @open-working-file-ext-highlight;
}
}
}
.sidebar-selection {
background: @bc-sidebar-selection;
border-top: 1px solid @bc-shadow-small;
@ -780,7 +809,7 @@ a, img {
}
//Initially start with the open files hidden, they will get show as files are added
#open-files-container {
.open-files-container {
display:none;
}
@ -2009,6 +2038,10 @@ label input {
display: inline;
}
#hidden-editors {
display: none;
}
.theme-settings td {
padding: 2px;
}
@ -2018,6 +2051,3 @@ label input {
max-height: 300px;
}
.theme-settings .label {
padding: 4px !important;
}

View File

@ -30,6 +30,7 @@
*
* This module defines 2 methods for client modules to attach callbacks:
* - htmlReady - When the main application template is rendered
* - extensionsRead - When the extension manager has loaded all extensions
* - appReady - When Brackets completes loading all modules and extensions
*
* These are *not* jQuery events. Each method is similar to $(document).ready
@ -39,18 +40,51 @@
define(function (require, exports, module) {
"use strict";
// Fires when the base htmlContent/main-view.html is loaded
/*
* Fires when the base htmlContent/main-view.html is loaded
* @type {string}
* @const
*/
var HTML_READY = "htmlReady";
// Fires when all extensions are loaded
/*
* Fires when all extensions are loaded
* @type {string}
* @const
*/
var APP_READY = "appReady";
var status = { HTML_READY : false, APP_READY : false },
callbacks = {};
/*
* Fires after extensions have been loaded
* @type {string}
* @const
*/
var EXTENSIONS_LOADED = "extensionsLoaded";
callbacks[HTML_READY] = [];
callbacks[APP_READY] = [];
/*
* Map of each state's trigger
* @type {Object.<string, boolean>}
* @private
*/
var _status = { HTML_READY : false, APP_READY : false, EXTENSIONS_LOADED: false };
/*
* Map of callbacks to states
* @type {Object.<string, Array.<function()>>}
* @private
*/
var _callbacks = {};
_callbacks[HTML_READY] = [];
_callbacks[APP_READY] = [];
_callbacks[EXTENSIONS_LOADED] = [];
/*
* calls the specified handler inside a try/catch handler
* @param {function()} handler - the callback to call
* @private
*/
function _callHandler(handler) {
try {
// TODO (issue 1034): We *could* use a $.Deferred for this, except deferred objects enter a broken
@ -63,26 +97,37 @@ define(function (require, exports, module) {
}
}
/*
* dispatches the event by calling all handlers registered for that type
* @param {string} type - the event type to dispatch (APP_READY, EXTENSIONS_READY, HTML_READY)
* @private
*/
function _dispatchReady(type) {
var i,
myHandlers = callbacks[type];
myHandlers = _callbacks[type];
// mark this status complete
status[type] = true;
_status[type] = true;
for (i = 0; i < myHandlers.length; i++) {
_callHandler(myHandlers[i]);
}
// clear all callbacks after being called
callbacks[type] = [];
_callbacks[type] = [];
}
function _addListener(type, callback) {
if (status[type]) {
_callHandler(callback);
/*
* adds a callback to the list of functions to call for the specified event type
* @param {string} type - the event type to dispatch (APP_READY, EXTENSIONS_READY, HTML_READY)
* @param {function} handler - callback funciton to call when the event is triggered
* @private
*/
function _addListener(type, handler) {
if (_status[type]) {
_callHandler(handler);
} else {
callbacks[type].push(callback);
_callbacks[type].push(handler);
}
}
@ -90,27 +135,39 @@ define(function (require, exports, module) {
* Adds a callback for the ready hook. Handlers are called after
* htmlReady is done, the initial project is loaded, and all extensions are
* loaded.
* @param {function} callback
* @param {function} handler - callback function to call when the event is fired
*/
function appReady(callback) {
_addListener(APP_READY, callback);
function appReady(handler) {
_addListener(APP_READY, handler);
}
/**
* Adds a callback for the htmlReady hook. Handlers are called after the
* main application html template is rendered.
* @param {function} callback
* @param {function} handler - callback function to call when the event is fired
*/
function htmlReady(callback) {
_addListener(HTML_READY, callback);
function htmlReady(handler) {
_addListener(HTML_READY, handler);
}
/**
* Adds a callback for the extensionsLoaded hook. Handlers are called after the
* extensions have been loaded
* @param {function} handler - callback function to call when the event is fired
*/
function extensionsLoaded(handler) {
_addListener(EXTENSIONS_LOADED, handler);
}
// Public API
exports.appReady = appReady;
exports.htmlReady = htmlReady;
exports.extensionsLoaded = extensionsLoaded;
exports.HTML_READY = HTML_READY;
exports.APP_READY = APP_READY;
exports.EXTENSIONS_LOADED = EXTENSIONS_LOADED;
// internal use only
// Unit Test API
exports._dispatchReady = _dispatchReady;
});

View File

@ -21,7 +21,7 @@
*
*/
/*global define, console */
/*global define, console, $ */
/**
* Utilities functions to display deprecation warning in the console.
@ -55,7 +55,7 @@ define(function (require, exports, module) {
}
/**
* Show deprecation message with the call stack if it
* Show deprecation warning with the call stack if it
* has never been displayed before.
* @param {!string} message The deprecation message to be displayed.
* @param {boolean=} oncePerCaller If true, displays the message once for each unique call location.
@ -89,6 +89,91 @@ define(function (require, exports, module) {
displayedWarnings[message][callerLocation] = true;
}
/**
* Counts the number of event handlers listening for the specified event on the specified object
* @param {!Object} object - the object with the old event to dispatch
* @param {!string} name - the name of the event
* @return {!number} count of event handlers
*/
function getEventHandlerCount(object, name) {
var count = 0,
events = $._data(object, "events");
// If there are there any listeners then display a deprecation warning
if (events && events.hasOwnProperty(name)) {
var listeners = events[name];
count = listeners.length;
if (listeners.hasOwnProperty("delegateCount")) {
// we need to subtract 1 since delegateCount is counted
// in the length computed above.
count += (listeners.delegateCount - 1);
}
}
return count;
}
/**
* Show a deprecation warning if there are listeners for the event
*
* ```
* DeprecationWarning.deprecateEvent($(exports),
* $(MainViewManager),
* "workingSetAdd",
* "workingSetAdd",
* "DocumentManager.workingSetAdd",
* "MainViewManager.workingSetAdd");
* ```
*
* @param {Object} outbound - the object with the old event to dispatch
* @param {Object} inbound - the object with the new event to map to the old event
* @param {string} oldEventName - the name of the old event
* @param {string} newEventName - the name of the new event
* @param {string=} canonicalOutboundName - the canonical name of the old event
* @param {string=} canonicalInboundName - the canonical name of the new event
*/
function deprecateEvent(outbound, inbound, oldEventName, newEventName, canonicalOutboundName, canonicalInboundName) {
// create an event handler for the new event to listen for
$(inbound).on(newEventName, function () {
// Get the jQuery event data from the outbound object -- usually the module's exports
var listenerCount = getEventHandlerCount(outbound, oldEventName);
if (listenerCount > 0) {
var message = "The Event " + (canonicalOutboundName || oldEventName) + " has been deprecated. Use " + (canonicalInboundName || newEventName) + " instead.";
// We only want to show the deprecation warning once
if (!displayedWarnings[message]) {
displayedWarnings[message] = true;
console.warn(message);
}
}
// dispatch the event even if there are no listeners just in case the jQuery data is wrong for some reason
$(outbound).trigger(oldEventName, Array.prototype.slice.call(arguments, 1));
});
}
/**
* Create a deprecation warning and action for updated constants
* @param {!string} old Menu Id
* @param {!string} new Menu Id
*/
function deprecateConstant(obj, oldId, newId) {
var warning = "Use Menus." + newId + " instead of Menus." + oldId,
newValue = obj[newId];
Object.defineProperty(obj, oldId, {
get: function () {
deprecationWarning(warning, true);
return newValue;
}
});
}
// Define public API
exports.deprecationWarning = deprecationWarning;
exports.deprecateEvent = deprecateEvent;
exports.getEventHandlerCount = getEventHandlerCount;
exports.deprecateConstant = deprecateConstant;
});

View File

@ -33,7 +33,9 @@ define(function (require, exports, module) {
Commands = require("command/Commands"),
Dialogs = require("widgets/Dialogs"),
DefaultDialogs = require("widgets/DefaultDialogs"),
DocumentManager = require("document/DocumentManager"),
MainViewManager = require("view/MainViewManager"),
MainViewFactory = require("view/MainViewFactory"),
LanguageManager = require("language/LanguageManager"),
FileSystem = require("filesystem/FileSystem"),
EditorManager = require("editor/EditorManager"),
FileUtils = require("file/FileUtils"),
@ -42,26 +44,18 @@ define(function (require, exports, module) {
StringUtils = require("utils/StringUtils");
/**
* Return an array of files excluding all files with a custom viewer. If all files
* in the array have their own custom viewers, then the last file is added back in
* the array since only one file with custom viewer can be open at a time.
* Return an array of files excluding all files without a registered viewer.
*
* @param {Array.<string>} files Array of files to filter before opening.
* @return {Array.<string>}
* @param {Array.<string>} paths - filenames to filter before opening.
* @return {Array.<string>} paths which can actually be opened (may be empty)
*/
function filterFilesToOpen(files) {
// Filter out all files that have their own custom viewers
// since we don't keep them in the working set.
var filteredFiles = files.filter(function (file) {
return !EditorManager.getCustomViewerForPath(file);
function filterFilesToOpen(paths) {
// Filter out file in which we have no registered viewer
var filteredFiles = paths.filter(function (fullPath) {
return !LanguageManager.getLanguageForPath(fullPath).isBinary()
|| MainViewFactory.findSuitableFactoryForPath(fullPath);
});
// If all files have custom viewers, then add back the last file
// so that we open it in its custom viewer.
if (filteredFiles.length === 0 && files.length) {
filteredFiles.push(files[files.length - 1]);
}
return filteredFiles;
}
@ -111,13 +105,13 @@ define(function (require, exports, module) {
// file in the list, return. If this *is* the last file,
// always open it so it gets selected.
if (idx < filteredFiles.length - 1) {
if (DocumentManager.findInWorkingSet(path) !== -1) {
if (MainViewManager.findInWorkingSet(MainViewManager.ALL_PANES, path) !== -1) {
result.resolve();
return;
}
}
CommandManager.execute(Commands.FILE_ADD_TO_WORKING_SET,
CommandManager.execute(Commands.CMD_ADD_TO_WORKINGSET_AND_OPEN,
{fullPath: path, silent: true})
.done(function () {
result.resolve();

View File

@ -56,7 +56,7 @@ define(function (require, exports, module) {
/**
* Stores require.js contexts of extensions
* @type {Object<string, Object>}
* @type {Object.<string, Object>}
*/
var contexts = {};
@ -146,38 +146,6 @@ define(function (require, exports, module) {
return deferred.promise();
}
/**
* Loads the extension that lives at baseUrl into its own Require.js context
*
* @param {!string} name, used to identify the extension
* @param {!{baseUrl: string}} config object with baseUrl property containing absolute path of extension
* @param {!string} entryPoint, name of the main js file to load
* @return {!$.Promise} A promise object that is resolved when the extension is loaded, or rejected
* if the extension fails to load or throws an exception immediately when loaded.
* (Note: if extension contains a JS syntax error, promise is resolved not rejected).
*/
function loadExtension(name, config, entryPoint) {
var promise = new $.Deferred();
// Try to load the package.json to figure out if we are loading a theme.
ExtensionUtils.loadPackageJson(config.baseUrl).always(promise.resolve);
return promise
.then(function(metadata) {
// No special handling for themes... Let the promise propagate into the ExtensionManager
if (metadata && "theme" in metadata) {
return;
}
return loadExtensionModule(name, config, entryPoint);
})
.then(function () {
$(exports).triggerHandler("load", config.baseUrl);
}, function (err) {
$(exports).triggerHandler("loadFailed", config.baseUrl);
});
}
/**
* Loads the extension module that lives at baseUrl into its own Require.js context
*
@ -253,6 +221,38 @@ define(function (require, exports, module) {
return promise;
}
/**
* Loads the extension that lives at baseUrl into its own Require.js context
*
* @param {!string} name, used to identify the extension
* @param {!{baseUrl: string}} config object with baseUrl property containing absolute path of extension
* @param {!string} entryPoint, name of the main js file to load
* @return {!$.Promise} A promise object that is resolved when the extension is loaded, or rejected
* if the extension fails to load or throws an exception immediately when loaded.
* (Note: if extension contains a JS syntax error, promise is resolved not rejected).
*/
function loadExtension(name, config, entryPoint) {
var promise = new $.Deferred();
// Try to load the package.json to figure out if we are loading a theme.
ExtensionUtils.loadPackageJson(config.baseUrl).always(promise.resolve);
return promise
.then(function (metadata) {
// No special handling for themes... Let the promise propagate into the ExtensionManager
if (metadata && metadata.hasOwnProperty("theme")) {
return;
}
return loadExtensionModule(name, config, entryPoint);
})
.then(function () {
$(exports).triggerHandler("load", config.baseUrl);
}, function (err) {
$(exports).triggerHandler("loadFailed", config.baseUrl);
});
}
/**
* Runs unit tests for the extension that lives at baseUrl into its own Require.js context
*

View File

@ -143,9 +143,9 @@ define(function (require, exports, module) {
* @param {?string} forceLeft CSS selector indicating element whose 'left' should be locked to the
* the resizable element's size (useful for siblings laid out to the right of
* the element). Must lie in element's parent's subtree.
* @param {?boolean} createdByPanelManager For internal use only
* @param {?boolean} createdByWorkspaceManager For internal use only
*/
function makeResizable(element, direction, position, minSize, collapsible, forceLeft, createdByPanelManager) {
function makeResizable(element, direction, position, minSize, collapsible, forceLeft, createdByWorkspaceManager) {
var $resizer = $('<div class="' + direction + '-resizer"></div>'),
$element = $(element),
@ -177,9 +177,9 @@ define(function (require, exports, module) {
// Important so min/max sizes behave predictably
$element.css("box-sizing", "border-box");
// Detect legacy cases where panels in the editor area are created without using PanelManager APIs
if ($parent[0] && $parent.is(".content") && !createdByPanelManager) {
console.warn("Deprecated: resizable panels should be created via PanelManager.createBottomPanel(). Using Resizer directly will stop working in the future. \nElement:", element);
// Detect legacy cases where panels in the editor area are created without using WorkspaceManager APIs
if ($parent[0] && $parent.is(".content") && !createdByWorkspaceManager) {
console.warn("Deprecated: resizable panels should be created via WorkspaceManager.createBottomPanel(). Using Resizer directly will stop working in the future. \nElement:", element);
$(exports).triggerHandler("deprecatedPanelAdded", [$element]);
}
@ -328,7 +328,7 @@ define(function (require, exports, module) {
// between starting and current position, capped at minSize
newSize = Math.max(startSize + directionIncrement * (startPosition - e[directionProperty]), minSize);
// respect max size if one provided (e.g. by PanelManager)
// respect max size if one provided (e.g. by WorkspaceManager)
var maxSize = $element.data("maxsize");
if (maxSize !== undefined) {
newSize = Math.min(newSize, maxSize);

View File

@ -232,6 +232,11 @@ define(function (require, exports, module) {
}
};
var hideSelectionMarker = function (event) {
$selectionTriangle.addClass("forced-hidden");
$selectionMarker.addClass("forced-hidden");
};
var updateSelectionMarker = function (event, reveal) {
// find the selected list item
var $listItem = $listElement.find(selectedClassName).closest("li");
@ -240,6 +245,9 @@ define(function (require, exports, module) {
showTriangle = $listItem.hasClass(leafClassName);
}
$selectionTriangle.removeClass("forced-hidden");
$selectionMarker.removeClass("forced-hidden");
// always hide selection visuals first to force layout (issue #719)
$selectionTriangle.hide();
$selectionMarker.hide();
@ -279,6 +287,7 @@ define(function (require, exports, module) {
$listElement.on("selectionChanged", updateSelectionMarker);
$scrollerElement.on("scroll", updateSelectionTriangle);
$scrollerElement.on("selectionRedraw", updateSelectionTriangle);
$scrollerElement.on("selectionHide", hideSelectionMarker);
// update immediately
updateSelectionMarker();
@ -467,6 +476,32 @@ define(function (require, exports, module) {
return displayPaths;
}
function traverseViewArray(viewArray, startIndex, direction) {
if (Math.abs(direction) !== 1) {
console.error("traverseViewArray called with unsupported direction: " + direction.toString());
return null;
}
if (startIndex === -1) {
// If doc not in view list, return most recent view list item
if (viewArray.length > 0) {
return viewArray[0];
}
} else if (viewArray.length > 1) {
// If doc is in view list, return next/prev item with wrap-around
startIndex += direction;
if (startIndex >= viewArray.length) {
startIndex = 0;
} else if (startIndex < 0) {
startIndex = viewArray.length - 1;
}
return viewArray[startIndex];
}
// If no doc open or view list empty, there is no "next" file
return null;
}
// handle all resize handlers in a single listener
$(window).resize(_handleResize);
@ -480,4 +515,5 @@ define(function (require, exports, module) {
exports.getFileEntryDisplay = getFileEntryDisplay;
exports.toggleClass = toggleClass;
exports.getDirNamesForDuplicateFiles = getDirNamesForDuplicateFiles;
exports.traverseViewArray = traverseViewArray;
});

111
src/view/MainViewFactory.js Normal file
View File

@ -0,0 +1,111 @@
/*
* Copyright (c) 2014 Adobe Systems Incorporated. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
/*jslint vars: true, plusplus: true, devel: true, nomen: true, indent: 4, maxerr: 50 */
/*global define, window, $, brackets */
/**
* MainViewFactory is a singleton for managing view factories.
*
* Registering a view factory:
*
* registerViewFactory({
* canOpen: function (fullPath) {
* return (fullPath.slice(-4) === ".ico");
* },
* open: function(file, pane) {
* return createIconView(file, pane);
* }
* });
*
* The open method is used to open the file and construct
* a view of it. Implementation should add the view to the pane
*
* function createIconView(file, pane) {
* // IconView will construct its DOM and append
* // it to pane.$el
* var view = new IconView(file, pane.$el);
* // Then tell the pane to add it to
* // its view map and show it
* pane.addView(view, true);
* return new $.Deferred().resolve().promise();
* }
*
* Factories should only create 1 view of a file per pane. Brackets currently only supports 1 view of
* a file open at a given time but that may change to allow the same file open in more than 1 pane. Therefore
* Factories can do a simple check to see if a view already exists and show it before creating a new one:
*
* var view = pane.getViewForPath(file.fullPath);
* if (view) {
* pane.showView(view);
* } else {
* return createIconView(file, pane);
* }
*
*/
define(function (require, exports, module) {
"use strict";
var _ = require("thirdparty/lodash");
/**
* @typedef {canOpenFile:function(path:string):boolean, openFile:function(path:string, pane:Pane)} Factory
*/
/**
* The view registration Database
* @private
* @type {Array.<Factory>}
*/
var _factories = [];
/**
* Registers a view factory
* @param {!Factory} factory - the view factory to register
*/
function registerViewFactory(factory) {
_factories.push(factory);
}
/**
* Finds a factory that can open the specified file
* @param {!string} fullPath - the file to open
* @return {?Factory} A factory that can create a view for the path or undefined if there isn't one.
*/
function findSuitableFactoryForPath(fullPath) {
return _.find(_factories, function (factory) {
// This could get more complex in the future by searching in this order
// 1) a factory that can open the file by fullPath
// 2) a factory that can open the file by name
// 3) a factory that can open the file by filetype
return factory.canOpenFile(fullPath);
});
}
/*
* Public API
*/
exports.registerViewFactory = registerViewFactory;
exports.findSuitableFactoryForPath = findSuitableFactoryForPath;
});

1530
src/view/MainViewManager.js Normal file

File diff suppressed because it is too large Load Diff

1097
src/view/Pane.js Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved.
* Copyright (c) 2014 Adobe Systems Incorporated. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
@ -25,233 +25,34 @@
/*global define, window, $, brackets */
/**
* Manages layout of panels surrounding the editor area, and size of the editor area (but not its contents).
*
* Updates panel sizes when the window is resized. Maintains the max resizing limits for panels, based on
* currently available window size.
*
* Events:
* - editorAreaResize -- When editor-holder's size changes for any reason (including panel show/hide
* panel resize, or the window resize).
* The 2nd arg is the new editor-holder height.
* The 3rd arg is a refreshHint flag for internal EditorManager use.
* @deprecated This module provided for backwards compatibility. Use WorkspaceManager instead.
*/
define(function (require, exports, module) {
"use strict";
var AppInit = require("utils/AppInit"),
Resizer = require("utils/Resizer");
var WorkspaceManager = require("view/WorkspaceManager"),
DeprecationWarning = require("utils/DeprecationWarning");
/**
* The ".content" vertical stack (editor + all header/footer panels)
* @type {jQueryObject}
* Creates a deprecation warning event handler
* @param {!string} the event being deprecated
* @param {!string} the new event to use
*/
var $windowContent;
/**
* The "#editor-holder": has only one visible child, the current CodeMirror
* instance (or the no-editor placeholder)
* @type {jQueryObject}
*/
var $editorHolder;
/**
* Have we already started listening for the end of the ongoing window resize?
* @type {boolean}
*/
var windowResizing = false;
/**
* Calculates the available height for the full-size Editor (or the no-editor placeholder),
* accounting for the current size of all visible panels, toolbar, & status bar.
* @return {number}
*/
function calcEditorHeight() {
var availableHt = $windowContent.height();
$editorHolder.siblings().each(function (i, elem) {
var $elem = $(elem);
if ($elem.css("display") !== "none" && $elem.css("position") !== "absolute") {
availableHt -= $elem.outerHeight();
function _deprecateEvent(oldEventName, newEventName) {
DeprecationWarning.deprecateEvent(exports,
WorkspaceManager,
oldEventName,
newEventName,
"PanelManager." + oldEventName,
"MainViewManager." + newEventName);
}
});
// Clip value to 0 (it could be negative if a panel wants more space than we have)
return Math.max(availableHt, 0);
}
/** Updates panel resize limits to disallow making panels big enough to shrink editor area below 0 */
function updateResizeLimits() {
var editorAreaHeight = $editorHolder.height();
$editorHolder.siblings().each(function (i, elem) {
var $elem = $(elem);
if ($elem.css("display") === "none") {
$elem.data("maxsize", editorAreaHeight);
} else {
$elem.data("maxsize", editorAreaHeight + $elem.outerHeight());
}
});
}
/**
* Calculates a new size for editor-holder and resizes it accordingly, then and dispatches the "editorAreaResize"
* event. (The editors within are resized by EditorManager, in response to that event).
*
* @param {string=} refreshHint One of "skip", "force", or undefined. See EditorManager docs.
*/
function triggerEditorResize(refreshHint) {
// Find how much space is left for the editor
var editorAreaHeight = calcEditorHeight();
$editorHolder.height(editorAreaHeight); // affects size of "not-editor" placeholder as well
// Resize editor to fill the space
$(exports).trigger("editorAreaResize", [editorAreaHeight, refreshHint]);
}
/** Trigger editor area resize whenever the window is resized */
function handleWindowResize() {
// These are not initialized in Jasmine Spec Runner window until a test
// is run that creates a mock document.
if (!$windowContent || !$editorHolder) {
return;
}
// Immediately adjust editor's height, but skip the refresh since CodeMirror will call refresh()
// itself when it sees the window resize event
// triggerEditorResize("skip");
// FIXME (issue #4564) Workaround https://github.com/marijnh/CodeMirror/issues/1787
triggerEditorResize();
if (!windowResizing) {
windowResizing = true;
// We don't need any fancy debouncing here - we just need to react before the user can start
// resizing any panels at the new window size. So just listen for first mousemove once the
// window resize releases mouse capture.
$(window.document).one("mousemove", function () {
windowResizing = false;
updateResizeLimits();
});
}
}
/** Trigger editor area resize whenever the given panel is shown/hidden/resized */
function listenToResize($panel) {
// Update editor height when shown/hidden, & continuously as panel is resized
$panel.on("panelCollapsed panelExpanded panelResizeUpdate", function () {
triggerEditorResize();
});
// Update max size of sibling panels when shown/hidden, & at *end* of resize gesture
$panel.on("panelCollapsed panelExpanded panelResizeEnd", function () {
updateResizeLimits();
});
}
/**
* Represents a panel below the editor area (a child of ".content").
*
* @param {!jQueryObject} $panel The entire panel, including any chrome, already in the DOM.
* @param {number=} minSize Minimum height of panel in px.
*/
function Panel($panel, minSize) {
this.$panel = $panel;
Resizer.makeResizable($panel[0], Resizer.DIRECTION_VERTICAL, Resizer.POSITION_TOP, minSize, false, undefined, true);
listenToResize($panel);
}
/**
* Panel instance
* @type {jQueryObject}
*/
Panel.prototype.$panel = null;
Panel.prototype.isVisible = function () {
return this.$panel.is(":visible");
};
Panel.prototype.show = function () {
Resizer.show(this.$panel[0]);
};
Panel.prototype.hide = function () {
Resizer.hide(this.$panel[0]);
};
Panel.prototype.setVisible = function (visible) {
if (visible) {
Resizer.show(this.$panel[0]);
} else {
Resizer.hide(this.$panel[0]);
}
};
/**
* Creates a new resizable panel beneath the editor area and above the status bar footer. Panel is initially invisible.
* The panel's size & visibility are automatically saved & restored as a view-state preference.
*
* @param {!string} id Unique id for this panel. Use package-style naming, e.g. "myextension.feature.panelname"
* @param {!jQueryObject} $panel DOM content to use as the panel. Need not be in the document yet. Must have an id
* attribute, for use as a preferences key.
* @param {number=} minSize Minimum height of panel in px.
* @return {!Panel}
*/
function createBottomPanel(id, $panel, minSize) {
$panel.insertBefore("#status-bar");
$panel.hide();
updateResizeLimits(); // initialize panel's max size
return new Panel($panel, minSize);
}
/**
* Used by EditorManager to notify us of layout changes our normal panel/window listeners wouldn't detect.
* For internal use only: most code should call EditorManager.resizeEditor().
*/
function _notifyLayoutChange(refreshHint) {
triggerEditorResize(refreshHint);
updateResizeLimits();
}
// Attach to key parts of the overall UI, once created
AppInit.htmlReady(function () {
$windowContent = $(".content");
$editorHolder = $("#editor-holder");
// Sidebar is a special case: it isn't a Panel, and is not created dynamically. Need to explicitly
// listen for resize here.
listenToResize($("#sidebar"));
});
// Unit test only: allow passing in mock DOM notes, e.g. for use with SpecRunnerUtils.createMockEditor()
function _setMockDOM($mockWindowContent, $mockEditorHolder) {
$windowContent = $mockWindowContent;
$editorHolder = $mockEditorHolder;
}
// If someone adds a panel in the .content stack the old way, make sure we still listen for resize/show/hide
// (Resizer emits a deprecation warning for us - no need to log anything here)
$(Resizer).on("deprecatedPanelAdded", function (event, $panel) {
listenToResize($panel);
});
// Add this as a capture handler so we're guaranteed to run it before the editor does its own
// refresh on resize.
window.addEventListener("resize", handleWindowResize, true);
// Define public API
exports.createBottomPanel = createBottomPanel;
exports._notifyLayoutChange = _notifyLayoutChange;
exports._setMockDOM = _setMockDOM;
exports.createBottomPanel = function (id, $panel, minSize) {
DeprecationWarning.deprecationWarning("Use WorkspaceManager.createBottomPanel() instead of PanelManager.createBottomPanel().", true);
return WorkspaceManager.createBottomPanel(id, $panel, minSize);
};
// Deprecated PanelManager events
_deprecateEvent("editorAreaResize", "workspaceUpdateLayout");
});

View File

@ -44,6 +44,7 @@ define(function (require, exports, module) {
PreferencesManager = require("preferences/PreferencesManager"),
DocumentManager = require("document/DocumentManager"),
ThemeSettings = require("view/ThemeSettings"),
MainViewManager = require("view/MainViewManager"),
AppInit = require("utils/AppInit");
var prefs = PreferencesManager.getExtensionPrefs("fonts");
@ -486,7 +487,7 @@ define(function (require, exports, module) {
prefs.definePreference("fontFamily", "string", DEFAULT_FONT_FAMILY);
// Update UI when opening or closing a document
$(DocumentManager).on("currentDocumentChange", _updateUI);
$(MainViewManager).on("currentFileChange", _updateUI);
// Update UI when Brackets finishes loading
AppInit.appReady(init);

View File

@ -0,0 +1,101 @@
/*
* Copyright (c) 2014 Adobe Systems Incorporated. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
/*jslint vars: true, plusplus: true, devel: true, nomen: true, indent: 4, maxerr: 50 */
/*global define, $, window */
/**
* ViewStateManager is a singleton for views to park their global viwe state. The state is saved
* with project data but the View or View Factory is responsible for restoring the view state
* when the view is created.
*
* Views should implement `getViewState()` so that the view state can be saved and that data is cached
* for later use.
*
* Views or View Factories are responsible for restoring the view state when the view of that file is created
* by recalling the cached state. Views determine what data is store in the view state and how to restore it.
*/
define(function (require, exports, module) {
"use strict";
var _ = require("thirdparty/lodash");
/**
* The view state cache.
* @type {Object.<string,*>}
* @private
*/
var _viewStateCache = {};
/**
* resets the view state cache
*/
function reset() {
_viewStateCache = {};
}
/**
* Sets the view state for the specfied file
* @param {!File} file - the file to record the view state for
* @param {?*} viewState - any data that the view needs to restore the view state.
*/
function _setViewState(file, viewState) {
_viewStateCache[file.fullPath] = viewState;
}
/**
* Updates the view state for the specified view
* @param {!{!getFile:function():File, getViewState:function():*}} view - the to save state
* @param {?*} viewState - any data that the view needs to restore the view state.
*/
function updateViewState(view) {
if (view.getViewState) {
_setViewState(view.getFile(), view.getViewState());
}
}
/**
* gets the view state for the specified file
* @param {!File} file - the file to record the view state for
* @return {?*} whatever data that was saved earlier with a call setViewState
*/
function getViewState(file) {
return _viewStateCache[file.fullPath];
}
/**
* adds an array of view states
* @param {!object.<string, *>} viewStates - View State object to append to the current set of view states
*/
function addViewStates(viewStates) {
_viewStateCache = _.extend(_viewStateCache, viewStates);
}
/*
* Public API
*/
exports.reset = reset;
exports.updateViewState = updateViewState;
exports.getViewState = getViewState;
exports.addViewStates = addViewStates;
});

View File

@ -0,0 +1,275 @@
/*
* Copyright (c) 2014 Adobe Systems Incorporated. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
/*jslint vars: true, plusplus: true, devel: true, nomen: true, indent: 4, maxerr: 50 */
/*global define, window, $, brackets */
/**
* Manages layout of panels surrounding the editor area, and size of the editor area (but not its contents).
*
* Updates panel sizes when the window is resized. Maintains the max resizing limits for panels, based on
* currently available window size.
*
* Events:
* `workspaceUpdateLayout` When workspace size changes for any reason (including panel show/hide panel resize, or the window resize).
* The 2nd arg is the available workspace height.
* The 3rd arg is a refreshHint flag for internal use (passed in to recomputeLayout)
*/
define(function (require, exports, module) {
"use strict";
var AppInit = require("utils/AppInit"),
Resizer = require("utils/Resizer");
/**
* The ".content" vertical stack (editor + all header/footer panels)
* @type {jQueryObject}
*/
var $windowContent;
/**
* The "#editor-holder": has only one visible child, the current CodeMirror instance (or the no-editor placeholder)
* @type {jQueryObject}
*/
var $editorHolder;
/**
* Have we already started listening for the end of the ongoing window resize?
* @type {boolean}
*/
var windowResizing = false;
/**
* Calculates the available height for the full-size Editor (or the no-editor placeholder),
* accounting for the current size of all visible panels, toolbar, & status bar.
* @return {number}
*/
function calcAvailableHeight() {
var availableHt = $windowContent.height();
$editorHolder.siblings().each(function (i, elem) {
var $elem = $(elem);
if ($elem.css("display") !== "none" && $elem.css("position") !== "absolute") {
availableHt -= $elem.outerHeight();
}
});
// Clip value to 0 (it could be negative if a panel wants more space than we have)
return Math.max(availableHt, 0);
}
/** Updates panel resize limits to disallow making panels big enough to shrink editor area below 0 */
function updateResizeLimits() {
var editorAreaHeight = $editorHolder.height();
$editorHolder.siblings().each(function (i, elem) {
var $elem = $(elem);
if ($elem.css("display") === "none") {
$elem.data("maxsize", editorAreaHeight);
} else {
$elem.data("maxsize", editorAreaHeight + $elem.outerHeight());
}
});
}
/**
* Calculates a new size for editor-holder and resizes it accordingly, then and dispatches the "workspaceUpdateLayout"
* event. (The editors within are resized by EditorManager, in response to that event).
*
* @param {string=} refreshHint One of "skip", "force", or undefined. See EditorManager docs.
*/
function triggerUpdateLayout(refreshHint) {
// Find how much space is left for the editor
var editorAreaHeight = calcAvailableHeight();
$editorHolder.height(editorAreaHeight); // affects size of "not-editor" placeholder as well
// Resize editor to fill the space
$(exports).trigger("workspaceUpdateLayout", [editorAreaHeight, refreshHint]);
}
/** Trigger editor area resize whenever the window is resized */
function handleWindowResize() {
// These are not initialized in Jasmine Spec Runner window until a test
// is run that creates a mock document.
if (!$windowContent || !$editorHolder) {
return;
}
// Immediately adjust editor's height, but skip the refresh since CodeMirror will call refresh()
// itself when it sees the window resize event
// triggerUpdateLayout("skip");
// FIXME (issue #4564) Workaround https://github.com/marijnh/CodeMirror/issues/1787
triggerUpdateLayout();
if (!windowResizing) {
windowResizing = true;
// We don't need any fancy debouncing here - we just need to react before the user can start
// resizing any panels at the new window size. So just listen for first mousemove once the
// window resize releases mouse capture.
$(window.document).one("mousemove", function () {
windowResizing = false;
updateResizeLimits();
});
}
}
/** Trigger editor area resize whenever the given panel is shown/hidden/resized
* @param {!jQueryObject} $panel the jquery object in which to attach event handlers
*/
function listenToResize($panel) {
// Update editor height when shown/hidden, & continuously as panel is resized
$panel.on("panelCollapsed panelExpanded panelResizeUpdate", function () {
triggerUpdateLayout();
});
// Update max size of sibling panels when shown/hidden, & at *end* of resize gesture
$panel.on("panelCollapsed panelExpanded panelResizeEnd", function () {
updateResizeLimits();
});
}
/**
* Represents a panel below the editor area (a child of ".content").
* @constructor
* @param {!jQueryObject} $panel The entire panel, including any chrome, already in the DOM.
* @param {number=} minSize Minimum height of panel in px.
*/
function Panel($panel, minSize) {
this.$panel = $panel;
Resizer.makeResizable($panel[0], Resizer.DIRECTION_VERTICAL, Resizer.POSITION_TOP, minSize, false, undefined, true);
listenToResize($panel);
}
/**
* Dom node holding the rendered panel
* @type {jQueryObject}
*/
Panel.prototype.$panel = null;
/**
* Determines if the panel is visible
* @return {boolean} true if visible, false if not
*/
Panel.prototype.isVisible = function () {
return this.$panel.is(":visible");
};
/**
* Shows the panel
*/
Panel.prototype.show = function () {
Resizer.show(this.$panel[0]);
};
/**
* Hides the panel
*/
Panel.prototype.hide = function () {
Resizer.hide(this.$panel[0]);
};
/**
* Sets the panel's visibility state
* @param {boolean} visible true to show, false to hide
*/
Panel.prototype.setVisible = function (visible) {
if (visible) {
Resizer.show(this.$panel[0]);
} else {
Resizer.hide(this.$panel[0]);
}
};
/**
* Creates a new resizable panel beneath the editor area and above the status bar footer. Panel is initially invisible.
* The panel's size & visibility are automatically saved & restored as a view-state preference.
*
* @param {!string} id Unique id for this panel. Use package-style naming, e.g. "myextension.feature.panelname"
* @param {!jQueryObject} $panel DOM content to use as the panel. Need not be in the document yet. Must have an id
* attribute, for use as a preferences key.
* @param {number=} minSize Minimum height of panel in px.
* @return {!Panel}
*/
function createBottomPanel(id, $panel, minSize) {
$panel.insertBefore("#status-bar");
$panel.hide();
updateResizeLimits(); // initialize panel's max size
return new Panel($panel, minSize);
}
/**
* Called when an external widget has appeared and needs some of the space occupied
* by the mainview manager
* @param {boolean} refreshHint true to refresh the editor, false if not
*/
function recomputeLayout(refreshHint) {
triggerUpdateLayout(refreshHint);
updateResizeLimits();
}
/* Attach to key parts of the overall UI, once created */
AppInit.htmlReady(function () {
$windowContent = $(".content");
$editorHolder = $("#editor-holder");
// Sidebar is a special case: it isn't a Panel, and is not created dynamically. Need to explicitly
// listen for resize here.
listenToResize($("#sidebar"));
});
/* Unit test only: allow passing in mock DOM notes, e.g. for use with SpecRunnerUtils.createMockEditor() */
function _setMockDOM($mockWindowContent, $mockEditorHolder) {
$windowContent = $mockWindowContent;
$editorHolder = $mockEditorHolder;
}
/* If someone adds a panel in the .content stack the old way, make sure we still listen for resize/show/hide
* (Resizer emits a deprecation warning for us - no need to log anything here)
*/
$(Resizer).on("deprecatedPanelAdded", function (event, $panel) {
listenToResize($panel);
});
/* Add this as a capture handler so we're guaranteed to run it before the editor does its own
* refresh on resize.
*/
window.addEventListener("resize", handleWindowResize, true);
// Define public API
exports.createBottomPanel = createBottomPanel;
exports.recomputeLayout = recomputeLayout;
exports._setMockDOM = _setMockDOM;
});

View File

@ -43,7 +43,7 @@ define(function (require, exports, module) {
// Load dependent modules
var DropdownEventHandler = require("utils/DropdownEventHandler").DropdownEventHandler,
PanelManager = require("view/PanelManager"),
WorkspaceManager = require("view/WorkspaceManager"),
Menus = require("command/Menus"),
ViewUtils = require("utils/ViewUtils"),
_ = require("thirdparty/lodash");
@ -277,7 +277,7 @@ define(function (require, exports, module) {
this._dropdownEventHandler.open();
window.document.body.addEventListener("mousedown", this._onClickOutside, true);
$(PanelManager).on("editorAreaResize", this.closeDropdown);
$(WorkspaceManager).on("workspaceUpdateLayout", this.closeDropdown);
// Manage focus
this._lastFocus = window.document.activeElement;
@ -291,7 +291,7 @@ define(function (require, exports, module) {
*/
DropdownButton.prototype._onDropdownClose = function () {
window.document.body.removeEventListener("mousedown", this._onClickOutside, true);
$(PanelManager).off("editorAreaResize", this.closeDropdown);
$(WorkspaceManager).off("workspaceUpdateLayout", this.closeDropdown);
// Restore focus to old pos, unless "select" handler changed it
if (window.document.activeElement === this.$dropdown[0]) {

View File

@ -33,8 +33,10 @@ define(function (require, exports, module) {
"use strict";
var EditorManager = require("editor/EditorManager"),
MainViewManager = require("view/MainViewManager"),
KeyEvent = require("utils/KeyEvent"),
AnimationUtils = require("utils/AnimationUtils");
AnimationUtils = require("utils/AnimationUtils"),
WorkspaceManager = require("view/WorkspaceManager");
/**
* Creates a modal bar whose contents are the given template.
@ -77,9 +79,7 @@ define(function (require, exports, module) {
// to the editor here, before opening up the new modal bar. This ensures that the old
// focused item has time to react and close before the new modal bar is opened.
// See bugs #4287 and #3424
if (!EditorManager.getFocusedEditor()) {
EditorManager.focusEditor();
}
MainViewManager.focusActivePane();
if (autoClose) {
this._autoClose = true;
@ -98,15 +98,9 @@ define(function (require, exports, module) {
// Preserve scroll position of the current full editor across the editor refresh, adjusting for the
// height of the modal bar so the code doesn't appear to shift if possible.
var fullEditor = EditorManager.getCurrentFullEditor(),
scrollPos;
if (fullEditor) {
scrollPos = fullEditor.getScrollPos();
}
EditorManager.resizeEditor();
if (fullEditor) {
fullEditor._codeMirror.scrollTo(scrollPos.x, scrollPos.y + this.height());
}
MainViewManager.cacheScrollState(MainViewManager.ALL_PANES);
WorkspaceManager.recomputeLayout(); // changes available ht for editor area
MainViewManager.restoreAdjustedScrollState(MainViewManager.ALL_PANES, this.height());
}
/**
@ -160,18 +154,16 @@ define(function (require, exports, module) {
this._$root.css("top", top + "px");
}
// Preserve scroll position of the current full editor across the editor refresh, adjusting for the
// height of the modal bar so the code doesn't appear to shift if possible.
var fullEditor = EditorManager.getCurrentFullEditor(),
barHeight,
scrollPos;
if (restoreScrollPos && fullEditor) {
barHeight = this.height();
scrollPos = fullEditor.getScrollPos();
// Preserve scroll position of all visible views
// adjusting for the height of the modal bar so the code doesn't appear to shift if possible.
var barHeight = this.height();
if (restoreScrollPos) {
MainViewManager.cacheScrollState(MainViewManager.ALL_PANES);
}
EditorManager.resizeEditor();
if (restoreScrollPos && fullEditor) {
fullEditor._codeMirror.scrollTo(scrollPos.x, scrollPos.y - barHeight);
WorkspaceManager.recomputeLayout(); // changes available ht for editor area
// restore scroll position of all vies
if (restoreScrollPos) {
MainViewManager.restoreAdjustedScrollState(MainViewManager.ALL_PANES, -barHeight);
}
};
@ -223,7 +215,7 @@ define(function (require, exports, module) {
doRemove();
}
EditorManager.focusEditor();
MainViewManager.focusActivePane();
return result.promise();
};

View File

@ -37,7 +37,8 @@ define(function (require, exports, module) {
var AppInit = require("utils/AppInit"),
StatusBarHTML = require("text!widgets/StatusBar.html"),
EditorManager = require("editor/EditorManager"),
Strings = require("strings");
Strings = require("strings"),
WorkspaceManager = require("view/WorkspaceManager");
var _init = false;
@ -185,7 +186,7 @@ define(function (require, exports, module) {
if ($statusBar.is(":visible")) {
$statusBar.hide();
EditorManager.resizeEditor(); // changes available ht for editor area
WorkspaceManager.recomputeLayout();
}
}
@ -200,7 +201,7 @@ define(function (require, exports, module) {
if (!$statusBar.is(":visible")) {
$statusBar.show();
EditorManager.resizeEditor(); // changes available ht for editor area
WorkspaceManager.recomputeLayout();
}
}

View File

@ -40,6 +40,11 @@ pre {
opacity: 0.45;
}
/* Add some space between the menu and the list of tests. */
.container-fluid {
margin-top: 1.5em;
}
@media (min-width: 728px) and (max-width: 1199px) {
.navbar-fixed-top .container,
.navbar-fixed-bottom .container {

View File

@ -47,7 +47,6 @@
</head>
<body>
<div class="navbar navbar-fixed-top">
<div class="navbar-inner">
<div class="container">
@ -63,6 +62,7 @@
<li><a id="unit" href="?suite=unit">Unit</a></li>
<li><a id="integration" href="?suite=integration">Integration</a></li>
<li><a id="livepreview" href="?suite=livepreview">Live&nbsp;Preview</a></li>
<li><a id="mainview" href="?suite=mainview">Main&nbsp;View</a></li>
<li><a id="performance" href="?suite=performance">Performance</a></li>
<li><a id="extension" href="?suite=extension">Extensions</a></li>
<li><a id="reload" href="#">Reload</a></li>
@ -72,6 +72,6 @@
</div>
</div>
</div>
<div id="mock-main-view" style="position:absolute; height:1000px; width:1000px; left:-10000px; top:-10000px;"></div>
</body>
</html>

View File

@ -38,6 +38,7 @@ define(function (require, exports, module) {
require("spec/DocumentManager-test");
require("spec/DragAndDrop-test");
require("spec/Editor-test");
require("spec/EditorRedraw-test");
require("spec/EditorCommandHandlers-test");
require("spec/EditorOptionHandlers-test");
require("spec/EditorManager-test");
@ -59,10 +60,13 @@ define(function (require, exports, module) {
require("spec/LanguageManager-test");
require("spec/LiveDevelopment-test");
require("spec/LowLevelFileIO-test");
require("spec/MainViewFactory-test");
require("spec/MainViewManager-test");
require("spec/Menu-test");
require("spec/MultiRangeInlineEditor-test");
require("spec/NativeMenu-test");
require("spec/NodeConnection-test");
require("spec/Pane-test");
require("spec/PreferencesBase-test");
require("spec/PreferencesManager-test");
require("spec/ProjectManager-test");
@ -75,7 +79,9 @@ define(function (require, exports, module) {
require("spec/UpdateNotification-test");
require("spec/UrlParams-test");
require("spec/ValidationUtils-test");
require("spec/ViewFactory-test");
//require("spec/ViewCommandHandlers-test");
require("spec/ViewUtils-test");
require("spec/WorkingSetView-test");
require("spec/WorkingSetSort-test");
});

View File

@ -1498,7 +1498,7 @@ define(function (require, exports, module) {
.fail(function () { gotError = true; });
});
waitsFor(function () { return didOpen && !gotError; }, "FileViewController.addToWorkingSetAndSelect() timeout", 1000);
waitsFor(function () { return didOpen && !gotError; }, "FileViewController.openAndSelectDocument() timeout", 1000);
var rules = null;
@ -1534,7 +1534,7 @@ define(function (require, exports, module) {
.fail(function () { gotError = true; });
});
waitsFor(function () { return didOpen && !gotError; }, "FileViewController.addToWorkingSetAndSelect() timeout", 1000);
waitsFor(function () { return didOpen && !gotError; }, "FileViewController.openAndSelectDocument() timeout", 1000);
var rules = null;

View File

@ -34,6 +34,7 @@ define(function (require, exports, module) {
EditorManager, // loaded from brackets.test
DocumentModule, // loaded from brackets.test
DocumentManager, // loaded from brackets.test
MainViewManager, // loaded from brackets.test
SpecRunnerUtils = require("spec/SpecRunnerUtils");
@ -229,6 +230,7 @@ define(function (require, exports, module) {
EditorManager = testWindow.brackets.test.EditorManager;
DocumentModule = testWindow.brackets.test.DocumentModule;
DocumentManager = testWindow.brackets.test.DocumentManager;
MainViewManager = testWindow.brackets.test.MainViewManager;
SpecRunnerUtils.loadProjectInTestWindow(testPath);
});
@ -241,7 +243,9 @@ define(function (require, exports, module) {
EditorManager = null;
DocumentModule = null;
DocumentManager = null;
MainViewManager = null;
SpecRunnerUtils.closeTestWindow();
testWindow = null;
});
afterEach(function () {
@ -259,7 +263,7 @@ define(function (require, exports, module) {
describe("Dirty flag and undo", function () {
var promise, doc;
var promise;
it("should not fire dirtyFlagChange when created", function () {
var dirtyFlagListener = jasmine.createSpy();
@ -395,6 +399,7 @@ define(function (require, exports, module) {
$(doc).off("change", changeListener);
$(DocumentManager).off("dirtyFlagChange", dirtyFlagListener);
doc = null;
});
});
});
@ -480,7 +485,7 @@ define(function (require, exports, module) {
cssMasterEditor;
runs(function () {
promise = CommandManager.execute(Commands.FILE_ADD_TO_WORKING_SET, {fullPath: HTML_FILE});
promise = CommandManager.execute(Commands.CMD_ADD_TO_WORKINGSET_AND_OPEN, {fullPath: HTML_FILE});
waitsForDone(promise, "Open into working set");
});
runs(function () {
@ -489,7 +494,7 @@ define(function (require, exports, module) {
waitsForDone(promise, "Open inline editor");
});
runs(function () {
expect(DocumentManager.findInWorkingSet(CSS_FILE)).toBe(-1);
expect(MainViewManager.findInWorkingSet(MainViewManager.ACTIVE_PANE, CSS_FILE)).toBe(-1);
expect(DocumentManager.getOpenDocumentForPath(CSS_FILE)).toBeTruthy();
// Force creation of master editor for CSS file

View File

@ -33,6 +33,7 @@ define(function (require, exports, module) {
Commands, // loaded from brackets.test
DocumentCommandHandlers, // loaded from brackets.test
DocumentManager, // loaded from brackets.test
MainViewManager, // loaded from brackets.test
Dialogs, // loaded from brackets.test
FileSystem, // loaded from brackets.test
FileViewController, // loaded from brackets.test
@ -65,6 +66,7 @@ define(function (require, exports, module) {
Commands = testWindow.brackets.test.Commands;
DocumentCommandHandlers = testWindow.brackets.test.DocumentCommandHandlers;
DocumentManager = testWindow.brackets.test.DocumentManager;
MainViewManager = testWindow.brackets.test.MainViewManager;
Dialogs = testWindow.brackets.test.Dialogs;
FileSystem = testWindow.brackets.test.FileSystem;
FileViewController = testWindow.brackets.test.FileViewController;
@ -78,8 +80,10 @@ define(function (require, exports, module) {
Commands = null;
DocumentCommandHandlers = null;
DocumentManager = null;
MainViewManager = null;
Dialogs = null;
FileViewController = null;
EditorManager = null;
SpecRunnerUtils.closeTestWindow();
});
@ -97,7 +101,7 @@ define(function (require, exports, module) {
// Call closeAll() directly. Some tests set a spy on the save as
// dialog preventing SpecRunnerUtils.closeAllFiles() from
// working properly.
testWindow.brackets.test.DocumentManager.closeAll();
testWindow.brackets.test.MainViewManager._closeAll(testWindow.brackets.test.MainViewManager.ALL_PANES);
});
});
@ -126,8 +130,8 @@ define(function (require, exports, module) {
});
/** @return {Array.<Document>} */
function getWorkingSetDocs() {
return DocumentManager.getWorkingSet().map(function (file) {
function getOpenDocsFromWorkingSet() {
return MainViewManager.getWorkingSet(MainViewManager.ALL_PANES).map(function (file) {
return DocumentManager.getOpenDocumentForPath(file.fullPath);
});
}
@ -199,8 +203,8 @@ define(function (require, exports, module) {
expect(noLongerUntitledDocument.isDirty).toBe(false);
expect(noLongerUntitledDocument.isUntitled()).toBe(false);
expect(noLongerUntitledDocument.file.fullPath).toEqual(newFilePath);
expect(DocumentManager.findInWorkingSet(newFilePath)).toBeGreaterThan(-1);
expect(DocumentManager.getWorkingSet().length).toEqual(1); // no remnant of untitled doc left
expect(MainViewManager.findInWorkingSet(MainViewManager.ALL_PANES, newFilePath)).toNotEqual(-1);
expect(MainViewManager.getWorkingSet(MainViewManager.ALL_PANES).length).toEqual(1); // no remnant of untitled doc left
// Verify file exists, & clean up
expectAndDelete(newFilePath);
@ -265,8 +269,8 @@ define(function (require, exports, module) {
expect(noLongerUntitledDocument.isDirty).toBe(false);
expect(noLongerUntitledDocument.isUntitled()).toBe(false);
expect(noLongerUntitledDocument.file.fullPath).toEqual(newFilePath);
expect(DocumentManager.findInWorkingSet(newFilePath)).toBeGreaterThan(-1);
expect(DocumentManager.getWorkingSet().length).toEqual(1); // no remnant of untitled doc left
expect(MainViewManager.findInWorkingSet(MainViewManager.ALL_PANES, newFilePath)).toNotEqual(-1);
expect(MainViewManager.getWorkingSet(MainViewManager.ALL_PANES).length).toEqual(1); // no remnant of untitled doc left
// Verify file exists, & clean up
expectAndDelete(newFilePath);
@ -302,7 +306,7 @@ define(function (require, exports, module) {
});
runs(function () {
expect(DocumentManager.getWorkingSet().length).toEqual(0);
expect(MainViewManager.getWorkingSet(MainViewManager.ALL_PANES).length).toEqual(0);
// Verify file exists, & clean up
expectAndDelete(newFilePath);
@ -335,7 +339,7 @@ define(function (require, exports, module) {
expect(untitledDocument.isDirty).toBe(true);
expect(untitledDocument.isUntitled()).toBe(true);
expect(DocumentManager.findInWorkingSet(untitledDocument.file.fullPath)).toBeGreaterThan(-1);
expect(MainViewManager.findInWorkingSet(MainViewManager.ALL_PANES, untitledDocument.file.fullPath)).toNotEqual(-1);
});
});
@ -369,7 +373,7 @@ define(function (require, exports, module) {
expect(untitledDocument.isDirty).toBe(true);
expect(untitledDocument.isUntitled()).toBe(true);
expect(DocumentManager.findInWorkingSet(untitledDocument.file.fullPath)).toBeGreaterThan(-1);
expect(MainViewManager.findInWorkingSet(MainViewManager.ALL_PANES, untitledDocument.file.fullPath)).toNotEqual(-1);
});
});
@ -395,7 +399,7 @@ define(function (require, exports, module) {
});
runs(function () {
expect(DocumentManager.getWorkingSet().length).toEqual(0);
expect(MainViewManager.getWorkingSet(MainViewManager.ALL_PANES).length).toEqual(0);
});
});
@ -413,7 +417,7 @@ define(function (require, exports, module) {
});
runs(function () {
expect(DocumentManager.getWorkingSet().length).toEqual(0);
expect(MainViewManager.getWorkingSet(MainViewManager.ALL_PANES).length).toEqual(0);
});
});
@ -424,28 +428,28 @@ define(function (require, exports, module) {
createUntitled(3);
runs(function () {
var workingSetDocs = getWorkingSetDocs();
expect(workingSetDocs.length).toEqual(3);
var workingSetListDocs = getOpenDocsFromWorkingSet();
expect(workingSetListDocs.length).toEqual(3);
// Expect non-conflicting dummy paths
expect(workingSetDocs[0].file.fullPath).not.toBe(workingSetDocs[1].file.fullPath);
expect(workingSetDocs[0].file.fullPath).not.toBe(workingSetDocs[2].file.fullPath);
expect(workingSetDocs[1].file.fullPath).not.toBe(workingSetDocs[2].file.fullPath);
expect(workingSetListDocs[0].file.fullPath).not.toBe(workingSetListDocs[1].file.fullPath);
expect(workingSetListDocs[0].file.fullPath).not.toBe(workingSetListDocs[2].file.fullPath);
expect(workingSetListDocs[1].file.fullPath).not.toBe(workingSetListDocs[2].file.fullPath);
// Expect separate Document objects
expect(workingSetDocs[0]).not.toBe(workingSetDocs[1]);
expect(workingSetDocs[0]).not.toBe(workingSetDocs[2]);
expect(workingSetDocs[1]).not.toBe(workingSetDocs[2]);
expect(workingSetListDocs[0]).not.toBe(workingSetListDocs[1]);
expect(workingSetListDocs[0]).not.toBe(workingSetListDocs[2]);
expect(workingSetListDocs[1]).not.toBe(workingSetListDocs[2]);
// Expect all Documents to be untitled
workingSetDocs.forEach(function (doc) {
workingSetListDocs.forEach(function (doc) {
expect(doc.isUntitled()).toBe(true);
});
// Expect separate, unique content
expect(workingSetDocs[0].getText()).toBe("0");
expect(workingSetDocs[1].getText()).toBe("1");
expect(workingSetDocs[2].getText()).toBe("2");
expect(workingSetListDocs[0].getText()).toBe("0");
expect(workingSetListDocs[1].getText()).toBe("1");
expect(workingSetListDocs[2].getText()).toBe("2");
});
});
@ -469,17 +473,17 @@ define(function (require, exports, module) {
runs(function () {
// Expect clean Documents with correct, unique non-dummy paths
var workingSetDocs = getWorkingSetDocs();
expect(workingSetDocs.length).toEqual(3);
var workingSetListDocs = getOpenDocsFromWorkingSet();
expect(workingSetListDocs.length).toEqual(3);
workingSetDocs.forEach(function (doc, i) {
workingSetListDocs.forEach(function (doc, i) {
expect(doc.isUntitled()).toBe(false);
expect(doc.isDirty).toBe(false);
expect(doc.file.fullPath).toBe(getFilename(i));
});
// Verify files exist & clean up
workingSetDocs.forEach(function (doc, i) {
workingSetListDocs.forEach(function (doc, i) {
expectAndDelete(getFilename(i));
});
});
@ -508,7 +512,7 @@ define(function (require, exports, module) {
});
runs(function () {
expect(DocumentManager.getWorkingSet().length).toEqual(0);
expect(MainViewManager.getWorkingSet(MainViewManager.ALL_PANES).length).toEqual(0);
// Verify files exist & clean up
[0, 1, 2].forEach(function (i) {
@ -546,10 +550,10 @@ define(function (require, exports, module) {
runs(function () {
// Expect *only* first Document was saved - others remain untitled & dirty
var workingSetDocs = getWorkingSetDocs();
expect(workingSetDocs.length).toEqual(3);
var workingSetListDocs = getOpenDocsFromWorkingSet();
expect(workingSetListDocs.length).toEqual(3);
workingSetDocs.forEach(function (doc, i) {
workingSetListDocs.forEach(function (doc, i) {
if (i === 0) {
// First file was saved when we confirmed save dialog
expect(doc.isUntitled()).toBe(false);
@ -601,10 +605,10 @@ define(function (require, exports, module) {
runs(function () {
// Expect *all* Documents still open, and *only* first Document was saved
var workingSetDocs = getWorkingSetDocs();
expect(workingSetDocs.length).toEqual(3);
var workingSetListDocs = getOpenDocsFromWorkingSet();
expect(workingSetListDocs.length).toEqual(3);
workingSetDocs.forEach(function (doc, i) {
workingSetListDocs.forEach(function (doc, i) {
if (i === 0) {
// First file was saved when we confirmed save dialog
expect(doc.isUntitled()).toBe(false);
@ -824,7 +828,7 @@ define(function (require, exports, module) {
runs(function () {
// New file should not appear in working set
expect(DocumentManager.findInWorkingSet(newFilePath)).toEqual(-1);
expect(MainViewManager.findInWorkingSet(MainViewManager.ALL_PANES, newFilePath)).toEqual(-1);
// Verify file exists & clean it up
expectAndDelete(newFilePath);
@ -862,8 +866,8 @@ define(function (require, exports, module) {
runs(function () {
// Only new file should appear in working set
expect(DocumentManager.findInWorkingSet(newFilePath)).toBeGreaterThan(-1);
expect(DocumentManager.findInWorkingSet(filePath)).toEqual(-1);
expect(MainViewManager.findInWorkingSet(MainViewManager.ALL_PANES, newFilePath)).toNotEqual(-1);
expect(MainViewManager.findInWorkingSet(MainViewManager.ALL_PANES, filePath)).toEqual(-1);
// Verify file exists & clean it up
expectAndDelete(newFilePath);
@ -897,12 +901,12 @@ define(function (require, exports, module) {
});
runs(function () {
expect(DocumentManager.findInWorkingSet(newFilePath)).toEqual(-1);
expect(MainViewManager.findInWorkingSet(MainViewManager.ALL_PANES, newFilePath)).toEqual(-1);
});
});
it("should maintain order within Working Set after Save As", function () {
var index,
var views,
targetDoc;
runs(function () {
@ -913,7 +917,7 @@ define(function (require, exports, module) {
});
runs(function () {
index = DocumentManager.findInWorkingSet(filePath);
views = MainViewManager.findInAllWorkingSets(filePath);
targetDoc = DocumentManager.getOpenDocumentForPath(filePath);
});
@ -926,8 +930,7 @@ define(function (require, exports, module) {
runs(function () {
// save the file opened above to a different filename
DocumentManager.setCurrentDocument(targetDoc);
MainViewManager._edit(MainViewManager.ACTIVE_PANE, targetDoc);
spyOn(FileSystem, 'showSaveDialog').andCallFake(function (dialogTitle, initialPath, proposedNewName, callback) {
callback(undefined, newFilePath);
});
@ -938,8 +941,8 @@ define(function (require, exports, module) {
runs(function () {
// New file should appear in working set at old file's index; old file shouldn't appear at all
expect(DocumentManager.findInWorkingSet(newFilePath)).toEqual(index);
expect(DocumentManager.findInWorkingSet(filePath)).toEqual(-1);
expect(MainViewManager.findInAllWorkingSets(newFilePath)).toEqual(views);
expect(MainViewManager.findInWorkingSet(MainViewManager.ALL_PANES, filePath)).toEqual(-1);
// Verify file exists & clean it up
expectAndDelete(newFilePath);
@ -1102,6 +1105,10 @@ define(function (require, exports, module) {
});
});
/*
TODO: Disabled until image support is added for splitview
describe("Opens image file and validates EditorManager APIs", function () {
it("should return null after opening an image", function () {
var path = testPath + "/couz.png",
@ -1115,7 +1122,7 @@ define(function (require, exports, module) {
expect(EditorManager.getActiveEditor()).toEqual(null);
expect(EditorManager.getCurrentFullEditor()).toEqual(null);
expect(EditorManager.getFocusedEditor()).toEqual(null);
expect(EditorManager.getCurrentlyViewedPath()).toEqual(path);
expect(MainViewManager.getCurrentlyViewedPath(MainViewManager.ACTIVE_PANE)).toEqual(path);
var d = DocumentManager.getCurrentDocument();
expect(d).toEqual(null);
});
@ -1187,7 +1194,7 @@ define(function (require, exports, module) {
});
});
*/
describe("Open a text file while a text file is open", function () {
it("should fire currentDocumentChange and activeEditorChange events", function () {
@ -1267,7 +1274,8 @@ define(function (require, exports, module) {
e = EditorManager.getFocusedEditor();
expect(e.document.file.fullPath).toBe(path);
expect(EditorManager.getCurrentlyViewedPath()).toEqual(path);
e = EditorManager.getCurrentFullEditor();
expect(e.document.file.fullPath).toBe(path);
});
});
});

View File

@ -40,6 +40,7 @@ define(function (require, exports, module) {
this.category = "integration";
var testPath = SpecRunnerUtils.getTestPath("/spec/DocumentCommandHandlers-test-files"),
testFile = testPath + "/test.js",
testWindow,
_$,
promise;
@ -63,6 +64,7 @@ define(function (require, exports, module) {
CommandManager = null;
Commands = null;
DocumentManager = null;
EditorManager = null;
SpecRunnerUtils.closeTestWindow();
});
@ -80,48 +82,46 @@ define(function (require, exports, module) {
// Call closeAll() directly. Some tests set a spy on the save as
// dialog preventing SpecRunnerUtils.closeAllFiles() from
// working properly.
testWindow.brackets.test.DocumentManager.closeAll();
testWindow.brackets.test.MainViewManager._closeAll(testWindow.brackets.test.MainViewManager.ALL_PANES);
});
});
describe("_clearCurrentDocument ", function () {
it("should fire currentDocumentChange", function () {
var docChangeListener = jasmine.createSpy();
describe("openDocument ", function () {
it("Should report document in open documents list", function () {
runs(function () {
_$(DocumentManager).on("currentDocumentChange", docChangeListener);
expect(docChangeListener.callCount).toBe(0);
promise = CommandManager.execute(Commands.FILE_OPEN, { fullPath: testPath + "/test.js" });
promise = CommandManager.execute(Commands.FILE_OPEN, { fullPath: testFile });
waitsForDone(promise, Commands.FILE_OPEN);
});
runs(function () {
expect(docChangeListener.callCount).toBe(1);
DocumentManager._clearCurrentDocument();
expect(docChangeListener.callCount).toBe(2);
_$(DocumentManager).off("currentDocumentChange", docChangeListener);
});
});
});
describe("After _clearCurrentDocument ", function () {
it("getCurrentDocument should return null ", function () {
runs(function () {
promise = CommandManager.execute(Commands.FILE_OPEN, { fullPath: testPath + "/test.js" });
waitsForDone(promise, Commands.FILE_OPEN);
});
runs(function () {
expect(DocumentManager.getCurrentDocument()).toBeTruthy();
DocumentManager._clearCurrentDocument();
expect(DocumentManager.getCurrentDocument()).toBe(null);
expect(DocumentManager.getOpenDocumentForPath(testFile)).toBeTruthy();
expect(DocumentManager.getAllOpenDocuments().length).toEqual(1);
expect(DocumentManager.getCurrentDocument().file.fullPath).toEqual(testFile);
});
runs(function () {
promise = DocumentManager.getDocumentText({ fullPath: testFile });
waitsForDone(promise, "DocumentManager.getDocumentText");
});
runs(function () {
promise = CommandManager.execute(Commands.FILE_CLOSE_ALL);
waitsForDone(promise, Commands.FILE_CLOSE_ALL);
});
runs(function () {
expect(DocumentManager.getAllOpenDocuments().length).toEqual(0);
expect(DocumentManager.getCurrentDocument()).toBeFalsy();
});
});
it("Should create a new untitled document", function () {
runs(function () {
var doc = DocumentManager.createUntitledDocument(1, ".txt");
expect(doc).toBeTruthy();
});
});
});
});
});

View File

@ -32,6 +32,7 @@ define(function (require, exports, module) {
var DocumentManager, // loaded from brackets.test
DragAndDrop, // loaded from brackets.test
EditorManager, // loaded from brackets.test
MainViewManager, // loaded from brackets.test
SpecRunnerUtils = require("spec/SpecRunnerUtils");
@ -52,6 +53,7 @@ define(function (require, exports, module) {
DocumentManager = testWindow.brackets.test.DocumentManager;
DragAndDrop = testWindow.brackets.test.DragAndDrop;
EditorManager = testWindow.brackets.test.EditorManager;
MainViewManager = testWindow.brackets.test.MainViewManager;
});
});
@ -60,6 +62,7 @@ define(function (require, exports, module) {
DocumentManager = null;
DragAndDrop = null;
EditorManager = null;
MainViewManager = null;
SpecRunnerUtils.closeTestWindow();
});
@ -77,11 +80,17 @@ define(function (require, exports, module) {
// Call closeAll() directly. Some tests set a spy on the save as
// dialog preventing SpecRunnerUtils.closeAllFiles() from
// working properly.
testWindow.brackets.test.DocumentManager.closeAll();
testWindow.brackets.test.MainViewManager._closeAll(testWindow.brackets.test.MainViewManager.ALL_PANES);
});
});
describe("Testing openDroppedFiles function", function () {
it("should activate a pane on drag over", function () {
MainViewManager.setLayoutScheme(1, 2);
var $paneEl = _$("#second-pane");
$paneEl.triggerHandler("dragover");
expect(MainViewManager.getActivePaneId()).toBe("second-pane");
});
it("should NOT open any image file when a text file is in the dropped file list", function () {
var jsFilePath = testPath + "/test.js";
@ -94,7 +103,7 @@ define(function (require, exports, module) {
runs(function () {
var editor = EditorManager.getActiveEditor();
expect(editor.document.file.fullPath).toBe(jsFilePath);
expect(EditorManager.getCurrentlyViewedPath()).toEqual(jsFilePath);
expect(MainViewManager.getCurrentlyViewedPath(MainViewManager.ACTIVE_PANE)).toEqual(jsFilePath);
});
});
@ -108,7 +117,7 @@ define(function (require, exports, module) {
runs(function () {
var editor = EditorManager.getActiveEditor();
expect(editor).toBe(null);
expect(EditorManager.getCurrentlyViewedPath()).toEqual(path);
expect(MainViewManager.getCurrentlyViewedPath(MainViewManager.ACTIVE_PANE)).toEqual(path);
});
});
@ -123,10 +132,23 @@ define(function (require, exports, module) {
runs(function () {
var editor = EditorManager.getActiveEditor();
expect(editor).toBe(null);
expect(EditorManager.getCurrentlyViewedPath()).toEqual(lastImagePath);
expect(MainViewManager.getCurrentlyViewedPath(MainViewManager.ACTIVE_PANE)).toEqual(lastImagePath);
});
});
it("should add images to the working set when they dropped from outside the project", function () {
var imagesPath = SpecRunnerUtils.getTestPath("/spec/test-image-files");
runs(function () {
var files = [imagesPath + "/thermo.jpg", imagesPath + "/check.png"];
promise = DragAndDrop.openDroppedFiles(files);
waitsForDone(promise, "opening last image file from the dropped files");
});
runs(function () {
expect(MainViewManager.findInWorkingSet(MainViewManager.ALL_PANES, imagesPath + "/thermo.jpg")).toNotEqual(-1);
expect(MainViewManager.findInWorkingSet(MainViewManager.ALL_PANES, imagesPath + "/check.png")).toNotEqual(-1);
});
});
});
});
});

View File

@ -0,0 +1,7 @@
function testMe() {
console.log("this is a test");
}
function main() {
testMe();
}

View File

@ -131,7 +131,7 @@ define(function (require, exports, module) {
var promise;
runs(function () {
promise = CommandManager.execute(Commands.FILE_ADD_TO_WORKING_SET, {fullPath: testPath + "/test.html"});
promise = CommandManager.execute(Commands.CMD_ADD_TO_WORKINGSET_AND_OPEN, {fullPath: testPath + "/test.html"});
waitsForDone(promise, "Open into working set");
});
@ -3759,6 +3759,29 @@ define(function (require, exports, module) {
});
});
describe("Editor Navigation Commands", function () {
it("should jump to definition", function () {
var promise,
selection;
runs(function () {
promise = CommandManager.execute(Commands.CMD_ADD_TO_WORKINGSET_AND_OPEN, {fullPath: testPath + "/test.js"});
waitsForDone(promise, "Open into working set");
});
runs(function () {
myEditor = EditorManager.getCurrentFullEditor();
myEditor.setCursorPos({line: 5, ch: 8});
promise = CommandManager.execute(Commands.NAVIGATE_JUMPTO_DEFINITION);
waitsForDone(promise, "Jump To Definition");
});
runs(function () {
selection = myEditor.getSelection();
expect(selection).toEqual({start: {line: 0, ch: 9},
end: {line: 0, ch: 15},
reversed: false});
});
});
});
describe("Open Line Above and Below - inline editor", function () {

View File

@ -29,14 +29,13 @@ define(function (require, exports, module) {
'use strict';
var EditorManager = require("editor/EditorManager"),
PanelManager = require("view/PanelManager"),
WorkspaceManager = require("view/WorkspaceManager"),
MainViewManager = require("view/MainViewManager"),
ViewStateManager = require("view/ViewStateManager"),
SpecRunnerUtils = require("spec/SpecRunnerUtils");
describe("EditorManager", function () {
describe("resizeEditor() flag options", function () {
var testEditor, testDoc, $root, $fakeContentDiv;
var pane, testEditor, testDoc, $fakeContentDiv, $fakeHolder;
beforeEach(function () {
// Normally the editor holder would be created inside a "content" div, which is
// used in the available height calculation. We create a fake content div just to
@ -45,165 +44,111 @@ define(function (require, exports, module) {
.css("height", "200px")
.appendTo(document.body);
// createMockEditor() creates the mock-editor-holder, and links EditorManager/PanelManager
// to it (and links PanelManager to our content div)
var mock = SpecRunnerUtils.createMockEditor("");
// move newly created mock-editor-holder into the content div we created above
$("#mock-editor-holder")
$fakeHolder = SpecRunnerUtils.createMockElement()
.css("width", "1000px")
.attr("id", "hidden-editors")
.appendTo($fakeContentDiv);
testEditor = mock.editor;
testDoc = mock.doc;
$root = $(testEditor.getRootElement());
testDoc._masterEditor = testEditor;
EditorManager._doShow(testDoc);
pane = SpecRunnerUtils.createMockPane($fakeHolder);
testDoc = SpecRunnerUtils.createMockDocument("");
});
afterEach(function () {
$fakeHolder.remove();
$fakeHolder = null;
$fakeContentDiv.remove();
$fakeContentDiv = null;
SpecRunnerUtils.destroyMockEditor(testDoc);
testEditor = null;
testDoc = null;
$root = null;
pane = null;
ViewStateManager.reset();
});
// force cases
it("should refresh if force is specified even if no width or height change", function () {
$root.height(200); // same as content div, so shouldn't be detected as a change
$root.width(200);
EditorManager.resizeEditor(); // cache the width
describe("Create Editors", function () {
spyOn(testEditor, "refreshAll");
PanelManager._notifyLayoutChange(EditorManager.REFRESH_FORCE);
expect(testEditor.refreshAll).toHaveBeenCalled();
it("should create a new editor for a document and add it to a pane", function () {
spyOn(pane, "addView");
EditorManager.openDocument(testDoc, pane);
expect(pane.addView).toHaveBeenCalled();
});
it("should refresh if force is specified when width changed but height hasn't", function () {
$root.height(200); // same as content div, so shouldn't be detected as a change
$root.width(200);
EditorManager.resizeEditor(); // cache the width
$root.width(300); // change the width
spyOn(testEditor, "refreshAll");
PanelManager._notifyLayoutChange(EditorManager.REFRESH_FORCE);
expect(testEditor.refreshAll).toHaveBeenCalled();
it("should use an existing editor for a document and show the editor", function () {
spyOn(pane, "addView");
spyOn(pane, "showView");
var editor = SpecRunnerUtils.createEditorInstance(testDoc, pane.$el);
EditorManager.openDocument(testDoc, pane);
expect(pane.addView).toHaveBeenCalled();
expect(pane.showView).toHaveBeenCalled();
expect(pane.addView.calls[0].args[0]).toEqual(editor);
});
it("should refresh if force is specified when height changed but width hasn't", function () {
$root.height(200); // same as content div, so shouldn't be detected as a change
$root.width(200);
EditorManager.resizeEditor(); // cache the width
$root.height(300); // change the height (to be different from content div)
spyOn(testEditor, "refreshAll");
PanelManager._notifyLayoutChange(EditorManager.REFRESH_FORCE);
expect(testEditor.refreshAll).toHaveBeenCalled();
});
it("should refresh if force is specified when both height and width changed", function () {
$root.height(200); // same as content div, so shouldn't be detected as a change
$root.width(200);
EditorManager.resizeEditor(); // cache the width
$root.height(300); // change the height (to be different from content div)
$root.width(300); // change the width
spyOn(testEditor, "refreshAll");
PanelManager._notifyLayoutChange(EditorManager.REFRESH_FORCE);
expect(testEditor.refreshAll).toHaveBeenCalled();
});
describe("ViewStateManager", function () {
var pane, testEditor, testDoc, $fakeContentDiv, $fakeHolder;
beforeEach(function () {
// Normally the editor holder would be created inside a "content" div, which is
// used in the available height calculation. We create a fake content div just to
// hold the height, and we'll place the editor holder in it.
$fakeContentDiv = $("<div class='content'/>")
.css("height", "200px")
.appendTo(document.body);
// skip cases
it("should NOT refresh if skip is specified if no width or height change", function () {
$root.height(200); // same as content div, so shouldn't be detected as a change
$root.width(200);
EditorManager.resizeEditor(); // cache the width
$fakeHolder = SpecRunnerUtils.createMockElement()
.css("width", "1000px")
.attr("id", "hidden-editors")
.appendTo($fakeContentDiv);
spyOn(testEditor, "refreshAll");
PanelManager._notifyLayoutChange(EditorManager.REFRESH_SKIP);
expect(testEditor.refreshAll).not.toHaveBeenCalled();
pane = SpecRunnerUtils.createMockPane($fakeHolder);
testDoc = SpecRunnerUtils.createMockDocument("");
});
afterEach(function () {
$fakeHolder.remove();
$fakeHolder = null;
it("should NOT refresh if skip is specified when width changed but height hasn't", function () {
$root.height(200); // same as content div, so shouldn't be detected as a change
$root.width(200);
EditorManager.resizeEditor(); // cache the width
$root.width(300); // change the width
$fakeContentDiv.remove();
$fakeContentDiv = null;
spyOn(testEditor, "refreshAll");
PanelManager._notifyLayoutChange(EditorManager.REFRESH_SKIP);
expect(testEditor.refreshAll).not.toHaveBeenCalled();
SpecRunnerUtils.destroyMockEditor(testDoc);
testEditor = null;
testDoc = null;
pane = null;
ViewStateManager.reset();
});
it("should NOT refresh if skip is specified when height changed but width hasn't", function () {
$root.height(200); // same as content div, so shouldn't be detected as a change
$root.width(200);
EditorManager.resizeEditor(); // cache the width
$root.height(300); // change the height (to be different from content div)
spyOn(testEditor, "refreshAll");
PanelManager._notifyLayoutChange(EditorManager.REFRESH_SKIP);
expect(testEditor.refreshAll).not.toHaveBeenCalled();
describe("Save/Restore View State", function () {
it("should remember a file's view state", function () {
ViewStateManager.addViewStates({ a: "1234" });
expect(ViewStateManager.getViewState({fullPath: "a"})).toEqual("1234");
ViewStateManager.addViewStates({ b: "Jeff was here" });
expect(ViewStateManager.getViewState({fullPath: "B"})).toBeUndefined();
expect(ViewStateManager.getViewState({fullPath: "b"})).toEqual("Jeff was here");
});
it("should NOT refresh if skip is specified when both height and width changed", function () {
$root.height(200); // same as content div, so shouldn't be detected as a change
$root.width(200);
EditorManager.resizeEditor(); // cache the width
$root.height(300); // change the height (to be different from content div)
$root.width(300); // change the width
spyOn(testEditor, "refreshAll");
PanelManager._notifyLayoutChange(EditorManager.REFRESH_SKIP);
expect(testEditor.refreshAll).not.toHaveBeenCalled();
it("should extend the view state cache", function () {
ViewStateManager.addViewStates({ a: "1234" });
ViewStateManager.addViewStates({ b: "5678" });
expect(ViewStateManager.getViewState({fullPath: "a"})).toEqual("1234");
expect(ViewStateManager.getViewState({fullPath: "b"})).toEqual("5678");
});
// unspecified cases
it("should NOT refresh if unspecified if no width or height change", function () {
$root.height(200); // same as content div, so shouldn't be detected as a change
$root.width(200);
EditorManager.resizeEditor(); // cache the width
spyOn(testEditor, "refreshAll");
PanelManager._notifyLayoutChange();
expect(testEditor.refreshAll).not.toHaveBeenCalled();
it("should reset the view state cache", function () {
ViewStateManager.addViewStates({ a: "1234" });
ViewStateManager.addViewStates({ b: "5678" });
ViewStateManager.reset();
expect(ViewStateManager.getViewState({fullPath: "a"})).toBeUndefined();
expect(ViewStateManager.getViewState({fullPath: "b"})).toBeUndefined();
});
it("should refresh if unspecified when width changed but height hasn't", function () {
$root.height(200); // same as content div, so shouldn't be detected as a change
$root.width(200);
EditorManager.resizeEditor(); // cache the width
$root.width(300); // change the width
spyOn(testEditor, "refreshAll");
PanelManager._notifyLayoutChange();
expect(testEditor.refreshAll).toHaveBeenCalled();
});
it("should refresh if unspecified when height changed but width hasn't", function () {
$root.height(200); // same as content div, so shouldn't be detected as a change
$root.width(200);
EditorManager.resizeEditor(); // cache the width
$root.height(300); // change the height (to be different from content div)
spyOn(testEditor, "refreshAll");
PanelManager._notifyLayoutChange();
expect(testEditor.refreshAll).toHaveBeenCalled();
});
it("should refresh if unspecified when both height and width changed", function () {
$root.height(200); // same as content div, so shouldn't be detected as a change
$root.width(200);
EditorManager.resizeEditor(); // cache the width
$root.height(300); // change the height (to be different from content div)
$root.width(300); // change the width
spyOn(testEditor, "refreshAll");
PanelManager._notifyLayoutChange();
expect(testEditor.refreshAll).toHaveBeenCalled();
it("should update the view state cache", function () {
var myView = {
getFile: function () {
return {
fullPath: "a"
};
},
getViewState: function () {
return "1234";
}
};
ViewStateManager.updateViewState(myView);
expect(ViewStateManager.getViewState({fullPath: "a"})).toEqual("1234");
});
});
});

View File

@ -168,7 +168,7 @@ define(function (require, exports, module) {
// Helper functions to open editors / toggle options
function openEditor(fullPath) {
runs(function () {
var promise = CommandManager.execute(Commands.FILE_ADD_TO_WORKING_SET, {fullPath: fullPath});
var promise = CommandManager.execute(Commands.CMD_ADD_TO_WORKINGSET_AND_OPEN, {fullPath: fullPath});
waitsForDone(promise, "Open into working set");
});
}

View File

@ -0,0 +1,182 @@
/*
* Copyright (c) 2012 Adobe Systems Incorporated. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
/*jslint vars: true, plusplus: true, devel: true, browser: true, nomen: true, indent: 4, maxerr: 50 */
/*global define, describe, it, spyOn, expect, beforeEach, afterEach, waitsFor, runs, $ */
define(function (require, exports, module) {
'use strict';
var EditorManager = require("editor/EditorManager"),
WorkspaceManager = require("view/WorkspaceManager"),
MainViewManager = require("view/MainViewManager"),
SpecRunnerUtils = require("spec/SpecRunnerUtils");
describe("Editor Redrawing", function () {
var testEditor, testDoc, $root;
beforeEach(function () {
testDoc = SpecRunnerUtils.createMockDocument("");
MainViewManager._edit(MainViewManager.ACTIVE_PANE, testDoc);
testEditor = testDoc._masterEditor;
$root = $(testEditor.getRootElement());
WorkspaceManager._setMockDOM($("#mock-main-view"), $root.parent());
});
afterEach(function () {
MainViewManager._closeAll(MainViewManager.ALL_PANES);
SpecRunnerUtils.destroyMockEditor(testDoc);
testEditor = null;
testDoc = null;
$root = null;
WorkspaceManager._setMockDOM(undefined, undefined);
});
// force cases
describe("Editor Redraw Perforamnce", function () {
it("should refresh if force is specified even if no width or height change", function () {
$root.height(200); // same as content div, so shouldn't be detected as a change
$root.width(200);
spyOn(testEditor, "refreshAll");
WorkspaceManager.recomputeLayout(true);
expect(testEditor.refreshAll).toHaveBeenCalled();
});
it("should refresh if force is specified when width changed but height hasn't", function () {
$root.height(200); // same as content div, so shouldn't be detected as a change
$root.width(200);
WorkspaceManager.recomputeLayout();
$root.width(300); // change the width
spyOn(testEditor, "refreshAll");
WorkspaceManager.recomputeLayout(true);
expect(testEditor.refreshAll).toHaveBeenCalled();
});
it("should refresh if force is specified when height changed but width hasn't", function () {
$root.height(200); // same as content div, so shouldn't be detected as a change
$root.width(200);
WorkspaceManager.recomputeLayout();
$root.height(300); // change the height (to be different from content div)
spyOn(testEditor, "refreshAll");
WorkspaceManager.recomputeLayout(true);
expect(testEditor.refreshAll).toHaveBeenCalled();
});
it("should refresh if force is specified when both height and width changed", function () {
$root.height(200); // same as content div, so shouldn't be detected as a change
$root.width(200);
WorkspaceManager.recomputeLayout();
$root.height(300); // change the height (to be different from content div)
$root.width(300); // change the width
spyOn(testEditor, "refreshAll");
WorkspaceManager.recomputeLayout(true);
expect(testEditor.refreshAll).toHaveBeenCalled();
});
// skip cases
it("should NOT refresh if skip is specified if no width or height change", function () {
$root.height(200); // same as content div, so shouldn't be detected as a change
$root.width(200);
WorkspaceManager.recomputeLayout();
spyOn(testEditor, "refreshAll");
WorkspaceManager.recomputeLayout(false);
expect(testEditor.refreshAll).not.toHaveBeenCalled();
});
it("should NOT refresh if skip is specified when width changed but height hasn't", function () {
$root.height(200); // same as content div, so shouldn't be detected as a change
$root.width(200);
WorkspaceManager.recomputeLayout();
$root.width(300); // change the width
spyOn(testEditor, "refreshAll");
WorkspaceManager.recomputeLayout(false);
expect(testEditor.refreshAll).not.toHaveBeenCalled();
});
it("should NOT refresh if skip is specified when height changed but width hasn't", function () {
$root.height(200); // same as content div, so shouldn't be detected as a change
$root.width(200);
WorkspaceManager.recomputeLayout();
$root.height(300); // change the height (to be different from content div)
spyOn(testEditor, "refreshAll");
WorkspaceManager.recomputeLayout(false);
expect(testEditor.refreshAll).not.toHaveBeenCalled();
});
it("should NOT refresh if skip is specified when both height and width changed", function () {
$root.height(200); // same as content div, so shouldn't be detected as a change
$root.width(200);
WorkspaceManager.recomputeLayout();
$root.height(300); // change the height (to be different from content div)
$root.width(300); // change the width
spyOn(testEditor, "refreshAll");
WorkspaceManager.recomputeLayout(false);
expect(testEditor.refreshAll).not.toHaveBeenCalled();
});
// unspecified cases
it("should NOT refresh if unspecified if no width or height change", function () {
$root.height(200); // same as content div, so shouldn't be detected as a change
$root.width(200);
WorkspaceManager.recomputeLayout();
spyOn(testEditor, "refreshAll");
WorkspaceManager.recomputeLayout();
expect(testEditor.refreshAll).not.toHaveBeenCalled();
});
it("should refresh if unspecified when width changed but height hasn't", function () {
$root.height(200); // same as content div, so shouldn't be detected as a change
$root.width(200);
WorkspaceManager.recomputeLayout();
$root.width(300); // change the width
spyOn(testEditor, "refreshAll");
WorkspaceManager.recomputeLayout();
expect(testEditor.refreshAll).toHaveBeenCalled();
});
it("should refresh if unspecified when height changed but width hasn't", function () {
$root.height(200); // same as content div, so shouldn't be detected as a change
$root.width(200);
WorkspaceManager.recomputeLayout();
$root.height(300); // change the height (to be different from content div)
spyOn(testEditor, "refreshAll");
WorkspaceManager.recomputeLayout();
expect(testEditor.refreshAll).toHaveBeenCalled();
});
it("should refresh if unspecified when both height and width changed", function () {
$root.height(200); // same as content div, so shouldn't be detected as a change
$root.width(200);
WorkspaceManager.recomputeLayout();
$root.height(300); // change the height (to be different from content div)
$root.width(300); // change the width
spyOn(testEditor, "refreshAll");
WorkspaceManager.recomputeLayout();
expect(testEditor.refreshAll).toHaveBeenCalled();
});
});
});
});

View File

@ -52,6 +52,7 @@ define(function (require, exports, module) {
searchResults,
CommandManager,
DocumentManager,
MainViewManager,
EditorManager,
FileFilters,
FileSystem,
@ -79,6 +80,7 @@ define(function (require, exports, module) {
FindInFiles = testWindow.brackets.test.FindInFiles;
FindInFilesUI = testWindow.brackets.test.FindInFilesUI;
ProjectManager = testWindow.brackets.test.ProjectManager;
MainViewManager = testWindow.brackets.test.MainViewManager;
$ = testWindow.$;
});
});
@ -92,6 +94,7 @@ define(function (require, exports, module) {
FindInFiles = null;
FindInFilesUI = null;
ProjectManager = null;
MainViewManager = null;
$ = null;
testWindow = null;
SpecRunnerUtils.closeTestWindow();
@ -496,7 +499,7 @@ define(function (require, exports, module) {
runs(function () {
// Verify document is not yet in working set
expect(DocumentManager.findInWorkingSet(filePath)).toBe(-1);
expect(MainViewManager.findInWorkingSet(MainViewManager.ALL_PANES, filePath)).toBe(-1);
// Get list in panel
var $panelResults = $("#find-in-files-results table.bottom-panel-table tr");
@ -508,7 +511,7 @@ define(function (require, exports, module) {
$firstHit.dblclick();
// Verify document is now in working set
expect(DocumentManager.findInWorkingSet(filePath)).not.toBe(-1);
expect(MainViewManager.findInWorkingSet(MainViewManager.ALL_PANES, filePath)).not.toBe(-1);
waitsForDone(CommandManager.execute(Commands.FILE_CLOSE_ALL), "closing all files");
});
});
@ -524,7 +527,7 @@ define(function (require, exports, module) {
runs(function () {
// Verify document is not yet in working set
expect(DocumentManager.findInWorkingSet(filePath)).toBe(-1);
expect(MainViewManager.findInWorkingSet(MainViewManager.ALL_PANES, filePath)).toBe(-1);
// Get list in panel
$panelResults = $("#find-in-files-results table.bottom-panel-table tr");
@ -782,7 +785,7 @@ define(function (require, exports, module) {
describe("when in-memory document changes", function () {
it("should update the results when a matching line is added, updating line numbers and adding the match", function () {
runs(function () {
waitsForDone(CommandManager.execute(Commands.FILE_ADD_TO_WORKING_SET, { fullPath: fullTestPath("foo.html") }));
waitsForDone(CommandManager.execute(Commands.CMD_ADD_TO_WORKINGSET_AND_OPEN, { fullPath: fullTestPath("foo.html") }));
});
runs(function () {
var doc = DocumentManager.getOpenDocumentForPath(fullTestPath("foo.html")),
@ -823,7 +826,7 @@ define(function (require, exports, module) {
it("should update the results when a matching line is deleted, updating line numbers and removing the match", function () {
runs(function () {
waitsForDone(CommandManager.execute(Commands.FILE_ADD_TO_WORKING_SET, { fullPath: fullTestPath("foo.html") }));
waitsForDone(CommandManager.execute(Commands.CMD_ADD_TO_WORKINGSET_AND_OPEN, { fullPath: fullTestPath("foo.html") }));
});
runs(function () {
var doc = DocumentManager.getOpenDocumentForPath(fullTestPath("foo.html")),
@ -860,7 +863,7 @@ define(function (require, exports, module) {
it("should replace matches in a portion of the document that was edited to include a new match", function () {
runs(function () {
waitsForDone(CommandManager.execute(Commands.FILE_ADD_TO_WORKING_SET, { fullPath: fullTestPath("foo.html") }));
waitsForDone(CommandManager.execute(Commands.CMD_ADD_TO_WORKINGSET_AND_OPEN, { fullPath: fullTestPath("foo.html") }));
});
runs(function () {
var doc = DocumentManager.getOpenDocumentForPath(fullTestPath("foo.html")),
@ -901,7 +904,7 @@ define(function (require, exports, module) {
it("should completely remove the document from the results list if all matches in the document are deleted", function () {
runs(function () {
waitsForDone(CommandManager.execute(Commands.FILE_ADD_TO_WORKING_SET, { fullPath: fullTestPath("foo.html") }));
waitsForDone(CommandManager.execute(Commands.CMD_ADD_TO_WORKINGSET_AND_OPEN, { fullPath: fullTestPath("foo.html") }));
});
runs(function () {
var doc = DocumentManager.getOpenDocumentForPath(fullTestPath("foo.html")),
@ -1292,10 +1295,10 @@ define(function (require, exports, module) {
// Open two of the documents we want to replace in memory.
runs(function () {
waitsForDone(CommandManager.execute(Commands.FILE_ADD_TO_WORKING_SET, { fullPath: testPath + "/css/foo.css" }), "opening document");
waitsForDone(CommandManager.execute(Commands.CMD_ADD_TO_WORKINGSET_AND_OPEN, { fullPath: testPath + "/css/foo.css" }), "opening document");
});
runs(function () {
waitsForDone(CommandManager.execute(Commands.FILE_ADD_TO_WORKING_SET, { fullPath: testPath + "/foo.js" }), "opening document");
waitsForDone(CommandManager.execute(Commands.CMD_ADD_TO_WORKINGSET_AND_OPEN, { fullPath: testPath + "/foo.js" }), "opening document");
});
// We can't use expectInMemoryFiles(), since this test requires everything to happen fully synchronously
@ -1400,7 +1403,7 @@ define(function (require, exports, module) {
openTestProjectCopy(defaultSourcePath);
runs(function () {
waitsForDone(CommandManager.execute(Commands.FILE_ADD_TO_WORKING_SET, { fullPath: testPath + "/css/foo.css" }), "opening document");
waitsForDone(CommandManager.execute(Commands.CMD_ADD_TO_WORKINGSET_AND_OPEN, { fullPath: testPath + "/css/foo.css" }), "opening document");
});
doTestWithErrors({
@ -1427,7 +1430,7 @@ define(function (require, exports, module) {
openTestProjectCopy(defaultSourcePath);
runs(function () {
waitsForDone(CommandManager.execute(Commands.FILE_ADD_TO_WORKING_SET, {fullPath: testPath + "/css/foo.css"}), "add file to working set");
waitsForDone(CommandManager.execute(Commands.CMD_ADD_TO_WORKINGSET_AND_OPEN, {fullPath: testPath + "/css/foo.css"}), "add file to working set");
});
doInMemoryTest({
@ -1452,7 +1455,7 @@ define(function (require, exports, module) {
};
runs(function () {
waitsForDone(CommandManager.execute(Commands.FILE_ADD_TO_WORKING_SET, {fullPath: testPath + "/css/foo.css"}), "add file to working set");
waitsForDone(CommandManager.execute(Commands.CMD_ADD_TO_WORKINGSET_AND_OPEN, {fullPath: testPath + "/css/foo.css"}), "add file to working set");
});
runs(function () {
var doc = DocumentManager.getOpenDocumentForPath(testPath + "/css/foo.css");
@ -1488,7 +1491,7 @@ define(function (require, exports, module) {
openTestProjectCopy(defaultSourcePath);
runs(function () {
DocumentManager.addToWorkingSet(FileSystem.getFileForPath(testPath + "/css/foo.css"));
MainViewManager.addToWorkingSet(MainViewManager.ACTIVE_PANE, FileSystem.getFileForPath(testPath + "/css/foo.css"));
});
doInMemoryTest({
@ -1523,7 +1526,7 @@ define(function (require, exports, module) {
});
runs(function () {
var workingSet = DocumentManager.getWorkingSet();
var workingSet = MainViewManager.getWorkingSet(MainViewManager.ALL_PANES);
expect(workingSet.some(function (file) { return file.fullPath === openFilePath; })).toBe(true);
doc.releaseRef();
});
@ -1574,7 +1577,7 @@ define(function (require, exports, module) {
openTestProjectCopy(defaultSourcePath);
runs(function () {
waitsForDone(CommandManager.execute(Commands.FILE_ADD_TO_WORKING_SET, {fullPath: testPath + "/bar.txt"}), "open file");
waitsForDone(CommandManager.execute(Commands.CMD_ADD_TO_WORKINGSET_AND_OPEN, {fullPath: testPath + "/bar.txt"}), "open file");
});
doInMemoryTest({
@ -1614,7 +1617,7 @@ define(function (require, exports, module) {
openTestProjectCopy(defaultSourcePath);
runs(function () {
waitsForDone(CommandManager.execute(Commands.FILE_ADD_TO_WORKING_SET, {fullPath: testPath + "/css/foo.css"}), "open file");
waitsForDone(CommandManager.execute(Commands.CMD_ADD_TO_WORKINGSET_AND_OPEN, {fullPath: testPath + "/css/foo.css"}), "open file");
});
doInMemoryTest({
@ -1727,12 +1730,12 @@ define(function (require, exports, module) {
openTestProjectCopy(defaultSourcePath);
runs(function () {
waitsForDone(CommandManager.execute(Commands.FILE_ADD_TO_WORKING_SET, { fullPath: testPath + "/foo.html" }), "open file");
waitsForDone(CommandManager.execute(Commands.CMD_ADD_TO_WORKINGSET_AND_OPEN, { fullPath: testPath + "/foo.html" }), "open file");
});
runs(function () {
doc = DocumentManager.getOpenDocumentForPath(testPath + "/foo.html");
expect(doc).toBeTruthy();
DocumentManager.setCurrentDocument(doc);
MainViewManager._edit(MainViewManager.ACTIVE_PANE, doc);
editor = doc._masterEditor;
expect(editor).toBeTruthy();
editor.setSelection({line: 4, ch: 7}, {line: 4, ch: 10});
@ -1750,12 +1753,12 @@ define(function (require, exports, module) {
openTestProjectCopy(defaultSourcePath);
runs(function () {
waitsForDone(CommandManager.execute(Commands.FILE_ADD_TO_WORKING_SET, { fullPath: testPath + "/foo.html" }), "open file");
waitsForDone(CommandManager.execute(Commands.CMD_ADD_TO_WORKINGSET_AND_OPEN, { fullPath: testPath + "/foo.html" }), "open file");
});
runs(function () {
doc = DocumentManager.getOpenDocumentForPath(testPath + "/foo.html");
expect(doc).toBeTruthy();
DocumentManager.setCurrentDocument(doc);
MainViewManager._edit(MainViewManager.ACTIVE_PANE, doc);
editor = doc._masterEditor;
expect(editor).toBeTruthy();
editor.setSelection({line: 4, ch: 7}, {line: 6, ch: 10});
@ -1986,7 +1989,7 @@ define(function (require, exports, module) {
it("should do single-file Replace All in an open file in the project", function () {
openTestProjectCopy(defaultSourcePath);
runs(function () {
waitsForDone(CommandManager.execute(Commands.FILE_ADD_TO_WORKING_SET, { fullPath: testPath + "/foo.js" }), "open file");
waitsForDone(CommandManager.execute(Commands.CMD_ADD_TO_WORKINGSET_AND_OPEN, { fullPath: testPath + "/foo.js" }), "open file");
});
runs(function () {
waitsForDone(CommandManager.execute(Commands.CMD_REPLACE), "open single-file replace bar");
@ -2025,7 +2028,7 @@ define(function (require, exports, module) {
});
SpecRunnerUtils.loadProjectInTestWindow(blankProject);
runs(function () {
waitsForDone(CommandManager.execute(Commands.FILE_ADD_TO_WORKING_SET, { fullPath: externalFilePath }), "open external file");
waitsForDone(CommandManager.execute(Commands.CMD_ADD_TO_WORKINGSET_AND_OPEN, { fullPath: externalFilePath }), "open external file");
});
runs(function () {
waitsForDone(CommandManager.execute(Commands.CMD_REPLACE), "open single-file replace bar");
@ -2160,7 +2163,7 @@ define(function (require, exports, module) {
it("should close the panel if a file is modified in memory", function () {
openTestProjectCopy(defaultSourcePath);
runs(function () {
waitsForDone(CommandManager.execute(Commands.FILE_ADD_TO_WORKING_SET, { fullPath: testPath + "/foo.html" }), "open file");
waitsForDone(CommandManager.execute(Commands.CMD_ADD_TO_WORKINGSET_AND_OPEN, { fullPath: testPath + "/foo.html" }), "open file");
});
openSearchBar(null, true);
executeReplace("foo", "bar");
@ -2183,7 +2186,7 @@ define(function (require, exports, module) {
openTestProjectCopy(defaultSourcePath);
runs(function () {
waitsForDone(CommandManager.execute(Commands.FILE_ADD_TO_WORKING_SET, { fullPath: testPath + "/foo.html" }), "open file");
waitsForDone(CommandManager.execute(Commands.CMD_ADD_TO_WORKINGSET_AND_OPEN, { fullPath: testPath + "/foo.html" }), "open file");
});
runs(function () {
doc = DocumentManager.getOpenDocumentForPath(testPath + "/foo.html");

View File

@ -33,6 +33,7 @@ define(function (require, exports, module) {
EditorManager, // loaded from brackets.test
FileSyncManager, // loaded from brackets.test
DocumentManager, // loaded from brackets.test
MainViewManager, // loaded from brackets.test
FileViewController, // loaded from brackets.test
InlineWidget = require("editor/InlineWidget").InlineWidget,
Dialogs = require("widgets/Dialogs"),
@ -81,18 +82,18 @@ define(function (require, exports, module) {
* @param {string} openFile Project relative file path to open in a main editor.
* @param {number} openOffset The offset index location within openFile to open an inline editor.
* @param {boolean=} expectInline Use false to verify that an inline editor should not be opened. Omit otherwise.
* @param {Array<{string}>=} workingSet Optional array of files to open in working set
* @param {Array<{string}>=} documentList Optional array of files to open in working set
*/
function initInlineTest(openFile, openOffset, expectInline, workingSet) {
function initInlineTest(openFile, openOffset, expectInline, documentList) {
var editor;
workingSet = workingSet || [];
documentList = documentList || [];
expectInline = (expectInline !== undefined) ? expectInline : true;
runs(function () {
workingSet.push(openFile);
waitsForDone(SpecRunnerUtils.openProjectFiles(workingSet), "FILE_OPEN timeout", 1000);
documentList.push(openFile);
waitsForDone(SpecRunnerUtils.openProjectFiles(documentList), "FILE_OPEN timeout", 1000);
});
runs(function () {
@ -208,6 +209,7 @@ define(function (require, exports, module) {
EditorManager = testWindow.brackets.test.EditorManager;
FileSyncManager = testWindow.brackets.test.FileSyncManager;
DocumentManager = testWindow.brackets.test.DocumentManager;
MainViewManager = testWindow.brackets.test.MainViewManager;
FileViewController = testWindow.brackets.test.FileViewController;
});
});
@ -218,6 +220,7 @@ define(function (require, exports, module) {
EditorManager = null;
FileSyncManager = null;
DocumentManager = null;
MainViewManager = null;
FileViewController = null;
SpecRunnerUtils.closeTestWindow();
@ -1024,7 +1027,7 @@ define(function (require, exports, module) {
initInlineTest("test1.html", 0);
runs(function () {
var i = DocumentManager.findInWorkingSet(infos["test1.css"].fileEntry.fullPath);
var i = MainViewManager.findInWorkingSet(MainViewManager.ACTIVE_PANE, infos["test1.css"].fileEntry.fullPath);
expect(i).toEqual(-1);
});
});
@ -1047,7 +1050,7 @@ define(function (require, exports, module) {
inlineEditor.getCursorPos()
);
var i = DocumentManager.findInWorkingSet(infos["test1.css"].fileEntry.fullPath);
var i = MainViewManager.findInWorkingSet(MainViewManager.ACTIVE_PANE, infos["test1.css"].fileEntry.fullPath);
expect(i).toEqual(1);
inlineEditor = null;
@ -1073,7 +1076,7 @@ define(function (require, exports, module) {
);
// activate the full editor
DocumentManager.setCurrentDocument(cssDoc);
MainViewManager._edit(MainViewManager.ACTIVE_PANE, cssDoc);
fullEditor = EditorManager.getCurrentFullEditor();
// sanity check
@ -1123,7 +1126,7 @@ define(function (require, exports, module) {
inlineEditor = hostEditor.getInlineWidgets()[0].editor;
// activate the full editor
DocumentManager.setCurrentDocument(cssDoc);
MainViewManager._edit(MainViewManager.ACTIVE_PANE, cssDoc);
fullEditor = EditorManager.getCurrentFullEditor();
// alias offsets to nice names
@ -1518,7 +1521,7 @@ define(function (require, exports, module) {
inlineEditor = hostEditor.getInlineWidgets()[0].editor;
// activate the full editor
DocumentManager.setCurrentDocument(cssDoc);
MainViewManager._edit(MainViewManager.ACTIVE_PANE, cssDoc);
fullEditor = EditorManager.getCurrentFullEditor();
});
});
@ -1557,7 +1560,9 @@ define(function (require, exports, module) {
describe("InlineEditor provider prioritization", function () {
var testWindow,
testDocumentManager,
testEditorManager,
testMainViewManager,
testDoc;
function getPositiveProviderCallback(widget) {
@ -1577,8 +1582,16 @@ define(function (require, exports, module) {
testWindow = w;
Commands = testWindow.brackets.test.Commands;
testEditorManager = testWindow.brackets.test.EditorManager;
testMainViewManager = testWindow.brackets.test.MainViewManager;
testDocumentManager = testWindow.brackets.test.DocumentManager;
testDoc = mock.doc;
testEditorManager._doShow(testDoc);
testDocumentManager.getOpenDocumentForPath = function (fullPath) {
return testDoc;
};
testMainViewManager._edit(testMainViewManager.ACTIVE_PANE, testDoc);
});
});
@ -1589,6 +1602,8 @@ define(function (require, exports, module) {
Commands = null;
testEditorManager = null;
testDoc = null;
testMainViewManager = null;
testDocumentManager = null;
});

View File

@ -33,6 +33,7 @@ define(function (require, exports, module) {
var CodeMirror = require("thirdparty/CodeMirror2/lib/codemirror"),
LanguageManager = require("language/LanguageManager"),
DocumentManager = require("document/DocumentManager"),
MainViewManager = require("view/MainViewManager"),
PathUtils = require("thirdparty/path-utils/path-utils.min"),
SpecRunnerUtils = require("spec/SpecRunnerUtils"),
PreferencesManager = require("preferences/PreferencesManager"),
@ -509,6 +510,7 @@ define(function (require, exports, module) {
var DocumentManager,
FileSystem,
LanguageManager,
MainViewManager,
_$;
SpecRunnerUtils.createTempDirectory();
@ -518,6 +520,7 @@ define(function (require, exports, module) {
FileSystem = w.brackets.test.FileSystem;
LanguageManager = w.brackets.test.LanguageManager;
DocumentManager = w.brackets.test.DocumentManager;
MainViewManager = w.brackets.test.MainViewManager;
_$ = w.$;
});
@ -544,7 +547,7 @@ define(function (require, exports, module) {
var renameDeferred = $.Deferred();
runs(function () {
DocumentManager.setCurrentDocument(doc);
MainViewManager._edit(MainViewManager.ACTIVE_PANE, doc);
javascript = LanguageManager.getLanguage("javascript");
// sanity check language
@ -587,7 +590,6 @@ define(function (require, exports, module) {
});
SpecRunnerUtils.closeTestWindow();
SpecRunnerUtils.removeTempDirectory();
});

View File

@ -0,0 +1,8 @@
/* Desktop */
@import url("desktop.css");
/* Phone */
@import url("phone.css") only screen and (max-width:320px);
/* Tablet */
@import url("tablet.css") only screen and (min-width:321px) and (max-width:768px);

View File

@ -0,0 +1,165 @@
@charset "utf-8";
/* CSS Document */
article, aside, figure, footer, header, nav, section {
display: block;
margin: 0;
padding: 0;
}
body {
font-family: "Trebuchet MS", Arial, Helvetica, sans-serif;
color: #000;
background-color: #66B034;
margin: 0px;
padding: 0px;
}
#container {
width: 840px;
margin-top: 0px;
margin-right: auto;
margin-bottom: 0px;
margin-left: auto;
}
#logo {
background-image: url(../images/lrg_logo.png);
background-repeat: no-repeat;
height: 138px;
width: 100%;
}
#logo h1, #logo h2 {
position: absolute;
top: -500px;
}
nav {
padding-top: 150px;
}
#maincontent {
margin-top: 80px;
padding-top: 10px;
padding-right: 0px;
padding-bottom: 10px;
padding-left: 0px;
}
ul {
padding:0;
margin:0;
}
nav ul {
list-style: none;
margin-bottom: 15px;
font-weight: bold;
font-size:20px;
}
nav ul li {
float: left;
}
nav ul a {
display: block;
width:140px;
padding: 10px;
text-align:center;
text-decoration: none;
color: #fff;
border: 1px solid #618A37;
margin: 5px 0px;
border-radius: 8px;
-moz-box-shadow: 1px 1px 3px rgba(0,0,0,0.3);
-webkit-box-shadow: 1px 1px 3px rgba(0,0,0,0.3);
box-shadow: 1px 1px 3px rgba(0,0,0,0.3);
text-shadow: 1px 1px 1px rgba(0,0,0,0.8);
}
nav ul a:link, nav ul a:visited {
background: rgba(255,255,255,0.2);
}
nav ul a:hover, nav ul a:active, nav ul a:focus {
background: rgba(255,255,255,0.4);
}
nav ul li:hover {
margin-top:-10px;
}
nav ul li {
float: left;
-webkit-transition-duration:.5s;
-webkit-transition-property:margin-top;
-webkit-transition-timing-function:ease-in-out;
-o-transition-duration:.5s;
-o-transition-property:margin-top;
-o-transition-timing-function:ease-in-out;
-moz-transition-duration:.5s;
-moz-transition-property:margin-top;
-moz-transition-timing-function:ease-in-out;
transition-duration:.5s;
transition-property:margin-top;
transition-timing-function:ease-in-out;
}
#vision {
font-family:"Palatino Linotype", "Book Antiqua", Palatino, serif;
font-size:32px;
font-weight:bold;
line-height:1.2;
background-image:url(../images/lrg_hero.jpg);
background-repeat:no-repeat;
width: 409px;
height:237px;
padding:60px 370px 0 40px;
margin-bottom:20px;
}
.pod {
background: #fff;
padding: 10px;
width: 244px;
float:left;
margin-right: 13px;
}
.podContent {
margin-top:10px;
width: 244px;
height:181px;
overflow:hidden;
}
#news .podContent {
margin-top:12px;
overflow:auto;
}
#news .podContent p {
margin-top: 5px;
margin-bottom: 5px;
margin-left:6px;
font-size:15px;
}
.pod h1 {
background: #CCC;
color: #000;
padding:5px;
background-image:url(../images/icon_chevron.png);
background-repeat:no-repeat;
background-position:95%;
font-size:16px;
font-weight:normal;
margin: 0 0 10px 0;
}
a.block {
text-decoration:none;
display:block;
}
time {
font-weight:bold;
display:inline-block;
width:2.5em;
}
footer {
padding: 10px 0;
clear:both;
color: #fff;
}
footer p {
margin:0 0 5px 0;
}
#phone {
font-weight:bold;
color: #000;
}
#facebookTwitter {
float:right;
margin-right:25px;
}

View File

@ -0,0 +1,61 @@
@charset "utf-8";
#container {
width: 100%;
}
#logo {
height:auto;
width:270px;
background-image: url(../images/sml_logo.png);
margin-left:auto;
margin-right:auto;
}
nav {
padding-top:100px;
}
nav ul {
font-size:24px;
}
nav ul a {
width:97%;
padding-right:0;
}
nav ul li {
float:none;
}
nav ul li:hover {
margin-top:0;
}
#maincontent {
margin-top: 0;
padding:0;
}
#vision {
background-image:none;
width: 280px;
height:auto;
font-size:16px;
line-height:normal;
padding-top:0;
}
/* Uncomment the declarations in the following rules to hide the images in the pods. */
.pod {
width: 305px;
/*padding-bottom:0;*/
}
/*.pod h1 {
margin-bottom:0;
}*/
.podContent {
width: 302px;
height:180px;
/*display:none;*/
}
/*#news .podContent {
display:block;
}*/
footer p {
margin-left:5px;
}
#facebookTwitter {
margin-right:5px;
}

View File

@ -0,0 +1,47 @@
@charset "utf-8";
#container {
width:700px;
}
#logo {
background-image:url(../images/med_logo.png);
height:100px;
}
nav {
padding-top:110px;
}
nav ul {
font-size:18px;
}
nav ul a {
width:114px;
}
#maincontent {
padding: 0;
margin-left:5px;
width: 700px;
}
#vision {
background-image:url(../images/med_hero.jpg);
width: 289px;
height:217px;
padding-top:45px;
padding-right:350px;
font-size:26px;
}
.pod {
width: 305px;
}
.podContent {
width: 302px;
height:180px;
}
#events {
margin-left:7px;
}
#news {
width:650px;
margin-top:20px;
}
footer p {
margin-left:5px;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 460 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 926 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1005 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Some files were not shown because too many files have changed in this diff Show More