diff --git a/src/brackets.js b/src/brackets.js index dc0d4cc1ba3..975e8ae603b 100644 --- a/src/brackets.js +++ b/src/brackets.js @@ -100,6 +100,7 @@ define(function (require, exports, module) { require("search/FindReplace"); require("extensibility/InstallExtensionDialog"); require("extensibility/ExtensionManagerDialog"); + require("editor/ImageViewer"); // Compatibility shims for filesystem API migration require("project/FileIndexManager"); diff --git a/src/editor/EditorManager.js b/src/editor/EditorManager.js index 7a1e778e0b4..1f1f3f48bfe 100644 --- a/src/editor/EditorManager.js +++ b/src/editor/EditorManager.js @@ -58,7 +58,6 @@ define(function (require, exports, module) { PerfUtils = require("utils/PerfUtils"), Editor = require("editor/Editor").Editor, InlineTextEditor = require("editor/InlineTextEditor").InlineTextEditor, - ImageViewer = require("editor/ImageViewer"), Strings = require("strings"), LanguageManager = require("language/LanguageManager"); @@ -78,6 +77,8 @@ define(function (require, exports, module) { var _$currentCustomViewer = null; /** @type {?Object} view provider */ var _currentViewProvider = null; + /** @type {?Object} view provider registry */ + var _customViewerRegistry = {}; /** * Currently focused Editor (full-size, inline, or otherwise) @@ -625,9 +626,12 @@ define(function (require, exports, module) { /** Remove existing custom view if present */ function _removeCustomViewer() { - $(exports).triggerHandler("removeCustomViewer"); + if (_$currentCustomViewer) { _$currentCustomViewer.remove(); + if (_currentViewProvider.onRemove) { + _currentViewProvider.onRemove(); + } } _$currentCustomViewer = null; _currentViewProvider = null; @@ -663,15 +667,11 @@ define(function (require, exports, module) { // Hide the not-editor or reset current editor $("#not-editor").css("display", "none"); _nullifyEditor(); - + _currentViewProvider = provider; - _$currentCustomViewer = provider.getCustomViewHolder(fullPath); - - // place in window - $("#editor-holder").append(_$currentCustomViewer); // add path, dimensions and file size to the view after loading image - provider.render(fullPath); + _$currentCustomViewer = provider.render(fullPath, $("#editor-holder")); _setCurrentlyViewedPath(fullPath); } @@ -687,6 +687,40 @@ define(function (require, exports, module) { return (_currentViewProvider && _currentlyViewedPath === fullPath); } + /** + * Registers a new custom viewer provider. To create an extension + * that enables Brackets to view files that cannot be shown as + * text such as binary files, use this method to register a CustomViewer. + * + * A CustomViewer, such as ImageViewer in Brackets core needs to + * implement and export two methods: + * - render + * @param {!string} fullPath Path to the image file + * @param {!jQueryObject} $editorHolder The DOM element to append the view to. + * - onRemove + * signs off listeners and performs any required clean up when editor manager closes + * the custom viewer + * + * By registering a CustomViewer with EditorManager Brackets is + * enabled to view files for one or more given file extensions. + * The first argument defines a so called languageId which bundles + * file extensions to be handled by the custom viewer, see more + * in LanguageManager JSDocs. + * The second argument is an instance of the custom viewer that is ready to display + * files. + * + * @param {!String} languageId, i.e. string such as image, audio, etc to + * identify a language known to LanguageManager + * @param {!Object} provider custom view provider instance + */ + function registerCustomViewer(langId, provider) { + if (!_customViewerRegistry[langId]) { + _customViewerRegistry[langId] = provider; + } else { + console.error("There already is a custom viewer registered for language id \"" + langId + "\""); + } + } + /** * Update file name if necessary */ @@ -705,15 +739,8 @@ define(function (require, exports, module) { */ function getCustomViewerForPath(fullPath) { var lang = LanguageManager.getLanguageForPath(fullPath); - if (lang.getId() === "image") { - // TODO: Extensibility - // For now we only have the image viewer, so just return ImageViewer object. - // Once we have each viewer registers with EditorManager as a provider, - // then we return the provider registered with the language id. - return ImageViewer; - } - return null; + return _customViewerRegistry[lang.getId()]; } /** @@ -971,7 +998,7 @@ define(function (require, exports, module) { return _toggleInlineWidget(_inlineDocsProviders); }); CommandManager.register(Strings.CMD_JUMPTO_DEFINITION, Commands.NAVIGATE_JUMPTO_DEFINITION, _doJumpToDef); - + // Create PerfUtils measurement PerfUtils.createPerfMeasurement("JUMP_TO_DEFINITION", "Jump-To-Definiiton"); @@ -1011,6 +1038,7 @@ define(function (require, exports, module) { exports.getInlineEditors = getInlineEditors; exports.closeInlineWidget = closeInlineWidget; exports.showCustomViewer = showCustomViewer; + exports.registerCustomViewer = registerCustomViewer; exports.getCustomViewerForPath = getCustomViewerForPath; exports.notifyPathDeleted = notifyPathDeleted; exports.closeCustomViewer = closeCustomViewer; diff --git a/src/editor/ImageViewer.js b/src/editor/ImageViewer.js index a46a5d52fed..cdac4b6e90d 100644 --- a/src/editor/ImageViewer.js +++ b/src/editor/ImageViewer.js @@ -279,22 +279,12 @@ define(function (require, exports, module) { } } - /** - * creates a DOM node to place in the editor-holder - * in order to display an image. - * @param {!string} fullPath path to image file - * @return {JQuery} - * - */ - function getCustomViewHolder(fullPath) { - return $(Mustache.render(ImageHolderTemplate, {fullPath: fullPath})); - } /** * sign off listeners when editor manager closes * the image viewer */ - function _removeListeners() { + function onRemove() { $(PanelManager).off("editorAreaResize", _onEditorAreaResize); $(DocumentManager).off("fileNameChange", _onFileNameChange); $("#img").off("mousemove", "#img-preview, #img-scale, #img-tip, .img-guide", _showImageTip) @@ -304,10 +294,15 @@ define(function (require, exports, module) { /** * 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 {!string} fullPath Path to the image file + * @param {!jQueryObject} $editorHolder The DOM element to append the view to. */ - function render(fullPath) { - var relPath = ProjectManager.makeProjectRelativeIfPossible(fullPath); + function render(fullPath, $editorHolder) { + var relPath = ProjectManager.makeProjectRelativeIfPossible(fullPath), + $customViewer = $(Mustache.render(ImageHolderTemplate, {fullPath: fullPath})); + + // place DOM node to hold image + $editorHolder.append($customViewer); _scale = 100; // initialize to 100 _scaleDivInfo = null; @@ -337,10 +332,11 @@ define(function (require, exports, module) { } }); $("#image-holder").show(); + // listen to resize to update the scale sticker $(PanelManager).on("editorAreaResize", _onEditorAreaResize); - // listen to removal to stop listening to resize events - $(EditorManager).on("removeCustomViewer", _removeListeners); + + // make sure we always show the right file name $(DocumentManager).on("fileNameChange", _onFileNameChange); $("#img-tip").hide(); @@ -360,8 +356,14 @@ define(function (require, exports, module) { $(".img-guide").css("cursor", "crosshair"); } }); + return $customViewer; } - exports.getCustomViewHolder = getCustomViewHolder; + EditorManager.registerCustomViewer("image", { + render: render, + onRemove: onRemove + }); + exports.render = render; + exports.onRemove = onRemove; });