diff --git a/src/editor/EditorManager.js b/src/editor/EditorManager.js
index 8f3200d4287..06dcf721e9c 100644
--- a/src/editor/EditorManager.js
+++ b/src/editor/EditorManager.js
@@ -52,6 +52,7 @@ define(function (require, exports, module) {
// Load dependent modules
var Commands = require("command/Commands"),
+ PanelManager = require("view/PanelManager"),
CommandManager = require("command/CommandManager"),
DocumentManager = require("document/DocumentManager"),
PerfUtils = require("utils/PerfUtils"),
@@ -341,55 +342,43 @@ define(function (require, exports, module) {
/**
- * 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 = $(".content").height();
-
- _editorHolder.siblings().each(function (i, elem) {
- var $elem = $(elem);
- if ($elem.css("display") !== "none") {
- 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);
- }
-
- /**
- * Flag for resizeEditor() to always force refresh.
+ * Flag for _onEditorAreaResize() to always force refresh.
* @const
* @type {string}
*/
var REFRESH_FORCE = "force";
/**
- * Flag for resizeEditor() to never refresh.
+ * Flag for _onEditorAreaResize() to never refresh.
* @const
* @type {string}
*/
var REFRESH_SKIP = "skip";
- /**
- * Resize the editor. This must be called any time the contents of the editor area are swapped
- * or any time the editor area might change height. EditorManager takes care of calling this when
- * the Editor is swapped, and on window resize. But anyone who changes size/visiblity of editor
- * area siblings (toolbar, status bar, bottom panels) *must* manually call resizeEditor().
- *
- * @param {string=} refreshFlag For internal use. Set to "force" to ensure the editor will refresh,
- * "skip" to ensure the editor does not refresh, or leave undefined to let resizeEditor() determine
- * whether it needs to refresh.
+ /**
+ * Must be called whenever the size/visibility of editor area siblings is changed without going through
+ * PanelManager or Resizer. Resizable panels created via PanelManager do not require this manual call.
*/
- function resizeEditor(refreshFlag) {
+ function resizeEditor() {
if (!_editorHolder) {
return; // still too early during init
}
-
- var editorAreaHt = _calcEditorHeight();
- _editorHolder.height(editorAreaHt); // affects size of "not-editor" placeholder as well
+ // PanelManager computes the correct editor-holder size & calls us back with it, via _onEditorAreaResize()
+ PanelManager._notifyLayoutChange();
+ }
+
+ /**
+ * Update the current CodeMirror editor's size. Must be called any time the contents of the editor area
+ * are swapped or any time the editor-holder area has changed height. EditorManager calls us in the swap
+ * case. PanelManager calls us in the most common height-change cases (panel and/or window resize), but
+ * some other cases are handled by external code calling resizeEditor() (e.g. ModalBar hide/show).
+ *
+ * @param {number} editorAreaHt
+ * @param {string=} refreshFlag For internal use. Set to "force" to ensure the editor will refresh,
+ * "skip" to ensure the editor does not refresh, or leave undefined to let _onEditorAreaResize()
+ * determine whether it needs to refresh.
+ */
+ function _onEditorAreaResize(event, editorAreaHt, refreshFlag) {
if (_currentEditor) {
var curRoot = _currentEditor.getRootElement(),
@@ -412,15 +401,6 @@ define(function (require, exports, module) {
}
}
- /**
- * NJ's editor-resizing fix. Whenever the window resizes, we immediately adjust the editor's
- * height.
- */
- function _updateEditorDuringResize() {
- // always skip the refresh since CodeMirror will call refresh() itself when it sees the resize event
- resizeEditor(REFRESH_SKIP);
- }
-
/** Updates _viewStateCache from the given editor's actual current state */
function _saveEditorViewState(editor) {
@@ -465,13 +445,13 @@ define(function (require, exports, module) {
_currentEditorsDocument = document;
_currentEditor = document._masterEditor;
- // Skip refreshing the editor since we're going to refresh it in resizeEditor() later.
+ // Skip refreshing the editor since we're going to refresh it more explicitly below
_currentEditor.setVisible(true, false);
_currentEditor.focus();
// Resize and refresh the editor, since it might have changed size or had other edits applied
// since it was last visible.
- resizeEditor(REFRESH_FORCE);
+ PanelManager._notifyLayoutChange(REFRESH_FORCE);
}
/**
@@ -705,11 +685,8 @@ define(function (require, exports, module) {
$(DocumentManager).on("currentDocumentChange", _onCurrentDocumentChange);
$(DocumentManager).on("workingSetRemove", _onWorkingSetRemove);
$(DocumentManager).on("workingSetRemoveList", _onWorkingSetRemoveList);
+ $(PanelManager).on("editorAreaResize", _onEditorAreaResize);
- // 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", _updateEditorDuringResize, true);
-
// For unit tests and internal use only
exports._openInlineWidget = _openInlineWidget;
exports._createFullEditorForDocument = _createFullEditorForDocument;
diff --git a/src/extensions/default/JSLint/main.js b/src/extensions/default/JSLint/main.js
index 89fa889d0aa..ae2b96ccadd 100644
--- a/src/extensions/default/JSLint/main.js
+++ b/src/extensions/default/JSLint/main.js
@@ -36,6 +36,7 @@ define(function (require, exports, module) {
// Load dependent modules
var Commands = brackets.getModule("command/Commands"),
+ PanelManager = brackets.getModule("view/PanelManager"),
CommandManager = brackets.getModule("command/CommandManager"),
Menus = brackets.getModule("command/Menus"),
DocumentManager = brackets.getModule("document/DocumentManager"),
@@ -156,7 +157,7 @@ define(function (require, exports, module) {
EditorManager.focusEditor();
});
- $lintResults.show();
+ Resizer.show($lintResults);
if (JSLINT.errors.length === 1) {
StatusBar.updateIndicator(INDICATOR_ID, true, "jslint-errors", Strings.JSLINT_ERROR_INFORMATION);
} else {
@@ -175,7 +176,7 @@ define(function (require, exports, module) {
setGotoEnabled(true);
} else {
- $lintResults.hide();
+ Resizer.hide($lintResults);
StatusBar.updateIndicator(INDICATOR_ID, true, "jslint-valid", Strings.JSLINT_NO_ERRORS);
setGotoEnabled(false);
}
@@ -184,12 +185,10 @@ define(function (require, exports, module) {
} else {
// JSLint is disabled or does not apply to the current file, hide the results
- $lintResults.hide();
+ Resizer.hide($lintResults);
StatusBar.updateIndicator(INDICATOR_ID, true, "jslint-disabled", Strings.JSLINT_DISABLED);
setGotoEnabled(false);
}
-
- EditorManager.resizeEditor();
}
/**
@@ -263,20 +262,15 @@ define(function (require, exports, module) {
ExtensionUtils.loadStyleSheet(module, "jslint.css");
var jsLintHtml = Mustache.render(JSLintTemplate, Strings);
- $(jsLintHtml).insertBefore("#status-bar");
+ var resultsPanel = PanelManager.createBottomPanel("jslint.results", $(jsLintHtml), 100);
+ $lintResults = $("#jslint-results");
var goldStarHtml = Mustache.render("
★
", Strings);
$(goldStarHtml).insertBefore("#status-file");
- $lintResults = $("#jslint-results");
-
StatusBar.addIndicator(INDICATOR_ID, $("#gold-star"));
// Called on HTML ready to trigger the initial UI state
setEnabled(_prefs.getValue("enabled"));
-
- // AppInit.htmlReady() has already executed before extensions are loaded
- // so, for now, we need to call this ourself
- Resizer.makeResizable($lintResults.get(0), "vert", "top", 100);
});
});
diff --git a/src/extensions/default/JavaScriptCodeHints/unittests.js b/src/extensions/default/JavaScriptCodeHints/unittests.js
index 9c0599cde7b..8bf4e50963a 100644
--- a/src/extensions/default/JavaScriptCodeHints/unittests.js
+++ b/src/extensions/default/JavaScriptCodeHints/unittests.js
@@ -49,26 +49,15 @@ define(function (require, exports, module) {
DocumentManager.setCurrentDocument(doc);
});
});
+
/**
- * Returns an Editor suitable for use in isolation, given a Document. (Unlike
- * SpecRunnerUtils.createMockEditor(), which is given text and creates the Document
- * for you).
+ * Returns an Editor suitable for use in isolation, given a Document.
*
* @param {Document} doc - the document to be contained by the new Editor
* @return {Editor} - the mock editor object
*/
function createMockEditor(doc) {
- // Initialize EditorManager
- var $editorHolder = $("");
- EditorManager.setEditorHolder($editorHolder);
- $("body").append($editorHolder);
-
- // create Editor instance
- var editor = new Editor(doc, true, $editorHolder.get(0));
-
- EditorManager._notifyActiveEditorChanged(editor);
-
- return editor;
+ return SpecRunnerUtils.createMockEditorForDocument(doc);
}
describe("JavaScript Code Hinting", function () {
diff --git a/src/htmlContent/main-view.html b/src/htmlContent/main-view.html
index fff3db4d42a..a66abe19c62 100644
--- a/src/htmlContent/main-view.html
+++ b/src/htmlContent/main-view.html
@@ -62,7 +62,7 @@
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.
+ not get set correctly. Use PanelManager to have this managed for you automatically.
-->
@@ -83,14 +83,7 @@
-
+
diff --git a/src/htmlContent/search-results.html b/src/htmlContent/search-results.html
new file mode 100644
index 00000000000..e46d823f469
--- /dev/null
+++ b/src/htmlContent/search-results.html
@@ -0,0 +1,8 @@
+
diff --git a/src/search/FindInFiles.js b/src/search/FindInFiles.js
index 756cfc6805f..832dbd01197 100644
--- a/src/search/FindInFiles.js
+++ b/src/search/FindInFiles.js
@@ -22,7 +22,7 @@
*/
/*jslint vars: true, plusplus: true, devel: true, nomen: true, regexp: true, indent: 4, maxerr: 50 */
-/*global define, $, PathUtils, window */
+/*global define, $, PathUtils, window, Mustache */
/*
* Adds a "find in files" command to allow the user to find all occurances of a string in all files in
@@ -43,6 +43,7 @@ define(function (require, exports, module) {
"use strict";
var Async = require("utils/Async"),
+ Resizer = require("utils/Resizer"),
CommandManager = require("command/CommandManager"),
Commands = require("command/Commands"),
Strings = require("strings"),
@@ -50,12 +51,15 @@ define(function (require, exports, module) {
ProjectManager = require("project/ProjectManager"),
DocumentManager = require("document/DocumentManager"),
EditorManager = require("editor/EditorManager"),
+ PanelManager = require("view/PanelManager"),
FileIndexManager = require("project/FileIndexManager"),
FileUtils = require("file/FileUtils"),
KeyEvent = require("utils/KeyEvent"),
AppInit = require("utils/AppInit"),
StatusBar = require("widgets/StatusBar"),
ModalBar = require("widgets/ModalBar").ModalBar;
+
+ var searchResultsTemplate = require("text!htmlContent/search-results.html");
var searchResults = [];
@@ -64,8 +68,8 @@ define(function (require, exports, module) {
currentQuery = "",
currentScope;
- // Div holding the search results. Initialized in htmlReady().
- var $searchResultsDiv;
+ // Bottom panel holding the search results. Initialized in htmlReady().
+ var searchResultsPanel;
function _getQueryRegExp(query) {
// Clear any pending RegEx error message
@@ -193,9 +197,8 @@ define(function (require, exports, module) {
};
function _hideSearchResults() {
- if ($searchResultsDiv.is(":visible")) {
- $searchResultsDiv.hide();
- EditorManager.resizeEditor();
+ if (searchResultsPanel.isVisible()) {
+ searchResultsPanel.hide();
}
}
@@ -340,12 +343,10 @@ define(function (require, exports, module) {
_hideSearchResults();
});
- $searchResultsDiv.show();
+ searchResultsPanel.show();
} else {
_hideSearchResults();
}
-
- EditorManager.resizeEditor();
}
/**
@@ -444,11 +445,12 @@ define(function (require, exports, module) {
// Initialize items dependent on HTML DOM
AppInit.htmlReady(function () {
- $searchResultsDiv = $("#search-results");
+ var panelHtml = Mustache.render(searchResultsTemplate, Strings);
+ searchResultsPanel = PanelManager.createBottomPanel("find-in-files.results", $(panelHtml));
});
function _fileNameChangeHandler(event, oldName, newName) {
- if ($searchResultsDiv.is(":visible")) {
+ if (searchResultsPanel.isVisible()) {
// Update the search results
searchResults.forEach(function (item) {
item.fullPath = item.fullPath.replace(oldName, newName);
@@ -458,7 +460,7 @@ define(function (require, exports, module) {
}
function _pathDeletedHandler(event, path) {
- if ($searchResultsDiv.is(":visible")) {
+ if (searchResultsPanel.isVisible()) {
// Update the search results
searchResults.forEach(function (item, idx) {
if (FileUtils.isAffectedWhenRenaming(item.fullPath, path)) {
diff --git a/src/utils/Resizer.js b/src/utils/Resizer.js
index f8d967cd2b4..c97f7d38748 100644
--- a/src/utils/Resizer.js
+++ b/src/utils/Resizer.js
@@ -60,8 +60,7 @@ define(function (require, exports, module) {
// Load dependent modules
var AppInit = require("utils/AppInit"),
- PreferencesManager = require("preferences/PreferencesManager"),
- EditorManager = require("editor/EditorManager");
+ PreferencesManager = require("preferences/PreferencesManager");
/**
* @private
@@ -139,17 +138,20 @@ define(function (require, exports, module) {
* @param {!string} direction Direction of the resize action: one of the DIRECTION_* constants.
* @param {!string} position Which side of the element can be dragged: one of the POSITION_* constants
* (TOP/BOTTOM for vertical resizing or LEFT/RIGHT for horizontal).
- * @param {?number} minSize Minimum size (width or height) of the element. Defaults to 0.
+ * @param {?number} minSize Minimum size (width or height) of the element's outer dimensions, including
+ * border & padding. Defaults to 0.
* @param {?boolean} collapsible Indicates the panel is collapsible on double click on the
* resizer. Defaults to false.
* @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
*/
- function makeResizable(element, direction, position, minSize, collapsible, forceLeft) {
+ function makeResizable(element, direction, position, minSize, collapsible, forceLeft, createdByPanelManager) {
var $resizer = $(''),
$element = $(element),
+ $parent = $element.parent(),
$resizableElement = $($element.find(".resizable-content:first")[0]),
$body = $(window.document.body),
elementID = $element.attr("id"),
@@ -166,9 +168,18 @@ define(function (require, exports, module) {
$element.prepend($resizer);
+ // 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);
+ $(exports).triggerHandler("deprecatedPanelAdded", [$element]);
+ }
+
function adjustSibling(size) {
if (forceLeft !== undefined) {
- $(forceLeft, $element.parent()).css("left", size);
+ $(forceLeft, $parent).css("left", size);
}
}
@@ -205,9 +216,6 @@ define(function (require, exports, module) {
adjustSibling(elementSize);
- // Vertical resize affects editor directly; horizontal resize could change height of top toolbar
- EditorManager.resizeEditor();
-
$element.trigger("panelExpanded", [elementSize]);
_prefs.setValue(elementID, elementPrefs);
});
@@ -230,9 +238,6 @@ define(function (require, exports, module) {
adjustSibling(0);
- // Vertical resize affects editor directly; horizontal resize could change height of top toolbar
- EditorManager.resizeEditor();
-
$element.trigger("panelCollapsed", [elementSize]);
_prefs.setValue(elementID, elementPrefs);
});
@@ -307,9 +312,6 @@ define(function (require, exports, module) {
$element.trigger("panelResizeStart", newSize);
}
}
-
- // Vertical resize affects editor directly; horizontal resize could change height of top toolbar
- EditorManager.resizeEditor();
}
animationRequest = window.webkitRequestAnimationFrame(doRedraw);
@@ -319,6 +321,13 @@ define(function (require, exports, module) {
// calculate newSize adding to startSize the difference
// 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)
+ var maxSize = $element.data("maxsize");
+ if (maxSize !== undefined) {
+ newSize = Math.min(newSize, maxSize);
+ }
+
e.preventDefault();
if (animationRequest === null) {
diff --git a/src/view/PanelManager.js b/src/view/PanelManager.js
new file mode 100644
index 00000000000..28f39c5d806
--- /dev/null
+++ b/src/view/PanelManager.js
@@ -0,0 +1,236 @@
+/*
+ * Copyright (c) 2013 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:
+ * - 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.
+ */
+define(function (require, exports, module) {
+ "use strict";
+
+ var AppInit = require("utils/AppInit"),
+ Resizer = require("utils/Resizer");
+
+
+ /** @type {jQueryObject} The ".content" vertical stack (editor + all header/footer panels) */
+ var $windowContent;
+
+ /** @type {jQueryObject} The "#editor-holder": has only one visible child, the current CodeMirror
+ instance (or the no-editor placeholder) */
+ var $editorHolder;
+
+ /** @type {boolean} Have we already started listening for the end of the ongoing window resize? */
+ 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") {
+ 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 "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() {
+ // Immediately adjust editor's height, but skip the refresh since CodeMirror will call refresh()
+ // itself when it sees the window resize event
+ triggerEditorResize("skip");
+
+ 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; default is 0
+ */
+ function Panel($panel, minSize) {
+ this.$panel = $panel;
+
+ Resizer.makeResizable($panel[0], Resizer.DIRECTION_VERTICAL, Resizer.POSITION_TOP, minSize, false, undefined, true);
+ listenToResize($panel);
+ }
+
+ /** @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 panel beneath the editor area and above the status bar footer. Panel is initially invisible.
+ *
+ * @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.
+ * @param {number=} minSize Minimum height of panel in px; default is 0
+ * @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: a side panel rather than a bottom panel. It could still affect the
+ // editor-holder's height if changing .content's width causes the inBrowser titlebar to wrap/unwrap.
+ if (brackets.inBrowser) {
+ 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;
+});
diff --git a/src/widgets/StatusBar.js b/src/widgets/StatusBar.js
index d195611c24b..deec2e13a60 100644
--- a/src/widgets/StatusBar.js
+++ b/src/widgets/StatusBar.js
@@ -1,3 +1,27 @@
+/*
+ * 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, indent: 4, maxerr: 50 */
/*global define, $, brackets, window, document, Mustache */
diff --git a/test/spec/EditorManager-test.js b/test/spec/EditorManager-test.js
index 464127bb5ea..b682694c722 100644
--- a/test/spec/EditorManager-test.js
+++ b/test/spec/EditorManager-test.js
@@ -29,6 +29,7 @@ define(function (require, exports, module) {
'use strict';
var EditorManager = require("editor/EditorManager"),
+ PanelManager = require("view/PanelManager"),
SpecRunnerUtils = require("spec/SpecRunnerUtils");
describe("EditorManager", function () {
@@ -37,20 +38,25 @@ define(function (require, exports, module) {
var testEditor, testDoc, $root, $fakeContentDiv;
beforeEach(function () {
- var mock = SpecRunnerUtils.createMockEditor("");
- testEditor = mock.editor;
- testDoc = mock.doc;
- $root = $(testEditor.getRootElement());
-
// 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 move the editor holder into it.
+ // hold the height, and we'll place the editor holder in it.
$fakeContentDiv = $("")
.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")
.appendTo($fakeContentDiv);
+ testEditor = mock.editor;
+ testDoc = mock.doc;
+ $root = $(testEditor.getRootElement());
+
testDoc._masterEditor = testEditor;
EditorManager._doShow(testDoc);
});
@@ -72,7 +78,7 @@ define(function (require, exports, module) {
EditorManager.resizeEditor(); // cache the width
spyOn(testEditor, "refreshAll");
- EditorManager.resizeEditor(EditorManager.REFRESH_FORCE);
+ PanelManager._notifyLayoutChange(EditorManager.REFRESH_FORCE);
expect(testEditor.refreshAll).toHaveBeenCalled();
});
@@ -83,7 +89,7 @@ define(function (require, exports, module) {
$root.width(300); // change the width
spyOn(testEditor, "refreshAll");
- EditorManager.resizeEditor(EditorManager.REFRESH_FORCE);
+ PanelManager._notifyLayoutChange(EditorManager.REFRESH_FORCE);
expect(testEditor.refreshAll).toHaveBeenCalled();
});
@@ -94,7 +100,7 @@ define(function (require, exports, module) {
$root.height(300); // change the height (to be different from content div)
spyOn(testEditor, "refreshAll");
- EditorManager.resizeEditor(EditorManager.REFRESH_FORCE);
+ PanelManager._notifyLayoutChange(EditorManager.REFRESH_FORCE);
expect(testEditor.refreshAll).toHaveBeenCalled();
});
@@ -106,7 +112,7 @@ define(function (require, exports, module) {
$root.width(300); // change the width
spyOn(testEditor, "refreshAll");
- EditorManager.resizeEditor(EditorManager.REFRESH_FORCE);
+ PanelManager._notifyLayoutChange(EditorManager.REFRESH_FORCE);
expect(testEditor.refreshAll).toHaveBeenCalled();
});
@@ -117,7 +123,7 @@ define(function (require, exports, module) {
EditorManager.resizeEditor(); // cache the width
spyOn(testEditor, "refreshAll");
- EditorManager.resizeEditor(EditorManager.REFRESH_SKIP);
+ PanelManager._notifyLayoutChange(EditorManager.REFRESH_SKIP);
expect(testEditor.refreshAll).not.toHaveBeenCalled();
});
@@ -128,7 +134,7 @@ define(function (require, exports, module) {
$root.width(300); // change the width
spyOn(testEditor, "refreshAll");
- EditorManager.resizeEditor(EditorManager.REFRESH_SKIP);
+ PanelManager._notifyLayoutChange(EditorManager.REFRESH_SKIP);
expect(testEditor.refreshAll).not.toHaveBeenCalled();
});
@@ -139,7 +145,7 @@ define(function (require, exports, module) {
$root.height(300); // change the height (to be different from content div)
spyOn(testEditor, "refreshAll");
- EditorManager.resizeEditor(EditorManager.REFRESH_SKIP);
+ PanelManager._notifyLayoutChange(EditorManager.REFRESH_SKIP);
expect(testEditor.refreshAll).not.toHaveBeenCalled();
});
@@ -151,7 +157,7 @@ define(function (require, exports, module) {
$root.width(300); // change the width
spyOn(testEditor, "refreshAll");
- EditorManager.resizeEditor(EditorManager.REFRESH_SKIP);
+ PanelManager._notifyLayoutChange(EditorManager.REFRESH_SKIP);
expect(testEditor.refreshAll).not.toHaveBeenCalled();
});
@@ -162,7 +168,7 @@ define(function (require, exports, module) {
EditorManager.resizeEditor(); // cache the width
spyOn(testEditor, "refreshAll");
- EditorManager.resizeEditor();
+ PanelManager._notifyLayoutChange();
expect(testEditor.refreshAll).not.toHaveBeenCalled();
});
@@ -173,7 +179,7 @@ define(function (require, exports, module) {
$root.width(300); // change the width
spyOn(testEditor, "refreshAll");
- EditorManager.resizeEditor();
+ PanelManager._notifyLayoutChange();
expect(testEditor.refreshAll).toHaveBeenCalled();
});
@@ -184,7 +190,7 @@ define(function (require, exports, module) {
$root.height(300); // change the height (to be different from content div)
spyOn(testEditor, "refreshAll");
- EditorManager.resizeEditor();
+ PanelManager._notifyLayoutChange();
expect(testEditor.refreshAll).toHaveBeenCalled();
});
@@ -196,7 +202,7 @@ define(function (require, exports, module) {
$root.width(300); // change the width
spyOn(testEditor, "refreshAll");
- EditorManager.resizeEditor();
+ PanelManager._notifyLayoutChange();
expect(testEditor.refreshAll).toHaveBeenCalled();
});
});
diff --git a/test/spec/SpecRunnerUtils.js b/test/spec/SpecRunnerUtils.js
index bb7c726d98b..29b26a716d8 100644
--- a/test/spec/SpecRunnerUtils.js
+++ b/test/spec/SpecRunnerUtils.js
@@ -34,6 +34,7 @@ define(function (require, exports, module) {
DocumentManager = require("document/DocumentManager"),
Editor = require("editor/Editor").Editor,
EditorManager = require("editor/EditorManager"),
+ PanelManager = require("view/PanelManager"),
ExtensionLoader = require("utils/ExtensionLoader"),
UrlParams = require("utils/UrlParams").UrlParams,
LanguageManager = require("language/LanguageManager");
@@ -204,24 +205,34 @@ define(function (require, exports, module) {
}
/**
- * Returns a Document and Editor suitable for use with an Editor in
- * isolation: i.e., a Document that will never be set as the
- * currentDocument or added to the working set.
- * @return {!{doc:{Document}, editor:{Editor}}}
+ * Returns an Editor tied to the given Document, but suitable for use in isolation
+ * (without being placed inside the surrounding Brackets UI).
+ * @return {!Editor}
*/
- function createMockEditor(initialContent, languageId, visibleRange) {
- // Initialize EditorManager and position the editor-holder offscreen
+ function createMockEditorForDocument(doc, visibleRange) {
+ // Initialize EditorManager/PanelManager and position the editor-holder offscreen
+ // (".content" may not exist, but that's ok for headless tests where editor height doesn't matter)
var $editorHolder = createMockElement().attr("id", "mock-editor-holder");
+ PanelManager._setMockDOM($(".content"), $editorHolder);
EditorManager.setEditorHolder($editorHolder);
- // create dummy Document for the Editor
- var doc = createMockDocument(initialContent, languageId);
-
// create Editor instance
var editor = new Editor(doc, true, $editorHolder.get(0), visibleRange);
EditorManager._notifyActiveEditorChanged(editor);
- return { doc: doc, editor: editor };
+ return editor;
+ }
+
+ /**
+ * Returns a Document and Editor suitable for use in isolation: i.e., the Document
+ * will never be set as the currentDocument or added to the working set and the
+ * Editor does not live inside a full-blown Brackets UI layout.
+ * @return {!{doc:!Document, editor:!Editor}}
+ */
+ function createMockEditor(initialContent, languageId, visibleRange) {
+ // create dummy Document, then Editor tied to it
+ var doc = createMockDocument(initialContent, languageId);
+ return { doc: doc, editor: createMockEditorForDocument(doc, visibleRange) };
}
/**
@@ -941,6 +952,7 @@ define(function (require, exports, module) {
exports.createMockDocument = createMockDocument;
exports.createMockActiveDocument = createMockActiveDocument;
exports.createMockElement = createMockElement;
+ exports.createMockEditorForDocument = createMockEditorForDocument;
exports.createMockEditor = createMockEditor;
exports.createTestWindowAndRun = createTestWindowAndRun;
exports.closeTestWindow = closeTestWindow;