diff --git a/src/extensions/default/DebugCommands/ErrorNotification.js b/src/extensions/default/DebugCommands/ErrorNotification.js new file mode 100644 index 00000000000..b3b241065b5 --- /dev/null +++ b/src/extensions/default/DebugCommands/ErrorNotification.js @@ -0,0 +1,149 @@ +/* + * 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, regexp: true, indent: 4, maxerr: 50 */ +/*global define, $, brackets, window, document */ + +define(function (require, exports, module) { + "use strict"; + + var _ = brackets.getModule("thirdparty/lodash"), + AnimationUtils = brackets.getModule("utils/AnimationUtils"), + ExtensionUtils = brackets.getModule("utils/ExtensionUtils"), + Strings = brackets.getModule("strings"); + + var $span = null, + errorCount = 0, + _attached = false, + _windowOnError, + _consoleError, + _consoleClear; + + ExtensionUtils.loadStyleSheet(module, "styles.css"); + + function showDeveloperTools() { + try { + brackets.app.showDeveloperTools(); + } catch (err) { + console.error(err); + } + } + + function refreshIndicator() { + // never show 0 errors + if (!_attached || errorCount === 0) { + // hide notifier if it was attached previously + // but errorCount was cleared or it was disabled + if ($span) { + $span.parent().hide(); + } + return; + } + + // update span if it was created before + if ($span) { + $span.text(errorCount).parent().show(); + return; + } + + // create the span + $span = $("").text(errorCount); + $("
") + .attr("id", "error-counter") + .attr("title", Strings.CMD_SHOW_DEV_TOOLS + "\u2026") + .text(Strings.ERRORS + ": ") + .append($span) + .on("click", showDeveloperTools) + .insertBefore("#status-bar .spinner"); + } + + var blink = _.debounce(function () { + AnimationUtils.animateUsingClass($span.parent()[0], "flash"); + }, 100); + + function incErrorCount() { + errorCount++; + blink(); + refreshIndicator(); + } + + function clearErrorCount() { + errorCount = 0; + refreshIndicator(); + } + + function attachFunctions() { + if (_attached) { + return; + } + + _attached = true; + _windowOnError = window.onerror; + _consoleError = window.console.error; + _consoleClear = window.console.clear; + + // https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers.onerror + window.onerror = function (errorMsg, url, lineNumber) { + incErrorCount(); + if (_windowOnError) { + return _windowOnError(errorMsg, url, lineNumber); + } + // return false means that we didn't handle this error and it should run the default handler + return false; + }; + + window.console.error = function () { + incErrorCount(); + return _consoleError.apply(window.console, arguments); + }; + + window.console.clear = function () { + clearErrorCount(); + return _consoleClear.apply(window.console, arguments); + }; + } + + function detachFunctions() { + if (!_attached) { + return; + } + + _attached = false; + window.onerror = _windowOnError; + window.console.error = _consoleError; + window.console.clear = _consoleClear; + } + + function toggle(bool) { + if (bool) { + attachFunctions(); + } else { + detachFunctions(); + } + refreshIndicator(); + } + + // Public API + exports.toggle = toggle; + +}); diff --git a/src/extensions/default/DebugCommands/main.js b/src/extensions/default/DebugCommands/main.js index 50216e18e8a..388acc2da15 100644 --- a/src/extensions/default/DebugCommands/main.js +++ b/src/extensions/default/DebugCommands/main.js @@ -40,6 +40,7 @@ define(function (require, exports, module) { Dialogs = brackets.getModule("widgets/Dialogs"), Strings = brackets.getModule("strings"), PreferencesManager = brackets.getModule("preferences/PreferencesManager"), + ErrorNotification = require("ErrorNotification"), NodeDebugUtils = require("NodeDebugUtils"), PerfDialogTemplate = require("text!htmlContent/perf-dialog.html"), LanguageDialogTemplate = require("text!htmlContent/language-dialog.html"); @@ -59,7 +60,10 @@ define(function (require, exports, module) { DEBUG_SWITCH_LANGUAGE = "debug.switchLanguage", DEBUG_ENABLE_NODE_DEBUGGER = "debug.enableNodeDebugger", DEBUG_LOG_NODE_STATE = "debug.logNodeState", - DEBUG_RESTART_NODE = "debug.restartNode"; + DEBUG_RESTART_NODE = "debug.restartNode", + DEBUG_SHOW_ERRORS_IN_STATUS_BAR = "debug.showErrorsInStatusBar"; + + PreferencesManager.definePreference(DEBUG_SHOW_ERRORS_IN_STATUS_BAR, "boolean", false); function handleShowDeveloperTools() { brackets.app.showDeveloperTools(); @@ -230,6 +234,22 @@ define(function (require, exports, module) { }); } + function toggleErrorNotification(bool) { + var val; + + if (typeof bool === "undefined") { + val = !PreferencesManager.get(DEBUG_SHOW_ERRORS_IN_STATUS_BAR); + } else { + val = !!bool; + } + + ErrorNotification.toggle(val); + + // update menu + CommandManager.get(DEBUG_SHOW_ERRORS_IN_STATUS_BAR).setChecked(val); + PreferencesManager.set(DEBUG_SHOW_ERRORS_IN_STATUS_BAR, val); + } + /* Register all the command handlers */ // Show Developer Tools (optionally enabled) @@ -243,8 +263,9 @@ define(function (require, exports, module) { CommandManager.register(Strings.CMD_RUN_UNIT_TESTS, DEBUG_RUN_UNIT_TESTS, _runUnitTests) .setEnabled(false); - CommandManager.register(Strings.CMD_SHOW_PERF_DATA, DEBUG_SHOW_PERF_DATA, handleShowPerfData); - CommandManager.register(Strings.CMD_SWITCH_LANGUAGE, DEBUG_SWITCH_LANGUAGE, handleSwitchLanguage); + CommandManager.register(Strings.CMD_SHOW_PERF_DATA, DEBUG_SHOW_PERF_DATA, handleShowPerfData); + CommandManager.register(Strings.CMD_SWITCH_LANGUAGE, DEBUG_SWITCH_LANGUAGE, handleSwitchLanguage); + CommandManager.register(Strings.CMD_SHOW_ERRORS_IN_STATUS_BAR, DEBUG_SHOW_ERRORS_IN_STATUS_BAR, toggleErrorNotification); // Node-related Commands CommandManager.register(Strings.CMD_ENABLE_NODE_DEBUGGER, DEBUG_ENABLE_NODE_DEBUGGER, NodeDebugUtils.enableDebugger); @@ -252,6 +273,7 @@ define(function (require, exports, module) { CommandManager.register(Strings.CMD_RESTART_NODE, DEBUG_RESTART_NODE, NodeDebugUtils.restartNode); enableRunTestsMenuItem(); + toggleErrorNotification(PreferencesManager.get(DEBUG_SHOW_ERRORS_IN_STATUS_BAR)); /* * Debug menu @@ -270,6 +292,7 @@ define(function (require, exports, module) { menu.addMenuItem(DEBUG_ENABLE_NODE_DEBUGGER); menu.addMenuItem(DEBUG_LOG_NODE_STATE); menu.addMenuItem(DEBUG_RESTART_NODE); + menu.addMenuItem(DEBUG_SHOW_ERRORS_IN_STATUS_BAR); menu.addMenuItem(Commands.FILE_OPEN_PREFERENCES); // this command is defined in core, but exposed only in Debug menu for now // exposed for convenience, but not official API diff --git a/src/extensions/default/DebugCommands/styles.css b/src/extensions/default/DebugCommands/styles.css new file mode 100644 index 00000000000..d7c2e5ba632 --- /dev/null +++ b/src/extensions/default/DebugCommands/styles.css @@ -0,0 +1,10 @@ +#error-counter { + cursor: pointer; + transition: all 3s; + color: #f74687; + background-color: transparent; +} +#error-counter.flash { + transition: all 1s; + background-color: #ffb0cd; +} diff --git a/src/nls/root/strings.js b/src/nls/root/strings.js index f1b9bdab555..0e1774f2389 100644 --- a/src/nls/root/strings.js +++ b/src/nls/root/strings.js @@ -493,6 +493,7 @@ define({ // extensions/default/DebugCommands "DEBUG_MENU" : "Debug", + "ERRORS" : "Errors", "CMD_SHOW_DEV_TOOLS" : "Show Developer Tools", "CMD_REFRESH_WINDOW" : "Reload With Extensions", "CMD_RELOAD_WITHOUT_USER_EXTS" : "Reload Without Extensions", @@ -503,6 +504,7 @@ define({ "CMD_ENABLE_NODE_DEBUGGER" : "Enable Node Debugger", "CMD_LOG_NODE_STATE" : "Log Node State to Console", "CMD_RESTART_NODE" : "Restart Node", + "CMD_SHOW_ERRORS_IN_STATUS_BAR" : "Show Errors in Status Bar", "LANGUAGE_TITLE" : "Switch Language", "LANGUAGE_MESSAGE" : "Language:", diff --git a/src/widgets/StatusBar.html b/src/widgets/StatusBar.html index 258a9bbc91e..4d477e97807 100644 --- a/src/widgets/StatusBar.html +++ b/src/widgets/StatusBar.html @@ -13,4 +13,4 @@
{{STATUSBAR_INSERT}}
- \ No newline at end of file +